React: fix warnings
This commit is contained in:
@@ -83,7 +83,7 @@
|
|||||||
"clean": "node ./bin/clean.js",
|
"clean": "node ./bin/clean.js",
|
||||||
"open-config": "node ./bin/open-config.js",
|
"open-config": "node ./bin/open-config.js",
|
||||||
"package": "node ./bin/package.js",
|
"package": "node ./bin/package.js",
|
||||||
"start": "electron .",
|
"start": "jsx --es6module src/ build/ && electron .",
|
||||||
"test": "standard && node ./bin/check-deps.js",
|
"test": "standard && node ./bin/check-deps.js",
|
||||||
"update-authors": "./bin/update-authors.sh"
|
"update-authors": "./bin/update-authors.sh"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ function getDefaultPlayState () {
|
|||||||
lastTimeUpdate: 0, /* Unix time in ms */
|
lastTimeUpdate: 0, /* Unix time in ms */
|
||||||
mouseStationarySince: 0, /* Unix time in ms */
|
mouseStationarySince: 0, /* Unix time in ms */
|
||||||
playbackRate: 1,
|
playbackRate: 1,
|
||||||
|
volume: 1,
|
||||||
subtitles: {
|
subtitles: {
|
||||||
tracks: [], /* subtitle tracks, each {label, language, ...} */
|
tracks: [], /* subtitle tracks, each {label, language, ...} */
|
||||||
selectedIndex: -1, /* current subtitle track */
|
selectedIndex: -1, /* current subtitle track */
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ function onState (err, _state) {
|
|||||||
// a progress bar and to keep the cursor in sync when playing a video
|
// a progress bar and to keep the cursor in sync when playing a video
|
||||||
setInterval(update, 1000)
|
setInterval(update, 1000)
|
||||||
window.requestAnimationFrame(renderIfNecessary)
|
window.requestAnimationFrame(renderIfNecessary)
|
||||||
app = ReactDOM.render(<App state={state} />, document.querySelector('body'))
|
app = ReactDOM.render(<App state={state} />, document.querySelector('#body'))
|
||||||
|
|
||||||
// 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
|
||||||
@@ -240,8 +240,8 @@ const dispatchHandlers = {
|
|||||||
|
|
||||||
// Events from the UI never modify state directly. Instead they call dispatch()
|
// Events from the UI never modify state directly. Instead they call dispatch()
|
||||||
function dispatch (action, ...args) {
|
function dispatch (action, ...args) {
|
||||||
// Log dispatch calls, for debugging
|
// Log dispatch calls, for debugging, but don't spam
|
||||||
if (!['mediaMouseMoved', 'mediaTimeUpdate'].includes(action)) {
|
if (!['mediaMouseMoved', 'mediaTimeUpdate', 'update'].includes(action)) {
|
||||||
console.log('dispatch: %s %o', action, args)
|
console.log('dispatch: %s %o', action, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ module.exports = class App extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
console.time('render app')
|
|
||||||
var state = this.state
|
var state = this.state
|
||||||
|
|
||||||
// Hide player controls while playing video, if the mouse stays still for a while
|
// Hide player controls while playing video, if the mouse stays still for a while
|
||||||
@@ -55,7 +54,7 @@ module.exports = class App extends React.Component {
|
|||||||
{getModal(state)}
|
{getModal(state)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
console.timeEnd('render app')
|
|
||||||
return vdom
|
return vdom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/renderer/views/create-torrent-error-page.js
Normal file
26
src/renderer/views/create-torrent-error-page.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
const React = require('react')
|
||||||
|
|
||||||
|
const {dispatcher} = require('../lib/dispatcher')
|
||||||
|
|
||||||
|
module.exports = class CreateTorrentErrorPage extends React.Component {
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<div className='create-torrent'>
|
||||||
|
<h2>Create torrent</h2>
|
||||||
|
<p className='torrent-info'>
|
||||||
|
<p>
|
||||||
|
Sorry, you must select at least one file that is not a hidden file.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Hidden files, starting with a . character, are not included.
|
||||||
|
</p>
|
||||||
|
</p>
|
||||||
|
<p className='float-right'>
|
||||||
|
<button className='button-flat light' onClick={dispatcher('back')}>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -46,12 +46,12 @@ module.exports = class CreateTorrentPage extends React.Component {
|
|||||||
basePath = path.dirname(pathPrefix)
|
basePath = path.dirname(pathPrefix)
|
||||||
}
|
}
|
||||||
var maxFileElems = 100
|
var maxFileElems = 100
|
||||||
var fileElems = files.slice(0, maxFileElems).map(function (file) {
|
var fileElems = files.slice(0, maxFileElems).map(function (file, i) {
|
||||||
var relativePath = files.length === 0 ? file.name : path.relative(pathPrefix, file.path)
|
var relativePath = files.length === 0 ? file.name : path.relative(pathPrefix, file.path)
|
||||||
return (<div>{relativePath}</div>)
|
return (<div key={i}>{relativePath}</div>)
|
||||||
})
|
})
|
||||||
if (files.length > maxFileElems) {
|
if (files.length > maxFileElems) {
|
||||||
fileElems.push(<div>+ {maxFileElems - files.length} more</div>)
|
fileElems.push(<div key='more'>+ {maxFileElems - files.length} more</div>)
|
||||||
}
|
}
|
||||||
var trackers = createTorrent.announceList.join('\n')
|
var trackers = createTorrent.announceList.join('\n')
|
||||||
var collapsedClass = info.showAdvanced ? 'expanded' : 'collapsed'
|
var collapsedClass = info.showAdvanced ? 'expanded' : 'collapsed'
|
||||||
@@ -59,39 +59,39 @@ module.exports = class CreateTorrentPage extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<div className='create-torrent'>
|
<div className='create-torrent'>
|
||||||
<h2>Create torrent {defaultName}</h2>
|
<h2>Create torrent {defaultName}</h2>
|
||||||
<p className='torrent-info'>
|
<div key='info' className='torrent-info'>
|
||||||
{torrentInfo}
|
{torrentInfo}
|
||||||
</p>
|
</div>
|
||||||
<p className='torrent-attribute'>
|
<div key='path-prefix' className='torrent-attribute'>
|
||||||
<label>Path:</label>
|
<label>Path:</label>
|
||||||
<div className='torrent-attribute'>{pathPrefix}</div>
|
<div className='torrent-attribute'>{pathPrefix}</div>
|
||||||
</p>
|
</div>
|
||||||
<div className={'expand-collapse ' + collapsedClass}
|
<div key='toggle' className={'expand-collapse ' + collapsedClass}
|
||||||
onClick={dispatcher('toggleCreateTorrentAdvanced')}>
|
onClick={dispatcher('toggleCreateTorrentAdvanced')}>
|
||||||
{info.showAdvanced ? 'Basic' : 'Advanced'}
|
{info.showAdvanced ? 'Basic' : 'Advanced'}
|
||||||
</div>
|
</div>
|
||||||
<div className={'create-torrent-advanced ' + collapsedClass}>
|
<div key='advanced' className={'create-torrent-advanced ' + collapsedClass}>
|
||||||
<p className='torrent-attribute'>
|
<div key='comment' className='torrent-attribute'>
|
||||||
<label>Comment:</label>
|
<label>Comment:</label>
|
||||||
<textarea className='torrent-attribute torrent-comment'></textarea>
|
<textarea className='torrent-attribute torrent-comment'></textarea>
|
||||||
</p>
|
</div>
|
||||||
<p className='torrent-attribute'>
|
<div key='trackers' className='torrent-attribute'>
|
||||||
<label>Trackers:</label>
|
<label>Trackers:</label>
|
||||||
<textarea className='torrent-attribute torrent-trackers'>{trackers}</textarea>
|
<textarea className='torrent-attribute torrent-trackers' value={trackers}></textarea>
|
||||||
</p>
|
</div>
|
||||||
<p className='torrent-attribute'>
|
<div key='private' className='torrent-attribute'>
|
||||||
<label>Private:</label>
|
<label>Private:</label>
|
||||||
<input type='checkbox' className='torrent-is-private' value='torrent-is-private' />
|
<input type='checkbox' className='torrent-is-private' value='torrent-is-private' />
|
||||||
</p>
|
</div>
|
||||||
<p className='torrent-attribute'>
|
<div key='files' className='torrent-attribute'>
|
||||||
<label>Files:</label>
|
<label>Files:</label>
|
||||||
<div>{fileElems}</div>
|
<div>{fileElems}</div>
|
||||||
</p>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div key='buttons' className='float-right'>
|
||||||
|
<button key='cancel' className='button-flat light' onClick={dispatcher('back')}>Cancel</button>
|
||||||
|
<button key='create' className='button-raised' onClick={handleOK}>Create Torrent</button>
|
||||||
</div>
|
</div>
|
||||||
<p className='float-right'>
|
|
||||||
<button className='button-flat light' onClick={dispatcher('back')}>Cancel</button>
|
|
||||||
<button className='button-raised' onClick={handleOK}>Create Torrent</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ function renderMedia (state) {
|
|||||||
var isSelected = state.playing.subtitles.selectedIndex === i
|
var isSelected = state.playing.subtitles.selectedIndex === i
|
||||||
trackTags.push(
|
trackTags.push(
|
||||||
<track
|
<track
|
||||||
|
key={i}
|
||||||
default={isSelected ? 'default' : ''}
|
default={isSelected ? 'default' : ''}
|
||||||
label={track.label}
|
label={track.label}
|
||||||
type='subtitles'
|
type='subtitles'
|
||||||
@@ -110,7 +111,7 @@ function renderMedia (state) {
|
|||||||
onDoubleClick={dispatcher('toggleFullScreen')}
|
onDoubleClick={dispatcher('toggleFullScreen')}
|
||||||
onLoadedMetadata={onLoadedMetadata}
|
onLoadedMetadata={onLoadedMetadata}
|
||||||
onEnded={onEnded}
|
onEnded={onEnded}
|
||||||
onStalling={dispatcher('mediaStalled')}
|
onStalled={dispatcher('mediaStalled')}
|
||||||
onError={dispatcher('mediaError')}
|
onError={dispatcher('mediaError')}
|
||||||
onTimeUpdate={dispatcher('mediaTimeUpdate')}
|
onTimeUpdate={dispatcher('mediaTimeUpdate')}
|
||||||
onEncrypted={dispatcher('mediaEncrypted')}
|
onEncrypted={dispatcher('mediaEncrypted')}
|
||||||
@@ -122,6 +123,7 @@ function renderMedia (state) {
|
|||||||
// Show the media.
|
// Show the media.
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
key='letterbox'
|
||||||
className='letterbox'
|
className='letterbox'
|
||||||
onMouseMove={dispatcher('mediaMouseMoved')}>
|
onMouseMove={dispatcher('mediaMouseMoved')}>
|
||||||
{mediaTag}
|
{mediaTag}
|
||||||
@@ -179,7 +181,7 @@ function renderOverlay (state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='media-overlay-background' style={style}>
|
<div key='overlay' className='media-overlay-background' style={style}>
|
||||||
<div className='media-overlay'>{elems}</div>
|
<div className='media-overlay'>{elems}</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -209,21 +211,21 @@ function renderAudioMetadata (state) {
|
|||||||
var elems = []
|
var elems = []
|
||||||
if (artist) {
|
if (artist) {
|
||||||
elems.push((
|
elems.push((
|
||||||
<div className='audio-artist'>
|
<div key='artist' className='audio-artist'>
|
||||||
<label>Artist</label>{artist}
|
<label>Artist</label>{artist}
|
||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
if (album) {
|
if (album) {
|
||||||
elems.push((
|
elems.push((
|
||||||
<div className='audio-album'>
|
<div key='album' className='audio-album'>
|
||||||
<label>Album</label>{album}
|
<label>Album</label>{album}
|
||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
if (track) {
|
if (track) {
|
||||||
elems.push((
|
elems.push((
|
||||||
<div className='audio-track'>
|
<div key='track' className='audio-track'>
|
||||||
<label>Track</label>{track}
|
<label>Track</label>{track}
|
||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
@@ -232,12 +234,12 @@ function renderAudioMetadata (state) {
|
|||||||
// Align the title with the other info, if available. Otherwise, center title
|
// Align the title with the other info, if available. Otherwise, center title
|
||||||
var emptyLabel = (<label></label>)
|
var emptyLabel = (<label></label>)
|
||||||
elems.unshift((
|
elems.unshift((
|
||||||
<div className='audio-title'>
|
<div key='title' className='audio-title'>
|
||||||
{elems.length ? emptyLabel : undefined}{title}
|
{elems.length ? emptyLabel : undefined}{title}
|
||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
|
|
||||||
return (<div className='audio-metadata'>{elems}</div>)
|
return (<div key='audio-metadata' className='audio-metadata'>{elems}</div>)
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderLoadingSpinner (state) {
|
function renderLoadingSpinner (state) {
|
||||||
@@ -254,9 +256,9 @@ function renderLoadingSpinner (state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='media-stalled'>
|
<div key='loading' className='media-stalled'>
|
||||||
<div className='loading-spinner'> </div>
|
<div key='loading-spinner' className='loading-spinner'> </div>
|
||||||
<div className='loading-status ellipsis'>
|
<div key='loading-progress' className='loading-status ellipsis'>
|
||||||
<span className='progress'>{fileProgress}%</span> downloaded,
|
<span className='progress'>{fileProgress}%</span> downloaded,
|
||||||
<span>↓ {prettyBytes(prog.downloadSpeed || 0)}/s</span>
|
<span>↓ {prettyBytes(prog.downloadSpeed || 0)}/s</span>
|
||||||
<span>↑ {prettyBytes(prog.uploadSpeed || 0)}/s</span>
|
<span>↑ {prettyBytes(prog.uploadSpeed || 0)}/s</span>
|
||||||
@@ -302,11 +304,11 @@ function renderCastScreen (state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='letterbox' style={style}>
|
<div key='cast' className='letterbox' style={style}>
|
||||||
<div className='cast-screen'>
|
<div className='cast-screen'>
|
||||||
<i className='icon'>{castIcon}</i>
|
<i className='icon'>{castIcon}</i>
|
||||||
<div className='cast-type'>{castType}</div>
|
<div key='type' className='cast-type'>{castType}</div>
|
||||||
<div className='cast-status'>{castStatus}</div>
|
<div key='status' className='cast-status'>{castStatus}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -322,7 +324,7 @@ function renderCastOptions (state) {
|
|||||||
var isSelected = player.device === device
|
var isSelected = player.device === device
|
||||||
var name = device.name
|
var name = device.name
|
||||||
return (
|
return (
|
||||||
<li onClick={dispatcher('selectCastDevice', ix)}>
|
<li key={ix} onClick={dispatcher('selectCastDevice', ix)}>
|
||||||
<i className='icon'>{isSelected ? 'radio_button_checked' : 'radio_button_unchecked'}</i>
|
<i className='icon'>{isSelected ? 'radio_button_checked' : 'radio_button_unchecked'}</i>
|
||||||
{name}
|
{name}
|
||||||
</li>
|
</li>
|
||||||
@@ -330,20 +332,20 @@ function renderCastOptions (state) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ul className='options-list'>
|
<ul key='cast-options' className='options-list'>
|
||||||
{items}
|
{items}
|
||||||
</ul>
|
</ul>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderSubtitlesOptions (state) {
|
function renderSubtitleOptions (state) {
|
||||||
var subtitles = state.playing.subtitles
|
var subtitles = state.playing.subtitles
|
||||||
if (!subtitles.tracks.length || !subtitles.showMenu) return
|
if (!subtitles.tracks.length || !subtitles.showMenu) return
|
||||||
|
|
||||||
var items = subtitles.tracks.map(function (track, ix) {
|
var items = subtitles.tracks.map(function (track, ix) {
|
||||||
var isSelected = state.playing.subtitles.selectedIndex === ix
|
var isSelected = state.playing.subtitles.selectedIndex === ix
|
||||||
return (
|
return (
|
||||||
<li onClick={dispatcher('selectSubtitle', ix)}>
|
<li key={ix} onClick={dispatcher('selectSubtitle', ix)}>
|
||||||
<i className='icon'>{'radio_button_' + (isSelected ? 'checked' : 'unchecked')}</i>
|
<i className='icon'>{'radio_button_' + (isSelected ? 'checked' : 'unchecked')}</i>
|
||||||
{track.label}
|
{track.label}
|
||||||
</li>
|
</li>
|
||||||
@@ -353,7 +355,7 @@ function renderSubtitlesOptions (state) {
|
|||||||
var noneSelected = state.playing.subtitles.selectedIndex === -1
|
var noneSelected = state.playing.subtitles.selectedIndex === -1
|
||||||
var noneClass = 'radio_button_' + (noneSelected ? 'checked' : 'unchecked')
|
var noneClass = 'radio_button_' + (noneSelected ? 'checked' : 'unchecked')
|
||||||
return (
|
return (
|
||||||
<ul className='options-list'>
|
<ul key='subtitle-options' className='options-list'>
|
||||||
{items}
|
{items}
|
||||||
<li onClick={dispatcher('selectSubtitle', -1)}>
|
<li onClick={dispatcher('selectSubtitle', -1)}>
|
||||||
<i className='icon'>{noneClass}</i>
|
<i className='icon'>{noneClass}</i>
|
||||||
@@ -373,13 +375,15 @@ function renderPlayerControls (state) {
|
|||||||
: ''
|
: ''
|
||||||
|
|
||||||
var elements = [
|
var elements = [
|
||||||
<div className='playback-bar'>
|
<div key='playback-bar' className='playback-bar'>
|
||||||
{renderLoadingBar(state)}
|
{renderLoadingBar(state)}
|
||||||
<div
|
<div
|
||||||
|
key='cursor'
|
||||||
className='playback-cursor'
|
className='playback-cursor'
|
||||||
style={playbackCursorStyle}>
|
style={playbackCursorStyle}>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
key='scrub-bar'
|
||||||
className='scrub-bar'
|
className='scrub-bar'
|
||||||
draggable='true'
|
draggable='true'
|
||||||
onDragStart={handleDragStart}
|
onDragStart={handleDragStart}
|
||||||
@@ -388,11 +392,15 @@ function renderPlayerControls (state) {
|
|||||||
</div>
|
</div>
|
||||||
</div>,
|
</div>,
|
||||||
|
|
||||||
<i className='icon play-pause float-left' onClick={dispatcher('playPause')}>
|
<i
|
||||||
|
key='play'
|
||||||
|
className='icon play-pause float-left'
|
||||||
|
onClick={dispatcher('playPause')}>
|
||||||
{state.playing.isPaused ? 'play_arrow' : 'pause'}
|
{state.playing.isPaused ? 'play_arrow' : 'pause'}
|
||||||
</i>,
|
</i>,
|
||||||
|
|
||||||
<i
|
<i
|
||||||
|
key='fullscreen'
|
||||||
className='icon fullscreen float-right'
|
className='icon fullscreen float-right'
|
||||||
onClick={dispatcher('toggleFullScreen')}>
|
onClick={dispatcher('toggleFullScreen')}>
|
||||||
{state.window.isFullScreen ? 'fullscreen_exit' : 'fullscreen'}
|
{state.window.isFullScreen ? 'fullscreen_exit' : 'fullscreen'}
|
||||||
@@ -403,6 +411,7 @@ function renderPlayerControls (state) {
|
|||||||
// show closed captions icon
|
// show closed captions icon
|
||||||
elements.push((
|
elements.push((
|
||||||
<i
|
<i
|
||||||
|
key='subtitles'
|
||||||
className={'icon closed-caption float-right ' + captionsClass}
|
className={'icon closed-caption float-right ' + captionsClass}
|
||||||
onClick={handleSubtitles}>
|
onClick={handleSubtitles}>
|
||||||
closed_caption
|
closed_caption
|
||||||
@@ -446,6 +455,7 @@ function renderPlayerControls (state) {
|
|||||||
|
|
||||||
elements.push((
|
elements.push((
|
||||||
<i
|
<i
|
||||||
|
key={castType}
|
||||||
className={'icon device float-right ' + buttonClass}
|
className={'icon device float-right ' + buttonClass}
|
||||||
onClick={buttonHandler}>
|
onClick={buttonHandler}>
|
||||||
{buttonIcon}
|
{buttonIcon}
|
||||||
@@ -466,8 +476,10 @@ function renderPlayerControls (state) {
|
|||||||
'color-stop(' + (volume * 100) + '%, #727272))'
|
'color-stop(' + (volume * 100) + '%, #727272))'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: dcposch change the range input to use value / onChanged instead of
|
||||||
|
// "readonly" / onMouse[Down,Move,Up]
|
||||||
elements.push((
|
elements.push((
|
||||||
<div className='volume float-left'>
|
<div key='volume' className='volume float-left'>
|
||||||
<i
|
<i
|
||||||
className='icon volume-icon float-left'
|
className='icon volume-icon float-left'
|
||||||
onMouseDown={handleVolumeMute}>
|
onMouseDown={handleVolumeMute}>
|
||||||
@@ -476,10 +488,8 @@ function renderPlayerControls (state) {
|
|||||||
<input
|
<input
|
||||||
className='volume-slider float-right'
|
className='volume-slider float-right'
|
||||||
type='range' min='0' max='1' step='0.05'
|
type='range' min='0' max='1' step='0.05'
|
||||||
value={volumeChanging !== false ? volumeChanging : volume}
|
value={volume}
|
||||||
onMouseDown={handleVolumeScrub}
|
onChange={handleVolumeScrub}
|
||||||
onMouseUp={handleVolumeScrub}
|
|
||||||
onMouseMove={handleVolumeScrub}
|
|
||||||
style={volumeStyle}
|
style={volumeStyle}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -489,7 +499,7 @@ function renderPlayerControls (state) {
|
|||||||
var currentTimeStr = formatTime(state.playing.currentTime)
|
var currentTimeStr = formatTime(state.playing.currentTime)
|
||||||
var durationStr = formatTime(state.playing.duration)
|
var durationStr = formatTime(state.playing.duration)
|
||||||
elements.push((
|
elements.push((
|
||||||
<span className='time float-left'>
|
<span key='time' className='time float-left'>
|
||||||
{currentTimeStr} / {durationStr}
|
{currentTimeStr} / {durationStr}
|
||||||
</span>
|
</span>
|
||||||
))
|
))
|
||||||
@@ -497,17 +507,17 @@ function renderPlayerControls (state) {
|
|||||||
// render playback rate
|
// render playback rate
|
||||||
if (state.playing.playbackRate !== 1) {
|
if (state.playing.playbackRate !== 1) {
|
||||||
elements.push((
|
elements.push((
|
||||||
<span className='rate float-left'>
|
<span key='rate' className='rate float-left'>
|
||||||
{state.playing.playbackRate}x
|
{state.playing.playbackRate}x
|
||||||
</span>
|
</span>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='controls'>
|
<div key='controls' className='controls'>
|
||||||
{elements}
|
{elements}
|
||||||
{renderCastOptions(state)}
|
{renderCastOptions(state)}
|
||||||
{renderSubtitlesOptions(state)}
|
{renderSubtitleOptions(state)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -540,21 +550,7 @@ function renderPlayerControls (state) {
|
|||||||
|
|
||||||
// Handles volume slider scrub
|
// Handles volume slider scrub
|
||||||
function handleVolumeScrub (e) {
|
function handleVolumeScrub (e) {
|
||||||
switch (e.type) {
|
dispatch('setVolume', e.target.value)
|
||||||
case 'mouseup':
|
|
||||||
volumeChanging = false
|
|
||||||
dispatch('setVolume', e.nativeEvent.offsetX / 50)
|
|
||||||
break
|
|
||||||
case 'mousedown':
|
|
||||||
volumeChanging = this.value
|
|
||||||
break
|
|
||||||
case 'mousemove':
|
|
||||||
// only change if move was started by click
|
|
||||||
if (volumeChanging !== false) {
|
|
||||||
volumeChanging = this.value
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSubtitles (e) {
|
function handleSubtitles (e) {
|
||||||
@@ -567,9 +563,6 @@ function renderPlayerControls (state) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// lets scrub without sending to volume backend
|
|
||||||
var volumeChanging = false
|
|
||||||
|
|
||||||
// Renders the loading bar. Shows which parts of the torrent are loaded, which
|
// Renders the loading bar. Shows which parts of the torrent are loaded, which
|
||||||
// can be 'spongey' / non-contiguous
|
// can be 'spongey' / non-contiguous
|
||||||
function renderLoadingBar (state) {
|
function renderLoadingBar (state) {
|
||||||
@@ -594,15 +587,15 @@ function renderLoadingBar (state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Output some bars to show which parts of the file are loaded
|
// Output some bars to show which parts of the file are loaded
|
||||||
var loadingBarElems = parts.map(function (part) {
|
var loadingBarElems = parts.map(function (part, i) {
|
||||||
var style = {
|
var style = {
|
||||||
left: (100 * part.start / fileProg.numPieces) + '%',
|
left: (100 * part.start / fileProg.numPieces) + '%',
|
||||||
width: (100 * part.count / fileProg.numPieces) + '%'
|
width: (100 * part.count / fileProg.numPieces) + '%'
|
||||||
}
|
}
|
||||||
|
|
||||||
return (<div className='loading-bar-part' style={style}></div>)
|
return (<div key={i} className='loading-bar-part' style={style}></div>)
|
||||||
})
|
})
|
||||||
return (<div className='loading-bar'>{loadingBarElems}</div>)
|
return (<div key='loading-bar' className='loading-bar'>{loadingBarElems}</div>)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the CSS background-image string for a poster image + dark vignette
|
// Returns the CSS background-image string for a poster image + dark vignette
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ module.exports = class Preferences extends React.Component {
|
|||||||
|
|
||||||
function renderGeneralSection (state) {
|
function renderGeneralSection (state) {
|
||||||
return renderSection({
|
return renderSection({
|
||||||
|
key: 'general',
|
||||||
title: 'General',
|
title: 'General',
|
||||||
description: '',
|
description: '',
|
||||||
icon: 'settings'
|
icon: 'settings'
|
||||||
@@ -27,6 +28,7 @@ function renderGeneralSection (state) {
|
|||||||
|
|
||||||
function renderDownloadDirSelector (state) {
|
function renderDownloadDirSelector (state) {
|
||||||
return renderFileSelector({
|
return renderFileSelector({
|
||||||
|
key: 'download-path',
|
||||||
label: 'Download Path',
|
label: 'Download Path',
|
||||||
description: 'Data from torrents will be saved here',
|
description: 'Data from torrents will be saved here',
|
||||||
property: 'downloadPath',
|
property: 'downloadPath',
|
||||||
@@ -46,18 +48,18 @@ function renderDownloadDirSelector (state) {
|
|||||||
// - controls should be an array of vdom elements
|
// - controls should be an array of vdom elements
|
||||||
function renderSection (definition, controls) {
|
function renderSection (definition, controls) {
|
||||||
var helpElem = !definition.description ? null : (
|
var helpElem = !definition.description ? null : (
|
||||||
<div className='help text'>
|
<div key='help' className='help text'>
|
||||||
<i className='icon'>help_outline</i>{definition.description}
|
<i className='icon'>help_outline</i>{definition.description}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
<section className='section preferences-panel'>
|
<section key={definition.key} className='section preferences-panel'>
|
||||||
<div className='section-container'>
|
<div className='section-container'>
|
||||||
<div className='section-heading'>
|
<div key='heading' className='section-heading'>
|
||||||
<i className='icon'>{definition.icon}</i>{definition.title}
|
<i className='icon'>{definition.icon}</i>{definition.title}
|
||||||
</div>
|
</div>
|
||||||
{helpElem}
|
{helpElem}
|
||||||
<div className='section-body'>
|
<div key='body' className='section-body'>
|
||||||
{controls}
|
{controls}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -72,7 +74,7 @@ function renderSection (definition, controls) {
|
|||||||
// - callback takes a new file or folder path
|
// - callback takes a new file or folder path
|
||||||
function renderFileSelector (definition, value, callback) {
|
function renderFileSelector (definition, value, callback) {
|
||||||
return (
|
return (
|
||||||
<div className='control-group'>
|
<div key={definition.key} className='control-group'>
|
||||||
<div className='controls'>
|
<div className='controls'>
|
||||||
<label className='control-label'>
|
<label className='control-label'>
|
||||||
<div className='preference-title'>{definition.label}</div>
|
<div className='preference-title'>{definition.label}</div>
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ module.exports = class TorrentList extends React.Component {
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='torrent-list'>
|
<div key='torrent-list' className='torrent-list'>
|
||||||
{torrentRows}
|
{torrentRows}
|
||||||
<div className='torrent-placeholder'>
|
<div key='torrent-placeholder' className='torrent-placeholder'>
|
||||||
<span className='ellipsis'>Drop a torrent file here or paste a magnet link</span>
|
<span className='ellipsis'>Drop a torrent file here or paste a magnet link</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -45,7 +45,10 @@ module.exports = class TorrentList extends React.Component {
|
|||||||
if (isSelected) classes.push('selected')
|
if (isSelected) classes.push('selected')
|
||||||
if (!infoHash) classes.push('disabled')
|
if (!infoHash) classes.push('disabled')
|
||||||
return (
|
return (
|
||||||
<div style={style} className={classes.join(' ')}
|
<div
|
||||||
|
key={torrentSummary.torrentKey}
|
||||||
|
style={style}
|
||||||
|
className={classes.join(' ')}
|
||||||
onContextMenu={infoHash && dispatcher('openTorrentContextMenu', infoHash)}
|
onContextMenu={infoHash && dispatcher('openTorrentContextMenu', infoHash)}
|
||||||
onClick={infoHash && dispatcher('toggleSelectTorrent', infoHash)}>
|
onClick={infoHash && dispatcher('toggleSelectTorrent', infoHash)}>
|
||||||
{this.renderTorrentMetadata(torrentSummary)}
|
{this.renderTorrentMetadata(torrentSummary)}
|
||||||
@@ -59,14 +62,14 @@ module.exports = class TorrentList extends React.Component {
|
|||||||
renderTorrentMetadata (torrentSummary) {
|
renderTorrentMetadata (torrentSummary) {
|
||||||
var name = torrentSummary.name || 'Loading torrent...'
|
var name = torrentSummary.name || 'Loading torrent...'
|
||||||
var elements = [(
|
var elements = [(
|
||||||
<div className='name ellipsis'>{name}</div>
|
<div key='name' className='name ellipsis'>{name}</div>
|
||||||
)]
|
)]
|
||||||
|
|
||||||
// If it's downloading/seeding then show progress info
|
// If it's downloading/seeding then show progress info
|
||||||
var prog = torrentSummary.progress
|
var prog = torrentSummary.progress
|
||||||
if (torrentSummary.status !== 'paused' && prog) {
|
if (torrentSummary.status !== 'paused' && prog) {
|
||||||
elements.push((
|
elements.push((
|
||||||
<div className='ellipsis'>
|
<div key='progress-info' className='ellipsis'>
|
||||||
{renderPercentProgress()}
|
{renderPercentProgress()}
|
||||||
{renderTotalProgress()}
|
{renderTotalProgress()}
|
||||||
{renderPeers()}
|
{renderPeers()}
|
||||||
@@ -77,37 +80,37 @@ module.exports = class TorrentList extends React.Component {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
return (<div className='metadata'>{elements}</div>)
|
return (<div key='metadata' className='metadata'>{elements}</div>)
|
||||||
|
|
||||||
function renderPercentProgress () {
|
function renderPercentProgress () {
|
||||||
var progress = Math.floor(100 * prog.progress)
|
var progress = Math.floor(100 * prog.progress)
|
||||||
return (<span>{progress}%</span>)
|
return (<span key='percent-progress'>{progress}%</span>)
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderTotalProgress () {
|
function renderTotalProgress () {
|
||||||
var downloaded = prettyBytes(prog.downloaded)
|
var downloaded = prettyBytes(prog.downloaded)
|
||||||
var total = prettyBytes(prog.length || 0)
|
var total = prettyBytes(prog.length || 0)
|
||||||
if (downloaded === total) {
|
if (downloaded === total) {
|
||||||
return (<span>{downloaded}</span>)
|
return (<span key='total-progress'>{downloaded}</span>)
|
||||||
} else {
|
} else {
|
||||||
return (<span>{downloaded} / {total}</span>)
|
return (<span key='total-progress'>{downloaded} / {total}</span>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderPeers () {
|
function renderPeers () {
|
||||||
if (prog.numPeers === 0) return
|
if (prog.numPeers === 0) return
|
||||||
var count = prog.numPeers === 1 ? 'peer' : 'peers'
|
var count = prog.numPeers === 1 ? 'peer' : 'peers'
|
||||||
return (<span>{prog.numPeers} {count}</span>)
|
return (<span key='peers'>{prog.numPeers} {count}</span>)
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderDownloadSpeed () {
|
function renderDownloadSpeed () {
|
||||||
if (prog.downloadSpeed === 0) return
|
if (prog.downloadSpeed === 0) return
|
||||||
return (<span>↓ {prettyBytes(prog.downloadSpeed)}/s</span>)
|
return (<span key='download'>↓ {prettyBytes(prog.downloadSpeed)}/s</span>)
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderUploadSpeed () {
|
function renderUploadSpeed () {
|
||||||
if (prog.uploadSpeed === 0) return
|
if (prog.uploadSpeed === 0) return
|
||||||
return (<span>↑ {prettyBytes(prog.uploadSpeed)}/s</span>)
|
return (<span key='upload'>↑ {prettyBytes(prog.uploadSpeed)}/s</span>)
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderEta () {
|
function renderEta () {
|
||||||
@@ -175,6 +178,7 @@ module.exports = class TorrentList extends React.Component {
|
|||||||
if (TorrentPlayer.isPlayableTorrentSummary(torrentSummary)) {
|
if (TorrentPlayer.isPlayableTorrentSummary(torrentSummary)) {
|
||||||
playButton = (
|
playButton = (
|
||||||
<i
|
<i
|
||||||
|
key='play-button'
|
||||||
title={playTooltip}
|
title={playTooltip}
|
||||||
className={'button-round icon play ' + playClass}
|
className={'button-round icon play ' + playClass}
|
||||||
onClick={dispatcher('playFile', infoHash)}>
|
onClick={dispatcher('playFile', infoHash)}>
|
||||||
@@ -184,16 +188,18 @@ module.exports = class TorrentList extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='buttons'>
|
<div key='buttons' className='buttons'>
|
||||||
{positionElem}
|
{positionElem}
|
||||||
{playButton}
|
{playButton}
|
||||||
<i
|
<i
|
||||||
|
key='download-button'
|
||||||
className={'button-round icon download ' + torrentSummary.status}
|
className={'button-round icon download ' + torrentSummary.status}
|
||||||
title={downloadTooltip}
|
title={downloadTooltip}
|
||||||
onClick={dispatcher('toggleTorrent', infoHash)}>
|
onClick={dispatcher('toggleTorrent', infoHash)}>
|
||||||
{downloadIcon}
|
{downloadIcon}
|
||||||
</i>
|
</i>
|
||||||
<i
|
<i
|
||||||
|
key='delete-button'
|
||||||
className='icon delete'
|
className='icon delete'
|
||||||
title='Remove torrent'
|
title='Remove torrent'
|
||||||
onClick={dispatcher('confirmDeleteTorrent', infoHash, false)}>
|
onClick={dispatcher('confirmDeleteTorrent', infoHash, false)}>
|
||||||
@@ -211,7 +217,7 @@ module.exports = class TorrentList extends React.Component {
|
|||||||
var message = torrentSummary.status === 'paused'
|
var message = torrentSummary.status === 'paused'
|
||||||
? 'Failed to load torrent info. Click the download button to try again...'
|
? 'Failed to load torrent info. Click the download button to try again...'
|
||||||
: 'Downloading torrent info...'
|
: 'Downloading torrent info...'
|
||||||
filesElement = (<div className='files warning'>{message}</div>)
|
filesElement = (<div key='files' className='files warning'>{message}</div>)
|
||||||
} else {
|
} else {
|
||||||
// We do know the files. List them and show download stats for each one
|
// We do know the files. List them and show download stats for each one
|
||||||
var fileRows = torrentSummary.files
|
var fileRows = torrentSummary.files
|
||||||
@@ -224,16 +230,18 @@ module.exports = class TorrentList extends React.Component {
|
|||||||
.map((object) => this.renderFileRow(torrentSummary, object.file, object.index))
|
.map((object) => this.renderFileRow(torrentSummary, object.file, object.index))
|
||||||
|
|
||||||
filesElement = (
|
filesElement = (
|
||||||
<div className='files'>
|
<div key='files' className='files'>
|
||||||
<table>
|
<table>
|
||||||
{fileRows}
|
<tbody>
|
||||||
|
{fileRows}
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='torrent-details'>
|
<div key='details' className='torrent-details'>
|
||||||
{filesElement}
|
{filesElement}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -275,7 +283,7 @@ module.exports = class TorrentList extends React.Component {
|
|||||||
if (!isSelected) rowClass = 'disabled' // File deselected, not being torrented
|
if (!isSelected) rowClass = 'disabled' // File deselected, not being torrented
|
||||||
if (!isDone && !isPlayable) rowClass = 'disabled' // Can't open yet, can't stream
|
if (!isDone && !isPlayable) rowClass = 'disabled' // Can't open yet, can't stream
|
||||||
return (
|
return (
|
||||||
<tr onClick={handleClick}>
|
<tr key={index} onClick={handleClick}>
|
||||||
<td className={'col-icon ' + rowClass}>
|
<td className={'col-icon ' + rowClass}>
|
||||||
{positionElem}
|
{positionElem}
|
||||||
<i className='icon'>{icon}</i>
|
<i className='icon'>{icon}</i>
|
||||||
@@ -303,17 +311,17 @@ module.exports = class TorrentList extends React.Component {
|
|||||||
var transformFix = {transform: 'rotate(' + rotation + 'deg)'}
|
var transformFix = {transform: 'rotate(' + rotation + 'deg)'}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'radial-progress ' + cssClass}>
|
<div key='radial-progress' className={'radial-progress ' + cssClass}>
|
||||||
<div className='circle'>
|
<div key='circle' className='circle'>
|
||||||
<div className='mask full' style={transformFill}>
|
<div key='mask-full' className='mask full' style={transformFill}>
|
||||||
<div className='fill' style={transformFill}></div>
|
<div key='fill' className='fill' style={transformFill}></div>
|
||||||
</div>
|
</div>
|
||||||
<div className='mask half'>
|
<div key='mask-half' className='mask half'>
|
||||||
<div className='fill' style={transformFill}></div>
|
<div key='fill' className='fill' style={transformFill}></div>
|
||||||
<div className='fill fix' style={transformFix}></div>
|
<div key='fill-fix' className='fill fix' style={transformFix}></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='inset'></div>
|
<div key='inset' className='inset'></div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,13 @@ body {
|
|||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,5 +9,7 @@
|
|||||||
require('../build/renderer/main.js')
|
require('../build/renderer/main.js')
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body></body>
|
<body>
|
||||||
|
<div id='body'></div>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user