diff --git a/src/main/windows/main.js b/src/main/windows/main.js index 3c8d26f4..0cd82636 100644 --- a/src/main/windows/main.js +++ b/src/main/windows/main.js @@ -45,18 +45,26 @@ function init (state, options) { y: initialBounds.y }) - win.once('ready-to-show', function () { + win.loadURL(config.WINDOW_MAIN) + + win.once('ready-to-show', () => { if (!options.hidden) win.show() }) - win.loadURL(config.WINDOW_MAIN) - - if (win.setSheetOffset) win.setSheetOffset(config.UI_HEADER_HEIGHT) + if (win.setSheetOffset) { + win.setSheetOffset(config.UI_HEADER_HEIGHT) + } win.webContents.on('dom-ready', function () { menu.onToggleFullScreen(main.win.isFullScreen()) }) + win.webContents.on('will-navigate', (e, url) => { + // Prevent drag-and-drop from navigating the Electron window, which can happen + // before our drag-and-drop handlers have been initialized. + e.preventDefault() + }) + win.on('blur', onWindowBlur) win.on('focus', onWindowFocus) diff --git a/src/renderer/lib/state.js b/src/renderer/lib/state.js index 14f38a7e..af506482 100644 --- a/src/renderer/lib/state.js +++ b/src/renderer/lib/state.js @@ -6,6 +6,8 @@ const config = require('../../config') const SAVE_DEBOUNCE_INTERVAL = 1000 +appConfig.filePath = path.join(config.CONFIG_PATH, 'config.json') + const State = module.exports = Object.assign(new EventEmitter(), { getDefaultPlayState, load, @@ -16,13 +18,11 @@ const State = module.exports = Object.assign(new EventEmitter(), { // After first State.save() invokation, future calls go straight to the // debounced function State.save = debounce(saveImmediate, SAVE_DEBOUNCE_INTERVAL) - State.save() + State.save(...arguments) }, saveImmediate }) -appConfig.filePath = path.join(config.CONFIG_PATH, 'config.json') - function getDefaultState () { const LocationHistory = require('location-history') diff --git a/src/renderer/lib/telemetry.js b/src/renderer/lib/telemetry.js index 758b55a4..386161c6 100644 --- a/src/renderer/lib/telemetry.js +++ b/src/renderer/lib/telemetry.js @@ -2,6 +2,7 @@ // Reports back so that we can improve WebTorrent Desktop module.exports = { init, + send, logUncaughtError, logPlayAttempt } @@ -22,7 +23,9 @@ function init (state) { telemetry = state.saved.telemetry = createSummary() reset() } +} +function send (state) { const now = new Date() telemetry.version = config.APP_VERSION telemetry.timestamp = now.toISOString() @@ -223,7 +226,7 @@ function getElemString (elem) { let ret = elem.tagName try { ret += '.' + Array.from(elem.classList).join('.') - } catch (e) {} + } catch (err) {} return ret } diff --git a/src/renderer/main.js b/src/renderer/main.js index 2dc56f9c..783562f4 100644 --- a/src/renderer/main.js +++ b/src/renderer/main.js @@ -3,6 +3,12 @@ console.time('init') const crashReporter = require('../crash-reporter') crashReporter.init() +// Perf optimization: Start asynchronously read on config file before all the +// blocking require() calls below. + +const State = require('./lib/state') +State.load(onState) + const dragDrop = require('drag-drop') const electron = require('electron') const fs = require('fs') @@ -12,7 +18,6 @@ const ReactDOM = require('react-dom') const config = require('../config') const telemetry = require('./lib/telemetry') const sound = require('./lib/sound') -const State = require('./lib/state') const TorrentPlayer = require('./lib/torrent-player') // Required by Material UI -- adds `onTouchTap` event @@ -50,22 +55,22 @@ let state // Root React component let app -State.load(onState) - // Called once when the application loads. (Not once per window.) // Connects to the torrent networks, sets up the UI and OS integrations like // the dock icon and drag+drop. function onState (err, _state) { if (err) return onError(err) - state = window.state = _state // Make available for easier debugging + + // Make available for easier debugging + state = window.state = _state window.dispatch = dispatch telemetry.init(state) // Log uncaught JS errors - window.addEventListener('error', - (e) => telemetry.logUncaughtError('window', e), - true /* capture */) + window.addEventListener( + 'error', (e) => telemetry.logUncaughtError('window', e), true /* capture */ + ) // Create controllers controllers = { @@ -90,23 +95,18 @@ function onState (err, _state) { // Restart everything we were torrenting last time the app ran resumeTorrents() + // Initialize ReactDOM + app = ReactDOM.render(, document.querySelector('#body')) + // Calling update() updates the UI given the current state // Do this at least once a second to give every file in every torrentSummary // a progress bar and to keep the cursor in sync when playing a video setInterval(update, 1000) - app = ReactDOM.render(, document.querySelector('#body')) - - // Lazy-load other stuff, like the AppleTV module, later to keep startup fast - window.setTimeout(delayedInit, config.DELAYED_INIT) // Listen for messages from the main process setupIpc() - // Warn if the download dir is gone, eg b/c an external drive is unplugged - checkDownloadPath() - - // OS integrations: - // ...drag and drop files/text to start torrenting or seeding + // Drag and drop files/text to start torrenting or seeding dragDrop('body', { onDrop: onOpen, onDropText: onOpen @@ -119,18 +119,28 @@ function onState (err, _state) { window.addEventListener('focus', onFocus) window.addEventListener('blur', onBlur) - // ...window visibility state. - document.addEventListener('webkitvisibilitychange', onVisibilityChange) - - // Done! Ideally we want to get here < 500ms after the user clicks the app if (electron.remote.getCurrentWindow().isVisible()) { sound.play('STARTUP') } + + // To keep app startup fast, some code is delayed. + window.setTimeout(delayedInit, config.DELAYED_INIT) + + // Done! Ideally we want to get here < 500ms after the user clicks the app console.timeEnd('init') } // Runs a few seconds after the app loads, to avoid slowing down startup time function delayedInit () { + telemetry.send(state) + + // Warn if the download dir is gone, eg b/c an external drive is unplugged + checkDownloadPath() + + // ...window visibility state. + document.addEventListener('webkitvisibilitychange', onVisibilityChange) + onVisibilityChange() + lazyLoadCast() }