From aa82f736819d5dfe8dc7a9e468f3cfd6d0243d46 Mon Sep 17 00:00:00 2001 From: Feross Aboukhadijeh Date: Mon, 7 Mar 2016 18:58:43 -0800 Subject: [PATCH 1/6] faster animation fade in --- renderer/index.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renderer/index.css b/renderer/index.css index c023a7a4..e8d465df 100644 --- a/renderer/index.css +++ b/renderer/index.css @@ -63,7 +63,7 @@ body { height: 100%; display: flex; flex-flow: column; - animation: fadein 1s; + animation: fadein 0.3s; } /* From 5171e1a7daddea80e0b55f4a102222b4afa8bed8 Mon Sep 17 00:00:00 2001 From: Feross Aboukhadijeh Date: Mon, 7 Mar 2016 18:59:03 -0800 Subject: [PATCH 2/6] code style --- renderer/index.js | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/renderer/index.js b/renderer/index.js index ee0acd96..d2f45d43 100644 --- a/renderer/index.js +++ b/renderer/index.js @@ -1,4 +1,5 @@ console.time('init') + var airplay = require('airplay-js') var cfg = require('application-config')('WebTorrent') var cfgDirectory = require('application-config-path')('WebTorrent') @@ -9,6 +10,7 @@ var dragDrop = require('drag-drop') var electron = require('electron') var EventEmitter = require('events') var fs = require('fs') +var ipcRenderer = electron.ipcRenderer var mainLoop = require('main-loop') var networkAddress = require('network-address') var path = require('path') @@ -84,7 +86,7 @@ function init () { // ...same thing if you paste a torrent document.addEventListener('paste', function () { - electron.ipcRenderer.send('addTorrentFromPaste') + ipcRenderer.send('addTorrentFromPaste') }) // ...keyboard shortcuts @@ -103,7 +105,7 @@ function init () { // ...focus and blur. Needed to show correct dock icon text ("badge") in OSX window.addEventListener('focus', function () { state.isFocused = true - if (state.dock.badge > 0) electron.ipcRenderer.send('setBadge', '') + if (state.dock.badge > 0) ipcRenderer.send('setBadge', '') state.dock.badge = 0 }) @@ -175,7 +177,7 @@ function dispatch (action, ...args) { update() } if (action === 'toggleFullScreen') { - electron.ipcRenderer.send('toggleFullScreen') + ipcRenderer.send('toggleFullScreen') update() } if (action === 'videoMouseMoved') { @@ -185,20 +187,20 @@ function dispatch (action, ...args) { } function setupIpc () { - electron.ipcRenderer.on('addTorrent', function (e, torrentId) { + ipcRenderer.on('addTorrent', function (e, torrentId) { dispatch('addTorrent', torrentId) }) - electron.ipcRenderer.on('seed', function (e, files) { + ipcRenderer.on('seed', function (e, files) { dispatch('seed', files) }) - electron.ipcRenderer.on('fullscreenChanged', function (e, isFullScreen) { + ipcRenderer.on('fullscreenChanged', function (e, isFullScreen) { state.isFullScreen = isFullScreen update() }) - electron.ipcRenderer.on('addFakeDevice', function (e, device) { + ipcRenderer.on('addFakeDevice', function (e, device) { var player = new EventEmitter() player.play = (networkURL) => console.log(networkURL) state.devices[device] = player @@ -220,7 +222,7 @@ function detectDevices () { function loadState (callback) { cfg.read(function (err, data) { if (err) console.error(err) - electron.ipcRenderer.send('log', 'loaded state from ' + cfg.filePath) + ipcRenderer.send('log', 'loaded state from ' + cfg.filePath) // populate defaults if they're not there state.saved = Object.assign({}, state.defaultSavedState, data) @@ -238,7 +240,7 @@ function resumeTorrents () { // Write state.saved to the JSON state file function saveState () { - electron.ipcRenderer.send('log', 'saving state to ' + cfg.filePath) + ipcRenderer.send('log', 'saving state to ' + cfg.filePath) cfg.write(state.saved, function (err) { if (err) console.error(err) update() @@ -256,7 +258,7 @@ function updateDockIcon () { } if (progress !== state.dock.progress) { state.dock.progress = progress - electron.ipcRenderer.send('setProgress', progress) + ipcRenderer.send('setProgress', progress) } } @@ -365,7 +367,7 @@ function addTorrentEvents (torrent) { if (!state.isFocused) { state.dock.badge += 1 - electron.ipcRenderer.send('setBadge', state.dock.badge) + ipcRenderer.send('setBadge', state.dock.badge) } update() @@ -432,7 +434,7 @@ function closePlayer () { state.url = '/' state.title = config.APP_NAME if (state.isFullScreen) { - electron.ipcRenderer.send('toggleFullScreen') + ipcRenderer.send('toggleFullScreen') } restoreBounds() stopServer() @@ -507,14 +509,14 @@ function setDimensions (dimensions) { var x = Math.floor((screenWidth - width) / 2) var y = Math.floor((screenHeight - height) / 2) - electron.ipcRenderer.send('setAspectRatio', aspectRatio) - electron.ipcRenderer.send('setBounds', {x, y, width, height}) + ipcRenderer.send('setAspectRatio', aspectRatio) + ipcRenderer.send('setBounds', {x, y, width, height}) } function restoreBounds () { - electron.ipcRenderer.send('setAspectRatio', 0) + ipcRenderer.send('setAspectRatio', 0) if (state.mainWindowBounds) { - electron.ipcRenderer.send('setBounds', state.mainWindowBounds, true) + ipcRenderer.send('setBounds', state.mainWindowBounds, true) } } From 8ab2a1415bb6bf83c0efb7f703d97cbdd716a8f5 Mon Sep 17 00:00:00 2001 From: Feross Aboukhadijeh Date: Mon, 7 Mar 2016 19:36:01 -0800 Subject: [PATCH 3/6] =?UTF-8?q?update=20player=20window=20title=C2=A0to=20?= =?UTF-8?q?torrent=20name=20(Windows,=20Linux)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This also moves all the state “diffing” for purposes of updating the app’s window via Electron APIs into one function updateElectron(). --- main/ipc.js | 4 ++++ renderer/index.js | 32 +++++++++++++++++++++++--------- renderer/state.js | 1 + 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/main/ipc.js b/main/ipc.js index 9fdaf938..ea476b06 100644 --- a/main/ipc.js +++ b/main/ipc.js @@ -32,6 +32,10 @@ function init () { windows.main.setFullScreen(!windows.main.isFullScreen()) }) + ipcMain.on('setTitle', function (e, title) { + windows.main.setTitle(title) + }) + ipcMain.on('log', function (e, message) { console.log(message) }) diff --git a/renderer/index.js b/renderer/index.js index d2f45d43..6b240487 100644 --- a/renderer/index.js +++ b/renderer/index.js @@ -68,7 +68,10 @@ function init () { // Calling update() updates the UI given the current state // Do this at least once a second to show latest state for each torrent // (eg % downloaded) and to keep the cursor in sync when playing a video - setInterval(update, 1000) + setInterval(function () { + update() + updateClientProgress() + }, 1000) // All state lives in state.js. `state.saved` is read from and written to a // file. All other state is ephemeral. Here we'll load state.saved: @@ -105,7 +108,6 @@ function init () { // ...focus and blur. Needed to show correct dock icon text ("badge") in OSX window.addEventListener('focus', function () { state.isFocused = true - if (state.dock.badge > 0) ipcRenderer.send('setBadge', '') state.dock.badge = 0 }) @@ -127,7 +129,21 @@ function render (state) { // Calls render() to go from state -> UI, then applies to vdom to the real DOM. function update () { vdomLoop.update(state) - updateDockIcon() + updateElectron() +} + +function updateElectron () { + if (state.title !== state.prev.title) { + state.prev.title = state.title + ipcRenderer.send('setTitle', state.title) + } + if (state.dock.progress !== state.prev.progress) { + state.prev.progress = state.dock.progress + ipcRenderer.send('setProgress', state.dock.progress) + } + if (state.dock.badge !== state.prev.badge) { + ipcRenderer.send('setBadge', state.dock.badge || '') + } } // Events from the UI never modify state directly. Instead they call dispatch() @@ -247,7 +263,7 @@ function saveState () { }) } -function updateDockIcon () { +function updateClientProgress () { var progress = state.client.progress var activeTorrentsExist = state.client.torrents.some(function (torrent) { return torrent.progress !== 1 @@ -256,10 +272,7 @@ function updateDockIcon () { if (!activeTorrentsExist || progress === 1) { progress = -1 } - if (progress !== state.dock.progress) { - state.dock.progress = progress - ipcRenderer.send('setProgress', progress) - } + state.dock.progress = progress } function onFiles (files) { @@ -367,7 +380,6 @@ function addTorrentEvents (torrent) { if (!state.isFocused) { state.dock.badge += 1 - ipcRenderer.send('setBadge', state.dock.badge) } update() @@ -433,6 +445,8 @@ function openPlayer (infoHash) { function closePlayer () { state.url = '/' state.title = config.APP_NAME + update() + if (state.isFullScreen) { ipcRenderer.send('toggleFullScreen') } diff --git a/renderer/state.js b/renderer/state.js index 4fb84a45..8fe8b7a2 100644 --- a/renderer/state.js +++ b/renderer/state.js @@ -31,6 +31,7 @@ module.exports = { duration: 1, /* seconds */ mouseStationarySince: 0 /* Unix time in ms */ }, + prev: {}, /* used for state diffing in updateElectron() */ /* Saved state is read from and written to a file every time the app runs. * It should be simple and minimal and must be JSON. From 7c68be4fd42ea82f343afef67e2a6f275e198e51 Mon Sep 17 00:00:00 2001 From: Feross Aboukhadijeh Date: Mon, 7 Mar 2016 19:36:08 -0800 Subject: [PATCH 4/6] code style --- main/windows.js | 11 +++++------ renderer/index.js | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/main/windows.js b/main/windows.js index 1ab7c3b0..2d65065d 100644 --- a/main/windows.js +++ b/main/windows.js @@ -1,13 +1,14 @@ +var windows = module.exports = { + main: null, + createMainWindow: createMainWindow +} + var config = require('../config') var debug = require('debug')('webtorrent-app:windows') var electron = require('electron') var app = electron.app -var windows = { - main: null, - createMainWindow: createMainWindow -} var isQuitting = false app.on('before-quit', function () { @@ -55,5 +56,3 @@ function createMainWindow (menu) { windows.main = null }) } - -module.exports = windows diff --git a/renderer/index.js b/renderer/index.js index 6b240487..6b1e1ca6 100644 --- a/renderer/index.js +++ b/renderer/index.js @@ -10,18 +10,18 @@ var dragDrop = require('drag-drop') var electron = require('electron') var EventEmitter = require('events') var fs = require('fs') -var ipcRenderer = electron.ipcRenderer var mainLoop = require('main-loop') var networkAddress = require('network-address') var path = require('path') var torrentPoster = require('./lib/torrent-poster') var WebTorrent = require('webtorrent') +var App = require('./views/app') var createElement = require('virtual-dom/create-element') var diff = require('virtual-dom/diff') var patch = require('virtual-dom/patch') -var App = require('./views/app') +var ipcRenderer = electron.ipcRenderer // For easy debugging in Developer Tools var state = global.state = require('./state') From 0cca67a4369af69c9453b8fa7b43b5dda6db3d18 Mon Sep 17 00:00:00 2001 From: Feross Aboukhadijeh Date: Mon, 7 Mar 2016 21:46:17 -0800 Subject: [PATCH 5/6] fix fullscreen on Windows The win.isFullScreen() state takes a second to update so we should just pass the state manually into onToggleFullScreen(). --- main/ipc.js | 7 ++++--- main/menu.js | 29 +++++++++++++++++------------ main/windows.js | 4 ++-- renderer/index.js | 4 ++-- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/main/ipc.js b/main/ipc.js index ea476b06..29bc4ca8 100644 --- a/main/ipc.js +++ b/main/ipc.js @@ -2,9 +2,10 @@ module.exports = { init: init } -var electron = require('electron') var debug = require('debug')('webtorrent-app:ipcMain') +var electron = require('electron') var ipcMain = electron.ipcMain +var menu = require('./menu') var windows = require('./windows') function init () { @@ -28,8 +29,8 @@ function init () { setProgress(progress) }) - ipcMain.on('toggleFullScreen', function (e) { - windows.main.setFullScreen(!windows.main.isFullScreen()) + ipcMain.on('toggleFullScreen', function (e, flag) { + menu.toggleFullScreen(flag) }) ipcMain.on('setTitle', function (e, title) { diff --git a/main/menu.js b/main/menu.js index 73b55f5c..47a2fdf9 100644 --- a/main/menu.js +++ b/main/menu.js @@ -5,19 +5,21 @@ var windows = require('./windows') var app = electron.app -function toggleFullScreen () { - debug('toggleFullScreen') +function toggleFullScreen (flag) { + debug('toggleFullScreen %s', flag) if (windows.main && windows.main.isVisible()) { - windows.main.setFullScreen(!windows.main.isFullScreen()) + flag = flag != null ? flag : !windows.main.isFullScreen() + windows.main.setFullScreen(flag) } } // Sets whether the window should always show on top of other windows -function toggleFloatOnTop () { - debug('toggleFloatOnTop %s') +function toggleFloatOnTop (flag) { + debug('toggleFloatOnTop %s', flag) if (windows.main) { - windows.main.setAlwaysOnTop(!windows.main.isAlwaysOnTop()) - getMenuItem('Float on Top').checked = windows.main.isAlwaysOnTop() + flag = flag != null ? flag : !windows.main.isAlwaysOnTop() + windows.main.setAlwaysOnTop(flag) + getMenuItem('Float on Top').checked = flag } } @@ -37,6 +39,7 @@ function reloadWindow () { } function addFakeDevice (device) { + debug('addFakeDevice %s', device) windows.main.send('addFakeDevice', device) } @@ -53,9 +56,11 @@ function onWindowHide () { } function onToggleFullScreen () { - windows.main.setMenuBarVisibility(!windows.main.isFullScreen()) - getMenuItem('Full Screen').checked = windows.main.isFullScreen() - windows.main.send('fullscreenChanged', windows.main.isFullScreen()) +function onToggleFullScreen (isFullScreen) { + isFullScreen = isFullScreen != null ? isFullScreen : windows.main.isFullScreen() + windows.main.setMenuBarVisibility(!isFullScreen) + getMenuItem('Full Screen').checked = isFullScreen + windows.main.send('fullscreenChanged', isFullScreen) } function getMenuItem (label) { @@ -150,12 +155,12 @@ function getMenuTemplate () { if (process.platform === 'darwin') return 'Ctrl+Command+F' else return 'F11' })(), - click: toggleFullScreen + click: () => toggleFullScreen() }, { label: 'Float on Top', type: 'checkbox', - click: toggleFloatOnTop + click: () => toggleFloatOnTop() }, { type: 'separator' diff --git a/main/windows.js b/main/windows.js index 2d65065d..ecdc2c2f 100644 --- a/main/windows.js +++ b/main/windows.js @@ -42,8 +42,8 @@ function createMainWindow (menu) { win.on('blur', menu.onWindowHide) win.on('focus', menu.onWindowShow) - win.on('enter-full-screen', menu.onToggleFullScreen) - win.on('leave-full-screen', menu.onToggleFullScreen) + win.on('enter-full-screen', () => menu.onToggleFullScreen(true)) + win.on('leave-full-screen', () => menu.onToggleFullScreen(false)) win.on('close', function (e) { if (process.platform === 'darwin' && !isQuitting) { diff --git a/renderer/index.js b/renderer/index.js index 6b1e1ca6..84045280 100644 --- a/renderer/index.js +++ b/renderer/index.js @@ -193,7 +193,7 @@ function dispatch (action, ...args) { update() } if (action === 'toggleFullScreen') { - ipcRenderer.send('toggleFullScreen') + ipcRenderer.send('toggleFullScreen', args[0]) update() } if (action === 'videoMouseMoved') { @@ -448,7 +448,7 @@ function closePlayer () { update() if (state.isFullScreen) { - ipcRenderer.send('toggleFullScreen') + dispatch('toggleFullScreen', false) } restoreBounds() stopServer() From 81476a3954644341ca196e325073671a1891d19b Mon Sep 17 00:00:00 2001 From: Feross Aboukhadijeh Date: Mon, 7 Mar 2016 22:33:23 -0800 Subject: [PATCH 6/6] fix bad merge --- main/menu.js | 1 - 1 file changed, 1 deletion(-) diff --git a/main/menu.js b/main/menu.js index 47a2fdf9..3507bcc5 100644 --- a/main/menu.js +++ b/main/menu.js @@ -55,7 +55,6 @@ function onWindowHide () { getMenuItem('Float on Top').enabled = false } -function onToggleFullScreen () { function onToggleFullScreen (isFullScreen) { isFullScreen = isFullScreen != null ? isFullScreen : windows.main.isFullScreen() windows.main.setMenuBarVisibility(!isFullScreen)