Implement back/forward buttons (fix #180)
This commit is contained in:
@@ -17,10 +17,10 @@ var diff = require('virtual-dom/diff')
|
||||
var patch = require('virtual-dom/patch')
|
||||
|
||||
var App = require('./views/app')
|
||||
var config = require('../config')
|
||||
var torrentPoster = require('./lib/torrent-poster')
|
||||
var TorrentPlayer = require('./lib/torrent-player')
|
||||
var Cast = require('./lib/cast')
|
||||
var config = require('../config')
|
||||
var TorrentPlayer = require('./lib/torrent-player')
|
||||
var torrentPoster = require('./lib/torrent-poster')
|
||||
|
||||
// Electron apps have two processes: a main process (node) runs first and starts
|
||||
// a renderer process (essentially a Chrome window). We're in the renderer process,
|
||||
@@ -48,6 +48,8 @@ loadState(init)
|
||||
* the dock icon and drag+drop.
|
||||
*/
|
||||
function init () {
|
||||
state.location.go({ url: 'home' })
|
||||
|
||||
// Connect to the WebTorrent and BitTorrent networks
|
||||
// WebTorrent.app is a hybrid client, as explained here: https://webtorrent.io/faq
|
||||
state.client = new WebTorrent()
|
||||
@@ -158,7 +160,7 @@ function updateElectron () {
|
||||
|
||||
// Events from the UI never modify state directly. Instead they call dispatch()
|
||||
function dispatch (action, ...args) {
|
||||
if (['videoMouseMoved', 'playbackJump'].indexOf(action) < 0) {
|
||||
if (['videoMouseMoved', 'playbackJump'].indexOf(action) === -1) {
|
||||
console.log('dispatch: %s %o', action, args) /* log user interactions, but don't spam */
|
||||
}
|
||||
if (action === 'onOpen') {
|
||||
@@ -174,8 +176,14 @@ function dispatch (action, ...args) {
|
||||
seed(args[0] /* files */)
|
||||
}
|
||||
if (action === 'play') {
|
||||
// TODO: handle audio. video only for now.
|
||||
openPlayer(args[0] /* torrentSummary */, args[1] /* index */)
|
||||
state.location.go({
|
||||
url: 'player',
|
||||
onbeforeload: function (cb) {
|
||||
// TODO: handle audio. video only for now.
|
||||
openPlayer(args[0] /* torrentSummary */, args[1] /* index */, cb)
|
||||
},
|
||||
onbeforeunload: closePlayer
|
||||
})
|
||||
}
|
||||
if (action === 'openFile') {
|
||||
openFile(args[0] /* torrentSummary */, args[1] /* index */)
|
||||
@@ -205,14 +213,12 @@ function dispatch (action, ...args) {
|
||||
setDimensions(args[0] /* dimensions */)
|
||||
}
|
||||
if (action === 'back') {
|
||||
// TODO
|
||||
// window.history.back()
|
||||
ipcRenderer.send('unblockPowerSave')
|
||||
closePlayer()
|
||||
state.location.back()
|
||||
update()
|
||||
}
|
||||
if (action === 'forward') {
|
||||
// TODO
|
||||
// window.history.forward()
|
||||
state.location.forward()
|
||||
update()
|
||||
}
|
||||
if (action === 'playPause') {
|
||||
playPause()
|
||||
@@ -567,7 +573,7 @@ function stopServer () {
|
||||
}
|
||||
|
||||
// Opens the video player
|
||||
function openPlayer (torrentSummary, index) {
|
||||
function openPlayer (torrentSummary, index, cb) {
|
||||
var torrent = state.client.get(torrentSummary.infoHash)
|
||||
if (!torrent || !torrent.done) playInterfaceSound(config.SOUND_PLAY)
|
||||
torrentSummary.playStatus = 'requested'
|
||||
@@ -589,9 +595,9 @@ function openPlayer (torrentSummary, index) {
|
||||
if (timedOut) return
|
||||
|
||||
// otherwise, play the video
|
||||
state.url = 'player'
|
||||
state.window.title = torrentSummary.name
|
||||
update()
|
||||
cb()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -618,18 +624,20 @@ function openFolder (torrentSummary) {
|
||||
})
|
||||
}
|
||||
|
||||
function closePlayer () {
|
||||
state.url = 'home'
|
||||
function closePlayer (cb) {
|
||||
state.window.title = config.APP_NAME
|
||||
update()
|
||||
|
||||
if (state.window.isFullScreen) {
|
||||
dispatch('toggleFullScreen', false)
|
||||
}
|
||||
|
||||
restoreBounds()
|
||||
stopServer()
|
||||
update()
|
||||
|
||||
ipcRenderer.send('unblockPowerSave')
|
||||
|
||||
cb()
|
||||
}
|
||||
|
||||
function toggleTorrent (torrentSummary) {
|
||||
@@ -652,6 +660,7 @@ function deleteTorrent (torrentSummary) {
|
||||
var index = state.saved.torrents.findIndex((x) => x.infoHash === infoHash)
|
||||
if (index > -1) state.saved.torrents.splice(index, 1)
|
||||
saveState()
|
||||
state.location.clearForward() // prevent user from going forward to a deleted torrent
|
||||
playInterfaceSound(config.SOUND_DELETE)
|
||||
}
|
||||
|
||||
|
||||
61
renderer/lib/location-history.js
Normal file
61
renderer/lib/location-history.js
Normal file
@@ -0,0 +1,61 @@
|
||||
module.exports = LocationHistory
|
||||
|
||||
function LocationHistory () {
|
||||
if (!new.target) return new LocationHistory()
|
||||
this._history = []
|
||||
this._forward = []
|
||||
}
|
||||
|
||||
LocationHistory.prototype.go = function (page) {
|
||||
console.log('go', page)
|
||||
this.clearForward()
|
||||
this._go(page)
|
||||
}
|
||||
|
||||
LocationHistory.prototype._go = function (page) {
|
||||
if (page.onbeforeload) {
|
||||
page.onbeforeload((err) => {
|
||||
if (err) return
|
||||
this._history.push(page)
|
||||
})
|
||||
} else {
|
||||
this._history.push(page)
|
||||
}
|
||||
}
|
||||
|
||||
LocationHistory.prototype.back = function () {
|
||||
if (this._history.length <= 1) return
|
||||
|
||||
var page = this._history.pop()
|
||||
|
||||
if (page.onbeforeunload) {
|
||||
page.onbeforeunload(() => {
|
||||
this._forward.push(page)
|
||||
})
|
||||
} else {
|
||||
this._forward.push(page)
|
||||
}
|
||||
}
|
||||
|
||||
LocationHistory.prototype.forward = function () {
|
||||
if (this._forward.length === 0) return
|
||||
|
||||
var page = this._forward.pop()
|
||||
this._go(page)
|
||||
}
|
||||
|
||||
LocationHistory.prototype.clearForward = function () {
|
||||
this._forward = []
|
||||
}
|
||||
|
||||
LocationHistory.prototype.current = function () {
|
||||
return this._history[this._history.length - 1]
|
||||
}
|
||||
|
||||
LocationHistory.prototype.hasBack = function () {
|
||||
return this._history.length > 1
|
||||
}
|
||||
|
||||
LocationHistory.prototype.hasForward = function () {
|
||||
return this._forward.length > 0
|
||||
}
|
||||
@@ -2,6 +2,7 @@ var os = require('os')
|
||||
var path = require('path')
|
||||
|
||||
var config = require('../config')
|
||||
var LocationHistory = require('./lib/location-history')
|
||||
|
||||
module.exports = {
|
||||
/*
|
||||
@@ -11,9 +12,9 @@ module.exports = {
|
||||
client: null, /* the WebTorrent client */
|
||||
server: null, /* local WebTorrent-to-HTTP server */
|
||||
prev: {}, /* used for state diffing in updateElectron() */
|
||||
url: 'home',
|
||||
location: new LocationHistory(),
|
||||
window: {
|
||||
bounds: null, /* x y width height */
|
||||
bounds: null, /* {x, y, width, height } */
|
||||
isFocused: true,
|
||||
isFullScreen: false,
|
||||
title: config.APP_NAME /* current window title */
|
||||
|
||||
@@ -17,7 +17,7 @@ function App (state, dispatch) {
|
||||
// * The mouse is over the controls or we're scrubbing (see CSS)
|
||||
// * The video is paused
|
||||
// * The video is playing remotely on Chromecast or Airplay
|
||||
var hideControls = state.url === 'player' &&
|
||||
var hideControls = state.location.current().url === 'player' &&
|
||||
state.video.mouseStationarySince !== 0 &&
|
||||
new Date().getTime() - state.video.mouseStationarySince > 2000 &&
|
||||
!state.video.isPaused &&
|
||||
@@ -25,10 +25,10 @@ function App (state, dispatch) {
|
||||
|
||||
// Hide the header on Windows/Linux when in the player
|
||||
// On OSX, the header appears as part of the title bar
|
||||
var hideHeader = process.platform !== 'darwin' && state.url === 'player'
|
||||
var hideHeader = process.platform !== 'darwin' && state.location.current().url === 'player'
|
||||
|
||||
var cls = [
|
||||
'view-' + state.url, /* e.g. view-home, view-player */
|
||||
'view-' + state.location.current().url, /* e.g. view-home, view-player */
|
||||
'is-' + process.platform /* e.g. is-darwin, is-win32, is-linux */
|
||||
]
|
||||
if (state.window.isFullScreen) cls.push('is-fullscreen')
|
||||
@@ -75,9 +75,9 @@ function App (state, dispatch) {
|
||||
}
|
||||
|
||||
function getView () {
|
||||
if (state.url === 'home') {
|
||||
if (state.location.current().url === 'home') {
|
||||
return TorrentList(state, dispatch)
|
||||
} else if (state.url === 'player') {
|
||||
} else if (state.location.current().url === 'player') {
|
||||
return Player(state, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,14 +9,14 @@ function Header (state, dispatch) {
|
||||
<div class='header'>
|
||||
${getTitle()}
|
||||
<div class='nav left'>
|
||||
<i
|
||||
class='icon back'
|
||||
<i.icon.back
|
||||
class=${state.location.hasBack() ? '' : 'disabled'}
|
||||
title='back'
|
||||
onclick=${() => dispatch('back')}>
|
||||
chevron_left
|
||||
</i>
|
||||
<i
|
||||
class='icon forward'
|
||||
<i.icon.forward
|
||||
class=${state.location.hasForward() ? '' : 'disabled'}
|
||||
title='forward'
|
||||
onclick=${() => dispatch('forward')}>
|
||||
chevron_right
|
||||
@@ -35,7 +35,7 @@ function Header (state, dispatch) {
|
||||
}
|
||||
|
||||
function getAddButton () {
|
||||
if (state.url !== 'player') {
|
||||
if (state.location.current().url !== 'player') {
|
||||
return hx`
|
||||
<i
|
||||
class='icon add'
|
||||
|
||||
Reference in New Issue
Block a user