Commit 3d4eca03f309655578710ab4453f309c514268d1
refactor id-importing, style interface
mix irving committed on 5/29/2018, 5:25:37 AMParent: af8e9b0bc28f9eb27558912de8569872ffa19022
Files changed
app/html/header.js | changed |
app/page/splash.js | changed |
ftu/app.js | changed |
ftu/index.js | changed |
ftu/app.mcss | deleted |
ftu/observeSequence.js | added |
ftu/styles.js | added |
index.js | changed |
package-lock.json | changed |
package.json | changed |
translations/en.js | changed |
windowControls.js | added |
app/html/header.js | ||
---|---|---|
@@ -1,8 +1,8 @@ | ||
1 | 1 | const nest = require('depnest') |
2 | 2 | const { h, computed, when } = require('mutant') |
3 | 3 | const path = require('path') |
4 | -const { remote } = require('electron') | |
4 | +const windowControls = require('../../windowControls') | |
5 | 5 | |
6 | 6 | exports.gives = nest('app.html.header') |
7 | 7 | exports.needs = nest({ |
8 | 8 | 'app.obs.pluginsOk': 'first' |
@@ -64,35 +64,8 @@ | ||
64 | 64 | }) |
65 | 65 | ]) |
66 | 66 | ]) |
67 | 67 | }) |
68 | - | |
69 | - function windowControls () { | |
70 | - if (process.platform === 'darwin') return | |
71 | - | |
72 | - const window = remote.getCurrentWindow() | |
73 | - const minimize = () => window.minimize() | |
74 | - const maximize = () => { | |
75 | - if (!window.isMaximized()) window.maximize() | |
76 | - else window.unmaximize() | |
77 | - } | |
78 | - const close = () => window.close() | |
79 | - | |
80 | - return h('div.window-controls', [ | |
81 | - h('img.min', { | |
82 | - src: assetPath('minimize.png'), | |
83 | - 'ev-click': minimize | |
84 | - }), | |
85 | - h('img.max', { | |
86 | - src: assetPath('maximize.png'), | |
87 | - 'ev-click': maximize | |
88 | - }), | |
89 | - h('img.close', { | |
90 | - src: assetPath('close.png'), | |
91 | - 'ev-click': close | |
92 | - }) | |
93 | - ]) | |
94 | - } | |
95 | 68 | } |
96 | 69 | |
97 | 70 | function assetPath (name) { |
98 | 71 | return path.join(__dirname, '../../assets', name) |
app/page/splash.js | ||
---|---|---|
@@ -16,9 +16,8 @@ | ||
16 | 16 | |
17 | 17 | const strings = api.translations.sync.strings() |
18 | 18 | |
19 | 19 | const svg = assetPath('splash.svg') |
20 | - console.log(svg) | |
21 | 20 | |
22 | 21 | const style = { |
23 | 22 | 'background': require('../../assets/splash-svg.js'), |
24 | 23 | 'background-repeat': 'no-repeat', |
ftu/app.js | ||
---|---|---|
@@ -1,19 +1,20 @@ | ||
1 | -const { h, Value, when, resolve, computed, Struct, watch, throttle } = require('mutant') | |
1 | +const { h, Value, when, computed, Struct, watch, throttle } = require('mutant') | |
2 | 2 | const nest = require('depnest') |
3 | 3 | const path = require('path') |
4 | 4 | const fs = require('fs') |
5 | -const { remote } = require('electron') | |
6 | -const insertCss = require('insert-css') | |
7 | -const values = require('lodash/values') | |
8 | -const get = require('lodash/get') | |
9 | 5 | const electron = require('electron') |
10 | -const { dialog } = require('electron').remote | |
11 | 6 | const os = require('os') |
12 | 7 | const progress = require('progress-string') |
8 | +const values = require('lodash/values') | |
13 | 9 | |
10 | +const observeSequence = require('./observeSequence') | |
11 | +const windowControls = require('../windowControls') | |
12 | +const ftuCss = require('./styles') | |
13 | + | |
14 | 14 | const appName = process.env.SSB_APPNAME || 'ssb' |
15 | -const configFolder = path.join(os.homedir(), `.${appName}`) | |
15 | +const CONFIG_FOLDER = path.join(os.homedir(), `.${appName}`) | |
16 | +const IMPORT_FILE = path.join(CONFIG_FOLDER, 'importing.json') | |
16 | 17 | |
17 | 18 | var isBusy = Value(false) |
18 | 19 | var isPresentingOptions = Value(true) |
19 | 20 | var checkerTimeout |
@@ -36,43 +37,11 @@ | ||
36 | 37 | return nest({ |
37 | 38 | 'ftu.app': function app () { |
38 | 39 | const strings = api.translations.sync.strings() |
39 | 40 | |
40 | - const css = values(api.styles.css()).join('\n') | |
41 | - insertCss(css) | |
41 | + const css = [...values(api.styles.css()), ftuCss].join('\n') | |
42 | + document.head.appendChild(h('style', { innerHTML: css })) | |
42 | 43 | |
43 | - var actionButtons = h('section', [ | |
44 | - h('div.left', h('Button', { 'ev-click': () => actionImportIdentity(strings) }, strings.backup.ftu.importAction)), | |
45 | - h('div.right', h('Button', { 'ev-click': () => actionCreateNewOne() }, strings.backup.ftu.createAction)) | |
46 | - ]) | |
47 | - | |
48 | - var busyMessage = h('p', strings.backup.ftu.busyMessage) | |
49 | - | |
50 | - var initialOptions = h('Page -ftu', [ | |
51 | - h('div.content', [ | |
52 | - h('h1', strings.backup.ftu.welcomeHeader), | |
53 | - h('p', strings.backup.ftu.welcomeMessage), | |
54 | - when(isBusy, busyMessage, actionButtons) | |
55 | - ]) | |
56 | - ]) | |
57 | - | |
58 | - var importProgress = h('Page -ftu', [ | |
59 | - h('div.content', [ | |
60 | - h('h1', strings.backup.import.header), | |
61 | - h('p', [strings.backup.import.synchronizeMessage]), | |
62 | - h('pre', computed(state, s => { | |
63 | - return progress({ | |
64 | - width: 42, | |
65 | - total: s.latestSequence, | |
66 | - style: function (complete, incomplete) { | |
67 | - // add an arrow at the head of the completed part | |
68 | - return `${complete}>${incomplete} (${s.currentSequence}/ ${s.latestSequence})` | |
69 | - } | |
70 | - })(s.currentSequence) | |
71 | - })) | |
72 | - ]) | |
73 | - ]) | |
74 | - | |
75 | 44 | // This watcher is responsible for switching from FTU to Ticktack main app |
76 | 45 | watch(throttle(state, 500), s => { |
77 | 46 | if (s.currentSequence >= s.latestSequence && s.confirmedRemotely) { |
78 | 47 | console.log('all imported') |
@@ -80,9 +49,9 @@ | ||
80 | 49 | electron.ipcRenderer.send('import-completed') |
81 | 50 | } |
82 | 51 | }) |
83 | 52 | |
84 | - if (fs.existsSync(path.join(configFolder, 'secret'))) { | |
53 | + if (fs.existsSync(path.join(CONFIG_FOLDER, 'secret'))) { | |
85 | 54 | // somehow the FTU started but the identity is already in place. |
86 | 55 | // treat it as a failed import and start importing... |
87 | 56 | console.log('resuming import') |
88 | 57 | let previousData = getImportData() |
@@ -95,50 +64,93 @@ | ||
95 | 64 | } else { |
96 | 65 | state.latestSequence.set(previousData.latestSequence) |
97 | 66 | state.currentSequence.set(previousData.currentSequence) |
98 | 67 | isPresentingOptions.set(false) |
99 | - observeSequence() | |
68 | + observeSequence({ state, timeout: checkerTimeout }) | |
100 | 69 | } |
101 | 70 | } |
102 | 71 | |
103 | 72 | var app = h('App', [ |
104 | 73 | h('Header', [ |
74 | + h('img.logoName', { src: assetPath('logo_and_name.png') }), | |
105 | 75 | windowControls() |
106 | 76 | ]), |
107 | - when(isPresentingOptions, initialOptions, importProgress) | |
77 | + when(isPresentingOptions, InitialOptions(), ImportProgress()) | |
108 | 78 | ]) |
109 | 79 | |
110 | 80 | return app |
81 | + | |
82 | + function InitialOptions () { | |
83 | + const { welcomeHeader, welcomeMessage, busyMessage, importAction, createAction } = strings.backup.ftu | |
84 | + | |
85 | + return h('Page', [ | |
86 | + h('div.content', [ | |
87 | + h('section.welcome', [ | |
88 | + h('h1', welcomeHeader), | |
89 | + h('div', welcomeMessage) | |
90 | + ]), | |
91 | + when(isBusy, | |
92 | + h('p', busyMessage), | |
93 | + h('section.actionButtons', [ | |
94 | + h('div.left', h('Button', { 'ev-click': () => actionImportIdentity(strings) }, importAction)), | |
95 | + h('div.right', h('Button -strong', { 'ev-click': () => actionCreateNewOne() }, createAction)) | |
96 | + ]) | |
97 | + ) | |
98 | + ]) | |
99 | + ]) | |
100 | + } | |
101 | + | |
102 | + function ImportProgress () { | |
103 | + const { header, synchronizeMessage, details } = strings.backup.import | |
104 | + | |
105 | + return h('Page', [ | |
106 | + h('div.content', [ | |
107 | + h('h1', header), | |
108 | + h('p', synchronizeMessage), | |
109 | + h('pre', computed(state, s => { | |
110 | + return progress({ | |
111 | + width: 42, | |
112 | + total: s.latestSequence, | |
113 | + style: function (complete, incomplete) { | |
114 | + // add an arrow at the head of the completed part | |
115 | + return `${complete}>${incomplete} (${s.currentSequence}/ ${s.latestSequence})` | |
116 | + } | |
117 | + })(s.currentSequence) | |
118 | + })), | |
119 | + h('p', details) | |
120 | + ]) | |
121 | + ]) | |
122 | + } | |
111 | 123 | } |
112 | 124 | }) |
113 | 125 | } |
114 | 126 | |
115 | -electron.ipcRenderer.on('import-started', function (ev, c) { | |
127 | +electron.ipcRenderer.on('import-resumed', function (ev, c) { | |
116 | 128 | console.log('background process is running, begin observing') |
117 | 129 | |
118 | - observeSequence() | |
130 | + observeSequence({ state, timeout: checkerTimeout }) | |
119 | 131 | }) |
120 | 132 | |
121 | 133 | function actionCreateNewOne () { |
122 | 134 | isBusy.set(true) |
123 | 135 | const manifest = JSON.parse(fs.readFileSync(path.join(__dirname, '../manifest.json'))) |
124 | - const manifestFile = path.join(configFolder, 'manifest.json') | |
125 | - if (!fs.existsSync(configFolder)) { | |
126 | - fs.mkdirSync(configFolder) | |
136 | + const manifestFile = path.join(CONFIG_FOLDER, 'manifest.json') | |
137 | + if (!fs.existsSync(CONFIG_FOLDER)) { | |
138 | + fs.mkdirSync(CONFIG_FOLDER) | |
127 | 139 | } |
128 | 140 | fs.writeFileSync(manifestFile, JSON.stringify(manifest)) |
129 | 141 | |
130 | 142 | electron.ipcRenderer.send('create-new-identity') |
131 | 143 | } |
132 | 144 | |
133 | 145 | function actionImportIdentity (strings) { |
134 | - const peersFile = path.join(configFolder, 'gossip.json') | |
135 | - const secretFile = path.join(configFolder, 'secret') | |
146 | + const peersFile = path.join(CONFIG_FOLDER, 'gossip.json') | |
147 | + const secretFile = path.join(CONFIG_FOLDER, 'secret') | |
136 | 148 | const manifest = JSON.parse(fs.readFileSync(path.join(__dirname, '../manifest.json'))) |
137 | - const manifestFile = path.join(configFolder, 'manifest.json') | |
149 | + const manifestFile = path.join(CONFIG_FOLDER, 'manifest.json') | |
138 | 150 | |
139 | 151 | // place the other files first |
140 | - dialog.showOpenDialog( | |
152 | + electron.remote.dialog.showOpenDialog( | |
141 | 153 | { |
142 | 154 | title: strings.backup.import.dialog.title, |
143 | 155 | butttonLabel: strings.backup.import.dialog.label, |
144 | 156 | defaultPath: 'ticktack-identity.backup', |
@@ -148,10 +160,10 @@ | ||
148 | 160 | if (typeof filenames !== 'undefined') { |
149 | 161 | let filename = filenames[0] |
150 | 162 | let data = JSON.parse(fs.readFileSync(filename)) |
151 | 163 | if (data.hasOwnProperty('secret') && data.hasOwnProperty('peers') && data.hasOwnProperty('latestSequence')) { |
152 | - if (!fs.existsSync(configFolder)) { | |
153 | - fs.mkdirSync(configFolder) | |
164 | + if (!fs.existsSync(CONFIG_FOLDER)) { | |
165 | + fs.mkdirSync(CONFIG_FOLDER) | |
154 | 166 | } |
155 | 167 | |
156 | 168 | fs.writeFileSync(manifestFile, JSON.stringify(manifest)) |
157 | 169 | fs.writeFileSync(peersFile, JSON.stringify(data.peers), 'utf8') |
@@ -175,124 +187,20 @@ | ||
175 | 187 | } |
176 | 188 | ) |
177 | 189 | } |
178 | 190 | |
179 | -function windowControls () { | |
180 | - if (process.platform === 'darwin') return | |
181 | - | |
182 | - const window = remote.getCurrentWindow() | |
183 | - const minimize = () => window.minimize() | |
184 | - const maximize = () => { | |
185 | - if (!window.isMaximized()) window.maximize() | |
186 | - else window.unmaximize() | |
187 | - } | |
188 | - const close = () => window.close() | |
189 | - | |
190 | - return h('div.window-controls', [ | |
191 | - h('img.min', { | |
192 | - src: assetPath('minimize.png'), | |
193 | - 'ev-click': minimize | |
194 | - }), | |
195 | - h('img.max', { | |
196 | - src: assetPath('maximize.png'), | |
197 | - 'ev-click': maximize | |
198 | - }), | |
199 | - h('img.close', { | |
200 | - src: assetPath('close.png'), | |
201 | - 'ev-click': close | |
202 | - }) | |
203 | - ]) | |
204 | -} | |
205 | - | |
206 | 191 | function assetPath (name) { |
207 | 192 | return path.join(__dirname, '../assets', name) |
208 | 193 | } |
209 | 194 | |
210 | 195 | function getImportData () { |
211 | - var importFile = path.join(configFolder, 'importing.json') | |
212 | - if (fs.existsSync(importFile)) { | |
213 | - let data = JSON.parse(fs.readFileSync(importFile)) | |
196 | + if (fs.existsSync(IMPORT_FILE)) { | |
197 | + let data = JSON.parse(fs.readFileSync(IMPORT_FILE)) | |
214 | 198 | return data || false |
215 | 199 | } else { |
216 | 200 | return false |
217 | 201 | } |
218 | 202 | } |
219 | 203 | |
220 | 204 | function setImportData (data) { |
221 | - var importFile = path.join(configFolder, 'importing.json') | |
222 | - fs.writeFileSync(importFile, JSON.stringify(data)) | |
205 | + fs.writeFileSync(IMPORT_FILE, JSON.stringify(data)) | |
223 | 206 | } |
224 | - | |
225 | -function observeSequence () { | |
226 | - const pull = require('pull-stream') | |
227 | - const Client = require('ssb-client') | |
228 | - const config = require('../config').create().config.sync.load() | |
229 | - | |
230 | - Client(config.keys, config, (err, ssbServer) => { | |
231 | - if (err) return console.error('problem starting client', err) | |
232 | - | |
233 | - console.log('> sbot running!!!!') | |
234 | - | |
235 | - ssbServer.gossip.peers((err, peers) => { | |
236 | - if (err) return console.error(err) | |
237 | - | |
238 | - connectToPeers(peers) | |
239 | - checkPeers() | |
240 | - }) | |
241 | - | |
242 | - // start listening to the my seq, and update the state | |
243 | - pull( | |
244 | - ssbServer.createUserStream({ live: true, id: ssbServer.id }), | |
245 | - pull.drain((msg) => { | |
246 | - let seq = get(msg, 'value.sequence', false) | |
247 | - if (seq) { | |
248 | - state.currentSequence.set(seq) | |
249 | - } | |
250 | - }) | |
251 | - ) | |
252 | - | |
253 | - function connectToPeers (peers) { | |
254 | - if (peers.length > 10) { | |
255 | - const lessPeers = peers.filter(p => !p.error) | |
256 | - if (lessPeers.length > 10) peers = lessPeers | |
257 | - } | |
258 | - | |
259 | - peers.forEach(({ host, port, key }) => { | |
260 | - if (host && port && key) { | |
261 | - ssbServer.gossip.connect({ host, port, key }, (err, v) => { | |
262 | - if (err) console.log('error connecting to ', host, err) | |
263 | - else console.log('connected to ', host) | |
264 | - }) | |
265 | - } | |
266 | - }) | |
267 | - } | |
268 | - function checkPeers () { | |
269 | - ssbServer.ebt.peerStatus(ssbServer.id, (err, data) => { | |
270 | - if (err) { | |
271 | - checkerTimeout = setTimeout(checkPeers, 5000) | |
272 | - return | |
273 | - } | |
274 | - | |
275 | - const latest = resolve(state.latestSequence) | |
276 | - | |
277 | - const remoteSeqs = Object.keys(data.peers) | |
278 | - .map(p => data.peers[p].seq) // get my seq reported by each peer | |
279 | - .filter(s => s >= latest) // only keep remote seq that confirm or update backup seq | |
280 | - .sort((a, b) => a > b ? -1 : 1) // order them | |
281 | - | |
282 | - console.log(remoteSeqs) | |
283 | - | |
284 | - const newLatest = remoteSeqs[0] | |
285 | - if (newLatest) { | |
286 | - state.latestSequence.set(newLatest) | |
287 | - | |
288 | - // if this value is confirmed remotely twice, assume safe | |
289 | - if (remoteSeqs.filter(s => s === newLatest).length >= 2) { | |
290 | - state.confirmedRemotely.set(true) | |
291 | - } | |
292 | - } | |
293 | - | |
294 | - checkerTimeout = setTimeout(checkPeers, 5000) | |
295 | - }) | |
296 | - } | |
297 | - }) | |
298 | -} |
ftu/index.js | ||
---|---|---|
@@ -1,9 +1,8 @@ | ||
1 | 1 | const combine = require('depject') |
2 | 2 | const entry = require('depject/entry') |
3 | 3 | const nest = require('depnest') |
4 | 4 | |
5 | - | |
6 | 5 | // polyfills |
7 | 6 | require('setimmediate') |
8 | 7 | |
9 | 8 | // add inspect right click menu |
@@ -12,11 +11,11 @@ | ||
12 | 11 | // from more specialized to more general |
13 | 12 | const sockets = combine( |
14 | 13 | // need some modules first |
15 | 14 | { |
16 | - styles: require('../styles'), | |
17 | 15 | settings: require('patch-settings'), |
18 | 16 | translations: require('../translations/sync'), |
17 | + styles: require('../styles') | |
19 | 18 | }, |
20 | 19 | { |
21 | 20 | app: require('./app') |
22 | 21 | } |
ftu/app.mcss | ||
---|---|---|
@@ -1,56 +1,0 @@ | ||
1 | -App { | |
2 | - overflow: hidden | |
3 | - position: fixed | |
4 | - top: 0 | |
5 | - bottom: 0 | |
6 | - right: 0 | |
7 | - left: 0 | |
8 | -} | |
9 | - | |
10 | -Page -ftu { | |
11 | - margin-top: 0 | |
12 | - height: calc(100%) | |
13 | - | |
14 | - div.content { | |
15 | - section { | |
16 | - display: flex | |
17 | - align-content: center | |
18 | - | |
19 | - div { | |
20 | - padding: .5rem | |
21 | - | |
22 | - display: flex | |
23 | - align-items: center | |
24 | - } | |
25 | - | |
26 | - div.left { | |
27 | - flex-basis: 40% | |
28 | - justify-content: flex-end | |
29 | - } | |
30 | - div.right { | |
31 | - flex-basis: 60% | |
32 | - justify-content: flex-start | |
33 | - } | |
34 | - } | |
35 | - } | |
36 | -} | |
37 | - | |
38 | -Header { | |
39 | - div.window-controls { | |
40 | - position: fixed | |
41 | - right: 0 | |
42 | - z-index: 100 | |
43 | - | |
44 | - display: flex | |
45 | - | |
46 | - img { | |
47 | - padding: .5rem | |
48 | - cursor: pointer | |
49 | - :hover { | |
50 | - filter: drop-shadow(rgba(255, 255, 255, .5) 0 0 2px) | |
51 | - } | |
52 | - } | |
53 | - } | |
54 | -} | |
55 | - | |
56 | - |
ftu/observeSequence.js | ||
---|---|---|
@@ -1,0 +1,80 @@ | ||
1 | +const get = require('lodash/get') | |
2 | +const pull = require('pull-stream') | |
3 | +const Client = require('ssb-client') | |
4 | +const { resolve } = require('mutant') | |
5 | + | |
6 | +function observeSequence ({ state, timeout }) { | |
7 | + const config = require('../config').create().config.sync.load() | |
8 | + | |
9 | + Client(config.keys, config, (err, ssbServer) => { | |
10 | + if (err) return console.error('problem starting client', err) | |
11 | + | |
12 | + console.log('> sbot running!!!!') | |
13 | + | |
14 | + ssbServer.gossip.peers((err, peers) => { | |
15 | + if (err) return console.error(err) | |
16 | + | |
17 | + connectToPeers(peers) | |
18 | + checkPeers() | |
19 | + }) | |
20 | + | |
21 | + // start listening to the my seq, and update the state | |
22 | + pull( | |
23 | + ssbServer.createUserStream({ live: true, id: ssbServer.id }), | |
24 | + pull.drain((msg) => { | |
25 | + let seq = get(msg, 'value.sequence', false) | |
26 | + if (seq) { | |
27 | + state.currentSequence.set(seq) | |
28 | + } | |
29 | + }) | |
30 | + ) | |
31 | + | |
32 | + function connectToPeers (peers) { | |
33 | + if (peers.length > 10) { | |
34 | + const lessPeers = peers.filter(p => !p.error) | |
35 | + if (lessPeers.length > 10) peers = lessPeers | |
36 | + } | |
37 | + | |
38 | + peers.forEach(({ host, port, key }) => { | |
39 | + if (host && port && key) { | |
40 | + ssbServer.gossip.connect({ host, port, key }, (err, v) => { | |
41 | + if (err) console.log('error connecting to ', host, err) | |
42 | + else console.log('connected to ', host) | |
43 | + }) | |
44 | + } | |
45 | + }) | |
46 | + } | |
47 | + | |
48 | + function checkPeers () { | |
49 | + ssbServer.ebt.peerStatus(ssbServer.id, (err, data) => { | |
50 | + if (err) { | |
51 | + timeout = setTimeout(checkPeers, 5000) | |
52 | + return | |
53 | + } | |
54 | + | |
55 | + const latest = resolve(state.latestSequence) | |
56 | + | |
57 | + const remoteSeqs = Object.keys(data.peers) | |
58 | + .map(p => data.peers[p].seq) // get my seq reported by each peer | |
59 | + .filter(s => s >= latest) // only keep remote seq that confirm or update backup seq | |
60 | + .sort((a, b) => a > b ? -1 : 1) // order them | |
61 | + | |
62 | + // console.log(remoteSeqs) | |
63 | + | |
64 | + const newLatest = remoteSeqs[0] | |
65 | + if (newLatest) { | |
66 | + state.latestSequence.set(newLatest) | |
67 | + | |
68 | + // if this value is confirmed remotely twice, assume safe | |
69 | + if (remoteSeqs.filter(s => s === newLatest).length >= 2) { | |
70 | + state.confirmedRemotely.set(true) | |
71 | + } | |
72 | + } | |
73 | + | |
74 | + timeout = setTimeout(checkPeers, 5000) | |
75 | + }) | |
76 | + } | |
77 | + }) | |
78 | +} | |
79 | + | |
80 | +module.exports = observeSequence |
ftu/styles.js | ||
---|---|---|
@@ -1,0 +1,69 @@ | ||
1 | +const compile = require('micro-css') | |
2 | + | |
3 | +const styles = ` | |
4 | +App { | |
5 | + overflow: hidden | |
6 | + position: fixed | |
7 | + top: 0 | |
8 | + bottom: 0 | |
9 | + right: 0 | |
10 | + left: 0 | |
11 | +} | |
12 | + | |
13 | +Page { | |
14 | + padding-top: 6.5rem | |
15 | + margin-top: 0 | |
16 | + height: calc(100%) | |
17 | + | |
18 | + div.content { | |
19 | + max-width: 35rem | |
20 | + padding: 2rem | |
21 | + section { | |
22 | + display: flex | |
23 | + align-items: center | |
24 | + justify-content: center | |
25 | + | |
26 | + div { | |
27 | + padding: .5rem | |
28 | + | |
29 | + display: flex | |
30 | + align-items: center | |
31 | + } | |
32 | + } | |
33 | + | |
34 | + section.welcome { | |
35 | + flex-direction: column | |
36 | + } | |
37 | + } | |
38 | +} | |
39 | + | |
40 | +Header { | |
41 | + height: 6.5rem | |
42 | + background-color: #2f5ea1 | |
43 | + | |
44 | + display: initial | |
45 | + | |
46 | + img.logoName { | |
47 | + margin: 1rem | |
48 | + } | |
49 | + | |
50 | + div.window-controls { | |
51 | + position: fixed | |
52 | + top: 0 | |
53 | + right: 0 | |
54 | + z-index: 100 | |
55 | + | |
56 | + display: flex | |
57 | + | |
58 | + img { | |
59 | + padding: .5rem | |
60 | + cursor: pointer | |
61 | + :hover { | |
62 | + filter: drop-shadow(rgba(255, 255, 255, .5) 0 0 2px) | |
63 | + } | |
64 | + } | |
65 | + } | |
66 | +} | |
67 | +` | |
68 | + | |
69 | +module.exports = compile(styles) |
index.js | ||
---|---|---|
@@ -8,10 +8,10 @@ | ||
8 | 8 | const fs = require('fs') |
9 | 9 | const path = require('path') |
10 | 10 | const os = require('os') |
11 | 11 | const appName = process.env.SSB_APPNAME || 'ssb' |
12 | -const configFolder = path.join(os.homedir(), `.${appName}`) | |
13 | -const isInstalled = fs.existsSync(Path.join(configFolder, 'secret')) | |
12 | +const CONFIG_FOLDER = path.join(os.homedir(), `.${appName}`) | |
13 | +const IMPORT_FILE = path.join(CONFIG_FOLDER, 'importing.json') | |
14 | 14 | |
15 | 15 | var windows = {} |
16 | 16 | var quitting = false |
17 | 17 | |
@@ -40,9 +40,9 @@ | ||
40 | 40 | } |
41 | 41 | |
42 | 42 | Menu.setApplicationMenu(Menu.buildFromTemplate(menu)) |
43 | 43 | |
44 | - if (!isInstalled) { | |
44 | + if (!fs.existsSync(Path.join(CONFIG_FOLDER, 'secret'))) { | |
45 | 45 | console.log('Ticktack or SSB not installed, run FTU') |
46 | 46 | openFTUWindow() |
47 | 47 | } else { |
48 | 48 | startBackgroundProcess() |
@@ -54,9 +54,9 @@ | ||
54 | 54 | setImportRunningFlag(false) |
55 | 55 | startBackgroundProcess() |
56 | 56 | }) |
57 | 57 | |
58 | - // FTU told app to import some identity, need to start sbot and keep FTU running | |
58 | + // FTU told app to import some identity, need to start sbot and keep FTU running | |
59 | 59 | electron.ipcMain.once('import-identity', function (ev) { |
60 | 60 | console.log('import identity') |
61 | 61 | setImportRunningFlag(true) |
62 | 62 | startBackgroundProcess() |
@@ -72,15 +72,15 @@ | ||
72 | 72 | // wait until server has started before opening main window |
73 | 73 | electron.ipcMain.once('server-started', function (ev, config) { |
74 | 74 | let keepFTURunning = getImportRunningFlag(false) |
75 | 75 | if (!keepFTURunning) { |
76 | - console.log("> Opening main window") | |
76 | + console.log('> Opening main window') | |
77 | 77 | openMainWindow() |
78 | 78 | } else { |
79 | 79 | // sbot started but we're importing an older identity, need |
80 | 80 | // to tell FTU to wait for sync. |
81 | 81 | openFTUWindow() |
82 | - windows.ftu.webContents.send('import-started') | |
82 | + windows.ftu.webContents.send('import-resumed') | |
83 | 83 | } |
84 | 84 | }) |
85 | 85 | |
86 | 86 | electron.app.on('before-quit', function () { |
@@ -94,9 +94,9 @@ | ||
94 | 94 | } |
95 | 95 | }) |
96 | 96 | }) |
97 | 97 | |
98 | -function startBackgroundProcess() { | |
98 | +function startBackgroundProcess () { | |
99 | 99 | if (!windows.background) { |
100 | 100 | windows.background = openWindow(Path.join(__dirname, 'background-process.js'), { |
101 | 101 | connect: false, |
102 | 102 | center: true, |
@@ -114,9 +114,9 @@ | ||
114 | 114 | }) |
115 | 115 | } |
116 | 116 | } |
117 | 117 | |
118 | -function openMainWindow() { | |
118 | +function openMainWindow () { | |
119 | 119 | if (!windows.main) { |
120 | 120 | var windowState = WindowState({ |
121 | 121 | defaultWidth: 1024, |
122 | 122 | defaultHeight: 768 |
@@ -153,9 +153,9 @@ | ||
153 | 153 | } |
154 | 154 | } |
155 | 155 | } |
156 | 156 | |
157 | -function openFTUWindow() { | |
157 | +function openFTUWindow () { | |
158 | 158 | if (!windows.ftu) { |
159 | 159 | var windowState = WindowState({ |
160 | 160 | defaultWidth: 1024, |
161 | 161 | defaultHeight: 768 |
@@ -188,9 +188,9 @@ | ||
188 | 188 | }) |
189 | 189 | } |
190 | 190 | } |
191 | 191 | |
192 | -function openWindow(path, opts) { | |
192 | +function openWindow (path, opts) { | |
193 | 193 | var window = new electron.BrowserWindow(opts) |
194 | 194 | window.webContents.on('dom-ready', function () { |
195 | 195 | window.webContents.executeJavaScript(` |
196 | 196 | var electron = require('electron') |
@@ -217,25 +217,23 @@ | ||
217 | 217 | window.loadURL('file://' + Path.join(__dirname, 'assets', 'base.html')) |
218 | 218 | return window |
219 | 219 | } |
220 | 220 | |
221 | -function getImportRunningFlag(defaultValue) { | |
222 | - var importFile = Path.join(configFolder, 'importing.json') | |
223 | - if (fs.existsSync(importFile)) { | |
224 | - let data = JSON.parse(fs.readFileSync(importFile)) | |
221 | +function getImportRunningFlag (defaultValue) { | |
222 | + if (fs.existsSync(IMPORT_FILE)) { | |
223 | + let data = JSON.parse(fs.readFileSync(IMPORT_FILE)) | |
225 | 224 | return data.importing || defaultValue |
226 | 225 | } else { |
227 | 226 | return defaultValue |
228 | 227 | } |
229 | 228 | } |
230 | 229 | |
231 | -function setImportRunningFlag(v) { | |
230 | +function setImportRunningFlag (v) { | |
232 | 231 | let data = {} |
233 | - var importFile = Path.join(configFolder, 'importing.json') | |
234 | - if (fs.existsSync(importFile)) { | |
235 | - data = JSON.parse(fs.readFileSync(importFile)) | |
232 | + if (fs.existsSync(IMPORT_FILE)) { | |
233 | + data = JSON.parse(fs.readFileSync(IMPORT_FILE)) | |
236 | 234 | } |
237 | 235 | |
238 | 236 | data.importing = v |
239 | 237 | |
240 | - fs.writeFileSync(importFile, JSON.stringify(data)) | |
241 | -} | |
238 | + fs.writeFileSync(IMPORT_FILE, JSON.stringify(data)) | |
239 | +} |
package-lock.json | ||
---|---|---|
The diff is too large to show. Use a local git client to view these changes. Old file size: 283352 bytes New file size: 283162 bytes |
package.json | ||
---|---|---|
@@ -32,9 +32,8 @@ | ||
32 | 32 | "html-escape": "^2.0.0", |
33 | 33 | "human-time": "0.0.1", |
34 | 34 | "hyper-nav": "^2.0.0", |
35 | 35 | "hypermore": "^2.0.0", |
36 | - "insert-css": "^2.0.0", | |
37 | 36 | "libnested": "^1.2.1", |
38 | 37 | "lodash": "^4.17.4", |
39 | 38 | "markdown-summary": "^1.0.3", |
40 | 39 | "medium-editor": "^5.23.3", |
translations/en.js | ||
---|---|---|
@@ -212,50 +212,18 @@ | ||
212 | 212 | title: 'Export Identity' |
213 | 213 | } |
214 | 214 | }, |
215 | 215 | import: { |
216 | - header: 'Import identity', | |
217 | 216 | importAction: 'Import Identity', |
218 | - synchronizeMessage: 'Synchronizing feed: ', | |
217 | + header: 'Importing identity', | |
218 | + synchronizeMessage: 'Progress', | |
219 | 219 | dialog: { |
220 | 220 | label: 'Import Identity', |
221 | 221 | title: 'Import Identity' |
222 | - } | |
222 | + }, | |
223 | + details: 'Reconstructing your identity will take some time. Ticktack will launch once your identity is synchoronized, but it will take some time to gather your friends data, so some message and blogs will arrive later. You can safely close this window and Ticktack will resume sync next time you open it.' | |
223 | 224 | } |
224 | 225 | }, |
225 | - backup: { | |
226 | - sectionName: 'Backup', | |
227 | - ftu: { | |
228 | - importAction: 'Import identity', | |
229 | - createAction: 'Create new identity', | |
230 | - busyMessage: 'Processing...', | |
231 | - welcomeHeader: 'Welcome to Ticktack', | |
232 | - welcomeMessage: 'Do you want to create a new identity or import one?' | |
233 | - }, | |
234 | - export: { | |
235 | - header: 'Export identity', | |
236 | - message: [ | |
237 | - 'Please backup your private key file very carefully.', | |
238 | - 'If your private key is hacked, all your private messages will be retrieved by third party, and your identity will be faked on the network' | |
239 | - ], | |
240 | - passwordPlaceholder: 'Please enter password to protect export file', | |
241 | - cancelAction: 'Cancel', | |
242 | - exportAction: 'Export Identity', | |
243 | - dialog: { | |
244 | - label: 'Export Identity', | |
245 | - title: 'Export Identity' | |
246 | - } | |
247 | - }, | |
248 | - import: { | |
249 | - header: 'Import identity', | |
250 | - importAction: 'Import Identity', | |
251 | - synchronizeMessage: 'Synchronizing feed: ', | |
252 | - dialog: { | |
253 | - label: 'Import Identity', | |
254 | - title: 'Import Identity' | |
255 | - } | |
256 | - } | |
257 | - }, | |
258 | 226 | languages: { |
259 | 227 | en: 'English', |
260 | 228 | zh: '中文' |
261 | 229 | } |
windowControls.js | ||
---|---|---|
@@ -1,0 +1,36 @@ | ||
1 | +const { h } = require('mutant') | |
2 | +const { remote } = require('electron') | |
3 | +const path = require('path') | |
4 | + | |
5 | +function windowControls () { | |
6 | + if (process.platform === 'darwin') return | |
7 | + | |
8 | + const window = remote.getCurrentWindow() | |
9 | + const minimize = () => window.minimize() | |
10 | + const maximize = () => { | |
11 | + if (!window.isMaximized()) window.maximize() | |
12 | + else window.unmaximize() | |
13 | + } | |
14 | + const close = () => window.close() | |
15 | + | |
16 | + return h('div.window-controls', [ | |
17 | + h('img.min', { | |
18 | + src: assetPath('minimize.png'), | |
19 | + 'ev-click': minimize | |
20 | + }), | |
21 | + h('img.max', { | |
22 | + src: assetPath('maximize.png'), | |
23 | + 'ev-click': maximize | |
24 | + }), | |
25 | + h('img.close', { | |
26 | + src: assetPath('close.png'), | |
27 | + 'ev-click': close | |
28 | + }) | |
29 | + ]) | |
30 | +} | |
31 | + | |
32 | +module.exports = windowControls | |
33 | + | |
34 | +function assetPath (name) { | |
35 | + return path.join(__dirname, 'assets', name) | |
36 | +} |
Built with git-ssb-web