Merge pull request #543 from feross/on-open
Improve open behavior; Fix bugs in LocationHistory
This commit is contained in:
@@ -87,7 +87,7 @@ function init () {
|
|||||||
|
|
||||||
// OS integrations:
|
// OS integrations:
|
||||||
// ...drag and drop a torrent or video file to play or seed
|
// ...drag and drop a torrent or video file to play or seed
|
||||||
dragDrop('body', onDrag)
|
dragDrop('body', onOpen)
|
||||||
|
|
||||||
// ...same thing if you paste a torrent
|
// ...same thing if you paste a torrent
|
||||||
document.addEventListener('paste', onPaste)
|
document.addEventListener('paste', onPaste)
|
||||||
@@ -213,7 +213,6 @@ function dispatch (action, ...args) {
|
|||||||
onOpen(args[0] /* files */)
|
onOpen(args[0] /* files */)
|
||||||
}
|
}
|
||||||
if (action === 'addTorrent') {
|
if (action === 'addTorrent') {
|
||||||
backToList()
|
|
||||||
addTorrent(args[0] /* torrent */)
|
addTorrent(args[0] /* torrent */)
|
||||||
}
|
}
|
||||||
if (action === 'showOpenTorrentFile') {
|
if (action === 'showOpenTorrentFile') {
|
||||||
@@ -274,15 +273,14 @@ function dispatch (action, ...args) {
|
|||||||
playPause()
|
playPause()
|
||||||
}
|
}
|
||||||
if (action === 'play') {
|
if (action === 'play') {
|
||||||
if (state.location.pending()) return
|
|
||||||
state.location.go({
|
state.location.go({
|
||||||
url: 'player',
|
url: 'player',
|
||||||
onbeforeload: function (cb) {
|
onbeforeload: function (cb) {
|
||||||
|
play()
|
||||||
openPlayer(args[0] /* infoHash */, args[1] /* index */, cb)
|
openPlayer(args[0] /* infoHash */, args[1] /* index */, cb)
|
||||||
},
|
},
|
||||||
onbeforeunload: closePlayer
|
onbeforeunload: closePlayer
|
||||||
})
|
})
|
||||||
play()
|
|
||||||
}
|
}
|
||||||
if (action === 'playbackJump') {
|
if (action === 'playbackJump') {
|
||||||
jumpToTime(args[0] /* seconds */)
|
jumpToTime(args[0] /* seconds */)
|
||||||
@@ -306,7 +304,7 @@ function dispatch (action, ...args) {
|
|||||||
state.playing.isStalled = true
|
state.playing.isStalled = true
|
||||||
}
|
}
|
||||||
if (action === 'mediaError') {
|
if (action === 'mediaError') {
|
||||||
if (state.location.current().url === 'player') {
|
if (state.location.url() === 'player') {
|
||||||
state.playing.location = 'error'
|
state.playing.location = 'error'
|
||||||
ipcRenderer.send('checkForVLC')
|
ipcRenderer.send('checkForVLC')
|
||||||
ipcRenderer.once('checkForVLC', function (e, isInstalled) {
|
ipcRenderer.once('checkForVLC', function (e, isInstalled) {
|
||||||
@@ -386,7 +384,7 @@ function pause () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function playPause () {
|
function playPause () {
|
||||||
if (state.location.current().url !== 'player') return
|
if (state.location.url() !== 'player') return
|
||||||
if (state.playing.isPaused) {
|
if (state.playing.isPaused) {
|
||||||
play()
|
play()
|
||||||
} else {
|
} else {
|
||||||
@@ -432,18 +430,18 @@ function openSubtitles () {
|
|||||||
function backToList () {
|
function backToList () {
|
||||||
// Exit any modals and screens with a back button
|
// Exit any modals and screens with a back button
|
||||||
state.modal = null
|
state.modal = null
|
||||||
while (state.location.hasBack()) state.location.back()
|
state.location.backToFirst(function () {
|
||||||
|
// If we were already on the torrent list, scroll to the top
|
||||||
|
var contentTag = document.querySelector('.content')
|
||||||
|
if (contentTag) contentTag.scrollTop = 0
|
||||||
|
|
||||||
// If we were already on the torrent list, scroll to the top
|
// Work around virtual-dom issue: it doesn't expose its redraw function,
|
||||||
var contentTag = document.querySelector('.content')
|
// and only redraws on requestAnimationFrame(). That means when the user
|
||||||
if (contentTag) contentTag.scrollTop = 0
|
// closes the window (hide window / minimize to tray) and we want to pause
|
||||||
|
// the video, we update the vdom but it keeps playing until you reopen!
|
||||||
// Work around virtual-dom issue: it doesn't expose its redraw function,
|
var mediaTag = document.querySelector('video,audio')
|
||||||
// and only redraws on requestAnimationFrame(). That means when the user
|
if (mediaTag) mediaTag.pause()
|
||||||
// closes the window (hide window / minimize to tray) and we want to pause
|
})
|
||||||
// the video, we update the vdom but it keeps playing until you reopen!
|
|
||||||
var mediaTag = document.querySelector('video,audio')
|
|
||||||
if (mediaTag) mediaTag.pause()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether we are connected and already casting
|
// Checks whether we are connected and already casting
|
||||||
@@ -556,41 +554,29 @@ function saveState () {
|
|||||||
update()
|
update()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when the user clicks a magnet link or torrent, or uses the Open dialog
|
// Called when the user drag-drops files onto the app
|
||||||
function onOpen (files) {
|
function onOpen (files) {
|
||||||
if (!Array.isArray(files)) files = [ files ]
|
if (!Array.isArray(files)) files = [ files ]
|
||||||
|
|
||||||
// Return to the home screen
|
if (state.modal) {
|
||||||
backToList()
|
state.modal = null
|
||||||
|
|
||||||
if (files.every(isTorrent)) {
|
|
||||||
// All .torrent files? Start downloading
|
|
||||||
files.forEach(addTorrent)
|
|
||||||
} else {
|
|
||||||
// Show the Create Torrent screen. Let's seed those files.
|
|
||||||
showCreateTorrent(files)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Called when the user drag-drops files onto the app
|
var subtitles = files.filter(isSubtitle)
|
||||||
function onDrag (files) {
|
|
||||||
if (!Array.isArray(files)) files = [ files ]
|
|
||||||
|
|
||||||
var isInPlayer = state.location.current().url === 'player'
|
if (state.location.url() === 'home' || subtitles.length === 0) {
|
||||||
var isHome = state.location.current().url === 'home' && !state.modal
|
|
||||||
|
|
||||||
if (isInPlayer) {
|
|
||||||
// In the player, the only drag-drop function is adding subtitles
|
|
||||||
addSubtitles(files.filter(isSubtitle), true)
|
|
||||||
} else if (isHome) {
|
|
||||||
// Otherwise, you can only drag-drop onto the home screen
|
|
||||||
if (files.every(isTorrent)) {
|
if (files.every(isTorrent)) {
|
||||||
// All .torrent files? Start downloading
|
if (state.location.url() !== 'home') {
|
||||||
|
backToList()
|
||||||
|
}
|
||||||
|
// All .torrent files? Add them.
|
||||||
files.forEach(addTorrent)
|
files.forEach(addTorrent)
|
||||||
} else {
|
} else {
|
||||||
// Show the Create Torrent screen. Let's seed those files.
|
// Show the Create Torrent screen. Let's seed those files.
|
||||||
showCreateTorrent(files)
|
showCreateTorrent(files)
|
||||||
}
|
}
|
||||||
|
} else if (state.location.url() === 'player') {
|
||||||
|
addSubtitles(subtitles, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
update()
|
update()
|
||||||
@@ -620,6 +606,7 @@ function getTorrentSummary (torrentKey) {
|
|||||||
// Adds a torrent to the list, starts downloading/seeding. TorrentID can be a
|
// Adds a torrent to the list, starts downloading/seeding. TorrentID can be a
|
||||||
// magnet URI, infohash, or torrent file: https://github.com/feross/webtorrent#clientaddtorrentid-opts-function-ontorrent-torrent-
|
// magnet URI, infohash, or torrent file: https://github.com/feross/webtorrent#clientaddtorrentid-opts-function-ontorrent-torrent-
|
||||||
function addTorrent (torrentId) {
|
function addTorrent (torrentId) {
|
||||||
|
backToList()
|
||||||
var torrentKey = state.nextTorrentKey++
|
var torrentKey = state.nextTorrentKey++
|
||||||
var path = state.saved.downloadPath
|
var path = state.saved.downloadPath
|
||||||
if (torrentId.path) {
|
if (torrentId.path) {
|
||||||
@@ -762,7 +749,6 @@ function startTorrentingSummary (torrentSummary) {
|
|||||||
// Shows the Create Torrent page with options to seed a given file or folder
|
// Shows the Create Torrent page with options to seed a given file or folder
|
||||||
function showCreateTorrent (files) {
|
function showCreateTorrent (files) {
|
||||||
if (Array.isArray(files)) {
|
if (Array.isArray(files)) {
|
||||||
if (state.location.pending() || state.location.current().url !== 'home') return
|
|
||||||
state.location.go({
|
state.location.go({
|
||||||
url: 'create-torrent',
|
url: 'create-torrent',
|
||||||
files: files
|
files: files
|
||||||
@@ -812,6 +798,9 @@ function findFilesRecursive (fileOrFolder, cb) {
|
|||||||
function createTorrent (options) {
|
function createTorrent (options) {
|
||||||
var torrentKey = state.nextTorrentKey++
|
var torrentKey = state.nextTorrentKey++
|
||||||
ipcRenderer.send('wt-create-torrent', torrentKey, options)
|
ipcRenderer.send('wt-create-torrent', torrentKey, options)
|
||||||
|
state.location.backToFirst(function () {
|
||||||
|
state.location.clearForward('create-torrent')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function torrentInfoHash (torrentKey, infoHash) {
|
function torrentInfoHash (torrentKey, infoHash) {
|
||||||
@@ -1093,7 +1082,7 @@ function deleteTorrent (infoHash) {
|
|||||||
var index = state.saved.torrents.findIndex((x) => x.infoHash === infoHash)
|
var index = state.saved.torrents.findIndex((x) => x.infoHash === infoHash)
|
||||||
if (index > -1) state.saved.torrents.splice(index, 1)
|
if (index > -1) state.saved.torrents.splice(index, 1)
|
||||||
saveStateThrottled()
|
saveStateThrottled()
|
||||||
state.location.clearForward() // prevent user from going forward to a deleted torrent
|
state.location.clearForward('player') // prevent user from going forward to a deleted torrent
|
||||||
sound.play('DELETE')
|
sound.play('DELETE')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1241,7 +1230,7 @@ function showDoneNotification (torrent) {
|
|||||||
// * The video is paused
|
// * The video is paused
|
||||||
// * The video is playing remotely on Chromecast or Airplay
|
// * The video is playing remotely on Chromecast or Airplay
|
||||||
function showOrHidePlayerControls () {
|
function showOrHidePlayerControls () {
|
||||||
var hideControls = state.location.current().url === 'player' &&
|
var hideControls = state.location.url() === 'player' &&
|
||||||
state.playing.mouseStationarySince !== 0 &&
|
state.playing.mouseStationarySince !== 0 &&
|
||||||
new Date().getTime() - state.playing.mouseStationarySince > 2000 &&
|
new Date().getTime() - state.playing.mouseStationarySince > 2000 &&
|
||||||
!state.playing.isPaused &&
|
!state.playing.isPaused &&
|
||||||
|
|||||||
@@ -4,81 +4,123 @@ function LocationHistory () {
|
|||||||
if (!new.target) return new LocationHistory()
|
if (!new.target) return new LocationHistory()
|
||||||
this._history = []
|
this._history = []
|
||||||
this._forward = []
|
this._forward = []
|
||||||
this._pending = null
|
this._pending = false
|
||||||
}
|
}
|
||||||
|
|
||||||
LocationHistory.prototype.go = function (page, cb) {
|
LocationHistory.prototype.url = function () {
|
||||||
console.log('go', page)
|
return this.current() && this.current().url
|
||||||
this.clearForward()
|
|
||||||
this._go(page, cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
LocationHistory.prototype._go = function (page, cb) {
|
|
||||||
if (this._pending) return
|
|
||||||
if (page.onbeforeload) {
|
|
||||||
this._pending = page
|
|
||||||
page.onbeforeload((err) => {
|
|
||||||
if (this._pending !== page) return /* navigation was cancelled */
|
|
||||||
this._pending = null
|
|
||||||
if (err) {
|
|
||||||
if (cb) cb(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this._history.push(page)
|
|
||||||
if (cb) cb()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this._history.push(page)
|
|
||||||
if (cb) cb()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LocationHistory.prototype.back = function (cb) {
|
|
||||||
if (this._history.length <= 1) return
|
|
||||||
|
|
||||||
var page = this._history.pop()
|
|
||||||
|
|
||||||
if (page.onbeforeunload) {
|
|
||||||
// TODO: this is buggy. If the user clicks back twice, then those pages
|
|
||||||
// may end up in _forward in the wrong order depending on which onbeforeunload
|
|
||||||
// call finishes first.
|
|
||||||
page.onbeforeunload(() => {
|
|
||||||
this._forward.push(page)
|
|
||||||
if (cb) cb()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this._forward.push(page)
|
|
||||||
if (cb) cb()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LocationHistory.prototype.forward = function (cb) {
|
|
||||||
if (this._forward.length === 0) return
|
|
||||||
|
|
||||||
var page = this._forward.pop()
|
|
||||||
this._go(page, cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
LocationHistory.prototype.clearForward = function () {
|
|
||||||
this._forward = []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LocationHistory.prototype.current = function () {
|
LocationHistory.prototype.current = function () {
|
||||||
return this._history[this._history.length - 1]
|
return this._history[this._history.length - 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LocationHistory.prototype.go = function (page, cb) {
|
||||||
|
if (!cb) cb = noop
|
||||||
|
if (this._pending) return cb(null)
|
||||||
|
|
||||||
|
console.log('go', page)
|
||||||
|
|
||||||
|
this.clearForward()
|
||||||
|
this._go(page, cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
LocationHistory.prototype.back = function (cb) {
|
||||||
|
var self = this
|
||||||
|
if (!cb) cb = noop
|
||||||
|
if (self._history.length <= 1 || self._pending) return cb(null)
|
||||||
|
|
||||||
|
var page = self._history.pop()
|
||||||
|
self._unload(page, done)
|
||||||
|
|
||||||
|
function done (err) {
|
||||||
|
if (err) return cb(err)
|
||||||
|
self._forward.push(page)
|
||||||
|
self._load(self.current(), cb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LocationHistory.prototype.hasBack = function () {
|
LocationHistory.prototype.hasBack = function () {
|
||||||
return this._history.length > 1
|
return this._history.length > 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LocationHistory.prototype.forward = function (cb) {
|
||||||
|
if (!cb) cb = noop
|
||||||
|
if (this._forward.length === 0 || this._pending) return cb(null)
|
||||||
|
|
||||||
|
var page = this._forward.pop()
|
||||||
|
this._go(page, cb)
|
||||||
|
}
|
||||||
|
|
||||||
LocationHistory.prototype.hasForward = function () {
|
LocationHistory.prototype.hasForward = function () {
|
||||||
return this._forward.length > 0
|
return this._forward.length > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
LocationHistory.prototype.pending = function () {
|
LocationHistory.prototype.clearForward = function (url) {
|
||||||
return this._pending
|
if (url == null) {
|
||||||
|
this._forward = []
|
||||||
|
} else {
|
||||||
|
console.log(this._forward)
|
||||||
|
console.log(url)
|
||||||
|
this._forward = this._forward.filter(function (page) {
|
||||||
|
return page.url !== url
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LocationHistory.prototype.clearPending = function () {
|
LocationHistory.prototype.backToFirst = function (cb) {
|
||||||
this._pending = null
|
var self = this
|
||||||
|
if (!cb) cb = noop
|
||||||
|
if (self._history.length <= 1) return cb(null)
|
||||||
|
|
||||||
|
self.back(function (err) {
|
||||||
|
if (err) return cb(err)
|
||||||
|
self.backToFirst(cb)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LocationHistory.prototype._go = function (page, cb) {
|
||||||
|
var self = this
|
||||||
|
if (!cb) cb = noop
|
||||||
|
|
||||||
|
self._unload(self.current(), done1)
|
||||||
|
|
||||||
|
function done1 (err) {
|
||||||
|
if (err) return cb(err)
|
||||||
|
self._load(page, done2)
|
||||||
|
}
|
||||||
|
|
||||||
|
function done2 (err) {
|
||||||
|
if (err) return cb(err)
|
||||||
|
self._history.push(page)
|
||||||
|
cb(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LocationHistory.prototype._load = function (page, cb) {
|
||||||
|
var self = this
|
||||||
|
self._pending = true
|
||||||
|
|
||||||
|
if (page && page.onbeforeload) page.onbeforeload(done)
|
||||||
|
else done(null)
|
||||||
|
|
||||||
|
function done (err) {
|
||||||
|
self._pending = false
|
||||||
|
cb(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LocationHistory.prototype._unload = function (page, cb) {
|
||||||
|
var self = this
|
||||||
|
self._pending = true
|
||||||
|
|
||||||
|
if (page && page.onbeforeunload) page.onbeforeunload(done)
|
||||||
|
else done(null)
|
||||||
|
|
||||||
|
function done (err) {
|
||||||
|
self._pending = false
|
||||||
|
cb(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function noop () {}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ function App (state) {
|
|||||||
// * The mouse is over the controls or we're scrubbing (see CSS)
|
// * The mouse is over the controls or we're scrubbing (see CSS)
|
||||||
// * The video is paused
|
// * The video is paused
|
||||||
// * The video is playing remotely on Chromecast or Airplay
|
// * The video is playing remotely on Chromecast or Airplay
|
||||||
var hideControls = state.location.current().url === 'player' &&
|
var hideControls = state.location.url() === 'player' &&
|
||||||
state.playing.mouseStationarySince !== 0 &&
|
state.playing.mouseStationarySince !== 0 &&
|
||||||
new Date().getTime() - state.playing.mouseStationarySince > 2000 &&
|
new Date().getTime() - state.playing.mouseStationarySince > 2000 &&
|
||||||
!state.playing.isPaused &&
|
!state.playing.isPaused &&
|
||||||
@@ -30,10 +30,10 @@ function App (state) {
|
|||||||
|
|
||||||
// Hide the header on Windows/Linux when in the player
|
// Hide the header on Windows/Linux when in the player
|
||||||
// On OSX, the header appears as part of the title bar
|
// On OSX, the header appears as part of the title bar
|
||||||
var hideHeader = process.platform !== 'darwin' && state.location.current().url === 'player'
|
var hideHeader = process.platform !== 'darwin' && state.location.url() === 'player'
|
||||||
|
|
||||||
var cls = [
|
var cls = [
|
||||||
'view-' + state.location.current().url, /* e.g. view-home, view-player */
|
'view-' + state.location.url(), /* e.g. view-home, view-player */
|
||||||
'is-' + process.platform /* e.g. is-darwin, is-win32, is-linux */
|
'is-' + process.platform /* e.g. is-darwin, is-win32, is-linux */
|
||||||
]
|
]
|
||||||
if (state.window.isFullScreen) cls.push('is-fullscreen')
|
if (state.window.isFullScreen) cls.push('is-fullscreen')
|
||||||
@@ -81,6 +81,6 @@ function getModal (state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getView (state) {
|
function getView (state) {
|
||||||
var url = state.location.current().url
|
var url = state.location.url()
|
||||||
return Views[url](state)
|
return Views[url](state)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,11 +119,10 @@ function CreateTorrentPage (state) {
|
|||||||
comment: comment
|
comment: comment
|
||||||
}
|
}
|
||||||
dispatch('createTorrent', options)
|
dispatch('createTorrent', options)
|
||||||
dispatch('backToList')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCancel () {
|
function handleCancel () {
|
||||||
dispatch('backToList')
|
dispatch('back')
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleToggleShowAdvanced () {
|
function handleToggleShowAdvanced () {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ function Header (state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getAddButton () {
|
function getAddButton () {
|
||||||
if (state.location.current().url !== 'player') {
|
if (state.location.url() !== 'player') {
|
||||||
return hx`
|
return hx`
|
||||||
<i
|
<i
|
||||||
class='icon add'
|
class='icon add'
|
||||||
|
|||||||
Reference in New Issue
Block a user