feat(downloading): choose dir on new download

This commit is contained in:
Alexey Kasyanchuk 2018-08-28 19:47:55 +03:00
parent 5f874883a1
commit 4c2ff465f2
10 changed files with 217 additions and 86 deletions

55
src/app/context-menu.js Normal file
View File

@ -0,0 +1,55 @@
import React, {Component} from 'react';
import {List, ListItem} from 'material-ui/List';
export default class ContextMenu extends Component {
constructor(props) {
super(props)
this.state = {toggle: false}
}
render()
{
return (
<div style={{position: 'relative', display: 'inline-block'}}>
<div style={{display: 'inline-block'}} onClick={(e) => {
this.setState({toggle: !this.state.toggle})
if(this.props.onClick)
this.props.onClick(e)
}}>
{this.props.children}
</div>
{
this.state.toggle
&&
<div style={{width: '100%', height: '100%', position: 'fixed', top: 0, left: 0, zIndex: 2}} onClick={(e) => {
this.setState({toggle: !this.state.toggle})
e.preventDefault()
e.stopPropagation()
}}><span></span></div>
}
{
this.state.toggle
&&
<List className='context-menu' style={Object.assign({
position: 'absolute',
maxWidth: 350,
minWidth: 200,
top: -20,
backgroundColor: '#ffffff',
boxShadow: '0 0 10px rgba(0,0,0,0.45)',
borderRadius: 6,
zIndex: 3
}, !this.props.rightAlign ? { left: -30 } : { right: -30 })}>
{
this.props.menu && this.props.menu.map(menu => <ListItem style={{fontSize: '0.9em'}} primaryText={menu.name} leftIcon={menu.icon} onClick={(e) => {
menu.click()
this.setState({toggle: !this.state.toggle})
e.preventDefault()
e.stopPropagation()
}} />)
}
</List>
}
</div>
)
}
}

View File

@ -0,0 +1,73 @@
import React from 'react';
import ContextMenu from './context-menu'
let dialog
if(typeof WEB === 'undefined')
dialog = require('electron').remote.dialog
export default (props) => {
return (
<ContextMenu rightAlign={true} onClick={(e) => {
e.preventDefault();
e.stopPropagation();
}} menu={[
{name: __('Download'), click: () => {
window.torrentSocket.emit('download', props.torrent, null, (added) => {
if(props.onAdded)
props.onAdded(added)
})
}, icon: <svg style={{
fill: 'black'
}} viewBox="0 0 56 56">
<g>
<path d="M35.586,41.586L31,46.172V28c0-1.104-0.896-2-2-2s-2,0.896-2,2v18.172l-4.586-4.586c-0.781-0.781-2.047-0.781-2.828,0
s-0.781,2.047,0,2.828l7.999,7.999c0.093,0.094,0.196,0.177,0.307,0.251c0.047,0.032,0.099,0.053,0.148,0.081
c0.065,0.036,0.127,0.075,0.196,0.103c0.065,0.027,0.133,0.042,0.2,0.062c0.058,0.017,0.113,0.04,0.173,0.051
C28.738,52.986,28.869,53,29,53s0.262-0.014,0.392-0.04c0.06-0.012,0.115-0.034,0.173-0.051c0.067-0.02,0.135-0.035,0.2-0.062
c0.069-0.028,0.131-0.067,0.196-0.103c0.05-0.027,0.101-0.049,0.148-0.081c0.11-0.074,0.213-0.157,0.307-0.251l7.999-7.999
c0.781-0.781,0.781-2.047,0-2.828S36.367,40.805,35.586,41.586z"/>
<path d="M47.835,18.986c-0.137-0.019-2.457-0.335-4.684,0.002C43.1,18.996,43.049,19,42.999,19c-0.486,0-0.912-0.354-0.987-0.85
c-0.083-0.546,0.292-1.056,0.838-1.139c1.531-0.233,3.062-0.196,4.083-0.124C46.262,9.135,39.83,3,32.085,3
C27.388,3,22.667,5.379,19.8,9.129C21.754,10.781,23,13.246,23,16c0,0.553-0.447,1-1,1s-1-0.447-1-1
c0-2.462-1.281-4.627-3.209-5.876c-0.227-0.147-0.462-0.277-0.702-0.396c-0.069-0.034-0.139-0.069-0.21-0.101
c-0.272-0.124-0.55-0.234-0.835-0.321c-0.035-0.01-0.071-0.017-0.106-0.027c-0.259-0.075-0.522-0.132-0.789-0.177
c-0.078-0.013-0.155-0.025-0.233-0.036C14.614,9.027,14.309,9,14,9c-3.859,0-7,3.141-7,7c0,0.082,0.006,0.163,0.012,0.244
l0.012,0.21l-0.009,0.16C7.008,16.744,7,16.873,7,17v0.63l-0.567,0.271C2.705,19.688,0,24,0,28.154C0,34.135,4.865,39,10.845,39H25
V28c0-2.209,1.791-4,4-4s4,1.791,4,4v11h2.353c0.059,0,0.116-0.005,0.174-0.009l0.198-0.011l0.271,0.011
C36.053,38.995,36.11,39,36.169,39h9.803C51.501,39,56,34.501,56,28.972C56,24.161,52.49,19.872,47.835,18.986z"/>
</g>
</svg>
},
{name: __('Download to') + '...', click: () => {
if(dialog)
{
const path = dialog.showOpenDialog({
properties: ['openDirectory']
});
if(!path || path.length < 1)
return
window.torrentSocket.emit('download', props.torrent, path[0], (added) => {
if(props.onAdded)
props.onAdded(added)
})
}
},
icon: <svg viewBox="0 0 60 60">
<g>
<path d="M54.168,0H5.832C4.271,0,3,1.271,3,2.832v54.336C3,58.729,4.271,60,5.832,60h48.336C55.729,60,57,58.729,57,57.168V2.832
C57,1.271,55.729,0,54.168,0z M5.832,2h48.336C54.627,2,55,2.373,55,2.832V29H5V2.832C5,2.373,5.373,2,5.832,2z M54.168,58H5.832
C5.373,58,5,57.627,5,57.168V31h50v26.168C55,57.627,54.627,58,54.168,58z"/>
<path d="M24.505,18h10.99C37.428,18,39,16.428,39,14.495V13c0-0.553-0.447-1-1-1s-1,0.447-1,1v1.495C37,15.325,36.325,16,35.495,16
h-10.99C23.675,16,23,15.325,23,14.495V13c0-0.553-0.447-1-1-1s-1,0.447-1,1v1.495C21,16.428,22.572,18,24.505,18z"/>
<path d="M38,41c-0.553,0-1,0.447-1,1v1.495C37,44.325,36.325,45,35.495,45h-10.99C23.675,45,23,44.325,23,43.495V42
c0-0.553-0.447-1-1-1s-1,0.447-1,1v1.495C21,45.428,22.572,47,24.505,47h10.99C37.428,47,39,45.428,39,43.495V42
C39,41.447,38.553,41,38,41z"/>
</g>
</svg>
}
]}>
{props.children}
</ContextMenu>
)
}

View File

@ -59,7 +59,7 @@ export default class TopPage extends Page {
return
this.topTorrents[type][time].torrents = _.orderBy(_.unionBy(this.topTorrents[type][time].torrents, torrents, 'hash'), ['seeders'], ['desc'])
if(this.state.type == type && this.state.time == time)
{
this._update();

View File

@ -20,6 +20,7 @@ import FlatButton from 'material-ui/FlatButton';
import {fileTypeDetect} from './content'
import {contentIcon} from './torrent'
import TrackersImages from './trackers-images'
import DownloadTorrentMenu from './download-torrent-menu'
let parseDescriptionText = (text) => {
return text.split("\n").map(function(item) {
@ -103,17 +104,17 @@ const treeToTorrentFiles = (tree, torrent, toggles) => {
leftIcon={!tree[file].__fileBT ? <FileFolder /> : contentIcon(fileTypeDetect({path: file}))}
rightToggle={
newToggles.length > 0
&&
<Toggle
toggled={newToggles.every( ({selected}) => selected )}
onToggle={(e, checked) => {
e.preventDefault()
e.stopPropagation()
let toggleValues = {}
newToggles.forEach(({downloadIndex}) => toggleValues[downloadIndex] = checked)
window.torrentSocket.emit('downloadSelectFiles', torrent, toggleValues)
}}
/>}
&&
<Toggle
toggled={newToggles.every( ({selected}) => selected )}
onToggle={(e, checked) => {
e.preventDefault()
e.stopPropagation()
let toggleValues = {}
newToggles.forEach(({downloadIndex}) => toggleValues[downloadIndex] = checked)
window.torrentSocket.emit('downloadSelectFiles', torrent, toggleValues)
}}
/>}
/>);
if(toggles)
@ -254,7 +255,7 @@ export default class TorrentPage extends Page {
// Получаем более новую статистику пира
if((Date.now() / 1000) - this.torrent.trackersChecked > 10 * 60) {
window.torrentSocket.emit('checkTrackers', this.torrent.hash);
}
}
}
}, () => {
this.setState({
@ -273,15 +274,15 @@ export default class TorrentPage extends Page {
if(this.props.hash != hash)
return;
if(filesList)
{
if(this.torrent)
{
this.torrent.filesList = filesList
this.forceUpdate()
}
}
else
if(filesList)
{
if(this.torrent)
{
this.torrent.filesList = filesList
this.forceUpdate()
}
}
else
this.getTorrentInfo();
}
window.torrentSocket.on('filesReady', this.filesUpdated);
@ -447,30 +448,27 @@ export default class TorrentPage extends Page {
{
!this.state.downloaded && !this.state.downloading && !this.state.startingDownloading
&&
<RaisedButton
href={`magnet:?xt=urn:btih:${this.torrent.hash}`}
target="_self"
label={__('Download')}
backgroundColor='#00C853'
labelColor='white'
style={{marginTop: 8}}
onClick={(e) => {
e.preventDefault();
window.torrentSocket.emit('download', this.torrent, null, (added) => {
if(added)
this.setState({startingDownloading: true})
})
}}
icon={
<svg viewBox="0 0 56 56" fill='white'>
<g>
<path d="M35.586,41.586L31,46.172V28c0-1.104-0.896-2-2-2s-2,0.896-2,2v18.172l-4.586-4.586c-0.781-0.781-2.047-0.781-2.828,0
<DownloadTorrentMenu torrent={this.torrent}>
<RaisedButton
href={`magnet:?xt=urn:btih:${this.torrent.hash}`}
target="_self"
label={__('Download')}
backgroundColor='#00C853'
labelColor='white'
style={{marginTop: 8}}
onClick={(e) => {
e.preventDefault();
}}
icon={
<svg viewBox="0 0 56 56" fill='white'>
<g>
<path d="M35.586,41.586L31,46.172V28c0-1.104-0.896-2-2-2s-2,0.896-2,2v18.172l-4.586-4.586c-0.781-0.781-2.047-0.781-2.828,0
s-0.781,2.047,0,2.828l7.999,7.999c0.093,0.094,0.196,0.177,0.307,0.251c0.047,0.032,0.099,0.053,0.148,0.081
c0.065,0.036,0.127,0.075,0.196,0.103c0.065,0.027,0.133,0.042,0.2,0.062c0.058,0.017,0.113,0.04,0.173,0.051
C28.738,52.986,28.869,53,29,53s0.262-0.014,0.392-0.04c0.06-0.012,0.115-0.034,0.173-0.051c0.067-0.02,0.135-0.035,0.2-0.062
c0.069-0.028,0.131-0.067,0.196-0.103c0.05-0.027,0.101-0.049,0.148-0.081c0.11-0.074,0.213-0.157,0.307-0.251l7.999-7.999
c0.781-0.781,0.781-2.047,0-2.828S36.367,40.805,35.586,41.586z"/>
<path d="M47.835,18.986c-0.137-0.019-2.457-0.335-4.684,0.002C43.1,18.996,43.049,19,42.999,19c-0.486,0-0.912-0.354-0.987-0.85
<path d="M47.835,18.986c-0.137-0.019-2.457-0.335-4.684,0.002C43.1,18.996,43.049,19,42.999,19c-0.486,0-0.912-0.354-0.987-0.85
c-0.083-0.546,0.292-1.056,0.838-1.139c1.531-0.233,3.062-0.196,4.083-0.124C46.262,9.135,39.83,3,32.085,3
C27.388,3,22.667,5.379,19.8,9.129C21.754,10.781,23,13.246,23,16c0,0.553-0.447,1-1,1s-1-0.447-1-1
c0-2.462-1.281-4.627-3.209-5.876c-0.227-0.147-0.462-0.277-0.702-0.396c-0.069-0.034-0.139-0.069-0.21-0.101
@ -479,10 +477,11 @@ export default class TorrentPage extends Page {
l0.012,0.21l-0.009,0.16C7.008,16.744,7,16.873,7,17v0.63l-0.567,0.271C2.705,19.688,0,24,0,28.154C0,34.135,4.865,39,10.845,39H25
V28c0-2.209,1.791-4,4-4s4,1.791,4,4v11h2.353c0.059,0,0.116-0.005,0.174-0.009l0.198-0.011l0.271,0.011
C36.053,38.995,36.11,39,36.169,39h9.803C51.501,39,56,34.501,56,28.972C56,24.161,52.49,19.872,47.835,18.986z"/>
</g>
</svg>
}
/>
</g>
</svg>
}
/>
</DownloadTorrentMenu>
}
{
this.state.downloading

View File

@ -11,6 +11,7 @@ import LinearProgress from './LinearProgress';
let rating = require('./rating');
import scrollBack from './remember-scroll'
import TrackersImages from './trackers-images'
import DownloadTorrentMenu from './download-torrent-menu'
const contentIcon = (type, category, fill = 'grey') => {
if(category == 'xxx')
@ -184,6 +185,8 @@ export default class Torrent extends Component {
this.state.downloadRemoveOnDone = removeOnDone
this.state.downloadPaused = paused
}
this.downloadPathInput = React.createRef();
}
componentDidMount()
@ -438,41 +441,39 @@ export default class Torrent extends Component {
{
!this.state.startingDownloading && !this.state.downloading && !this.state.downloaded
?
<ToolTip hint={__('Download using built-in client')} right={true}>
<a href={`magnet:?xt=urn:btih:${torrent.hash}`}>
<svg style={{
height: '24px',
marginRight: 12,
fill: torrent.contentCategory != 'xxx' ? (torrent.peer ? '#5643db' : 'black') : (torrent.peer ? '#9083e2' : 'grey')
}} onClick={(e) => {
e.preventDefault();
e.stopPropagation();
window.torrentSocket.emit('download', torrent, null, (added) => {
if(added)
this.setState({startingDownloading: true})
})
}} viewBox="0 0 56 56">
<g>
<path d="M35.586,41.586L31,46.172V28c0-1.104-0.896-2-2-2s-2,0.896-2,2v18.172l-4.586-4.586c-0.781-0.781-2.047-0.781-2.828,0
s-0.781,2.047,0,2.828l7.999,7.999c0.093,0.094,0.196,0.177,0.307,0.251c0.047,0.032,0.099,0.053,0.148,0.081
c0.065,0.036,0.127,0.075,0.196,0.103c0.065,0.027,0.133,0.042,0.2,0.062c0.058,0.017,0.113,0.04,0.173,0.051
C28.738,52.986,28.869,53,29,53s0.262-0.014,0.392-0.04c0.06-0.012,0.115-0.034,0.173-0.051c0.067-0.02,0.135-0.035,0.2-0.062
c0.069-0.028,0.131-0.067,0.196-0.103c0.05-0.027,0.101-0.049,0.148-0.081c0.11-0.074,0.213-0.157,0.307-0.251l7.999-7.999
c0.781-0.781,0.781-2.047,0-2.828S36.367,40.805,35.586,41.586z"/>
<path d="M47.835,18.986c-0.137-0.019-2.457-0.335-4.684,0.002C43.1,18.996,43.049,19,42.999,19c-0.486,0-0.912-0.354-0.987-0.85
c-0.083-0.546,0.292-1.056,0.838-1.139c1.531-0.233,3.062-0.196,4.083-0.124C46.262,9.135,39.83,3,32.085,3
C27.388,3,22.667,5.379,19.8,9.129C21.754,10.781,23,13.246,23,16c0,0.553-0.447,1-1,1s-1-0.447-1-1
c0-2.462-1.281-4.627-3.209-5.876c-0.227-0.147-0.462-0.277-0.702-0.396c-0.069-0.034-0.139-0.069-0.21-0.101
c-0.272-0.124-0.55-0.234-0.835-0.321c-0.035-0.01-0.071-0.017-0.106-0.027c-0.259-0.075-0.522-0.132-0.789-0.177
c-0.078-0.013-0.155-0.025-0.233-0.036C14.614,9.027,14.309,9,14,9c-3.859,0-7,3.141-7,7c0,0.082,0.006,0.163,0.012,0.244
l0.012,0.21l-0.009,0.16C7.008,16.744,7,16.873,7,17v0.63l-0.567,0.271C2.705,19.688,0,24,0,28.154C0,34.135,4.865,39,10.845,39H25
V28c0-2.209,1.791-4,4-4s4,1.791,4,4v11h2.353c0.059,0,0.116-0.005,0.174-0.009l0.198-0.011l0.271,0.011
C36.053,38.995,36.11,39,36.169,39h9.803C51.501,39,56,34.501,56,28.972C56,24.161,52.49,19.872,47.835,18.986z"/>
</g>
</svg>
</a>
</ToolTip>
<DownloadTorrentMenu torrent={torrent} onAdded={(added) => {
if(added)
this.setState({startingDownloading: true})
}}>
<ToolTip hint={__('Download using built-in client')} right={true}>
<a href={`magnet:?xt=urn:btih:${torrent.hash}`}>
<svg style={{
height: '24px',
marginRight: 12,
fill: torrent.contentCategory != 'xxx' ? (torrent.peer ? '#5643db' : 'black') : (torrent.peer ? '#9083e2' : 'grey')
}} viewBox="0 0 56 56">
<g>
<path d="M35.586,41.586L31,46.172V28c0-1.104-0.896-2-2-2s-2,0.896-2,2v18.172l-4.586-4.586c-0.781-0.781-2.047-0.781-2.828,0
s-0.781,2.047,0,2.828l7.999,7.999c0.093,0.094,0.196,0.177,0.307,0.251c0.047,0.032,0.099,0.053,0.148,0.081
c0.065,0.036,0.127,0.075,0.196,0.103c0.065,0.027,0.133,0.042,0.2,0.062c0.058,0.017,0.113,0.04,0.173,0.051
C28.738,52.986,28.869,53,29,53s0.262-0.014,0.392-0.04c0.06-0.012,0.115-0.034,0.173-0.051c0.067-0.02,0.135-0.035,0.2-0.062
c0.069-0.028,0.131-0.067,0.196-0.103c0.05-0.027,0.101-0.049,0.148-0.081c0.11-0.074,0.213-0.157,0.307-0.251l7.999-7.999
c0.781-0.781,0.781-2.047,0-2.828S36.367,40.805,35.586,41.586z"/>
<path d="M47.835,18.986c-0.137-0.019-2.457-0.335-4.684,0.002C43.1,18.996,43.049,19,42.999,19c-0.486,0-0.912-0.354-0.987-0.85
c-0.083-0.546,0.292-1.056,0.838-1.139c1.531-0.233,3.062-0.196,4.083-0.124C46.262,9.135,39.83,3,32.085,3
C27.388,3,22.667,5.379,19.8,9.129C21.754,10.781,23,13.246,23,16c0,0.553-0.447,1-1,1s-1-0.447-1-1
c0-2.462-1.281-4.627-3.209-5.876c-0.227-0.147-0.462-0.277-0.702-0.396c-0.069-0.034-0.139-0.069-0.21-0.101
c-0.272-0.124-0.55-0.234-0.835-0.321c-0.035-0.01-0.071-0.017-0.106-0.027c-0.259-0.075-0.522-0.132-0.789-0.177
c-0.078-0.013-0.155-0.025-0.233-0.036C14.614,9.027,14.309,9,14,9c-3.859,0-7,3.141-7,7c0,0.082,0.006,0.163,0.012,0.244
l0.012,0.21l-0.009,0.16C7.008,16.744,7,16.873,7,17v0.63l-0.567,0.271C2.705,19.688,0,24,0,28.154C0,34.135,4.865,39,10.845,39H25
V28c0-2.209,1.791-4,4-4s4,1.791,4,4v11h2.353c0.059,0,0.116-0.005,0.174-0.009l0.198-0.011l0.271,0.011
C36.053,38.995,36.11,39,36.169,39h9.803C51.501,39,56,34.501,56,28.972C56,24.161,52.49,19.872,47.835,18.986z"/>
</g>
</svg>
</a>
</ToolTip>
</DownloadTorrentMenu>
:
this.state.startingDownloading && !this.state.downloading
?

View File

@ -800,10 +800,10 @@ module.exports = async ({
}
torrent.updateFilesSelection()
}
torrent.updateFilesSelection = () => {
torrent.deselect(0, torrent.pieces.length - 1, false)
for(const file of torrent.files)
{
const {selected} = file

View File

@ -54,7 +54,7 @@ const expand = (sphinx) => {
valuesData += sphinx.escape(JSON.stringify(values[val])) + ',';
else
valuesData += sphinx.escape(values[val]) + ',';
names += '`' + val + '`,';
}
names = names.slice(0, -1)

View File

@ -187,6 +187,7 @@
"Torrents cleaned": "Torrents cleaned",
"or with hash": "or with hash",
"Check torrent files intergrity": "Check torrent files intergrity",
"Enable database torrents files intergrity check on adding each torrent. Disable this will free some cpu usage on adding operation.": "Enable database torrents files intergrity check on adding each torrent. Disable this will free some cpu usage on adding operation."
"Enable database torrents files intergrity check on adding each torrent. Disable this will free some cpu usage on adding operation.": "Enable database torrents files intergrity check on adding each torrent. Disable this will free some cpu usage on adding operation.",
"Download to": "Download to"
}
}

View File

@ -187,6 +187,7 @@
"Torrents cleaned": "Торренты очещены",
"or with hash": "или по хэшу",
"Check torrent files intergrity": "Проверка целостности файлов",
"Enable database torrents files intergrity check on adding each torrent. Disable this will free some cpu usage on adding operation.": "Включить проверку целостности файлов в базе при добавлении каждого торрента. Отключение этой опции освободит некоторорое количество ресурсов процессора при добавлении."
"Enable database torrents files intergrity check on adding each torrent. Disable this will free some cpu usage on adding operation.": "Включить проверку целостности файлов в базе при добавлении каждого торрента. Отключение этой опции освободит некоторорое количество ресурсов процессора при добавлении.",
"Download to": "Скачать в"
}
}

View File

@ -187,6 +187,7 @@
"Torrents cleaned": "Torrents cleaned",
"or with hash": "or with hash",
"Check torrent files intergrity": "Check torrent files intergrity",
"Enable database torrents files intergrity check on adding each torrent. Disable this will free some cpu usage on adding operation.": "Enable database torrents files intergrity check on adding each torrent. Disable this will free some cpu usage on adding operation."
"Enable database torrents files intergrity check on adding each torrent. Disable this will free some cpu usage on adding operation.": "Enable database torrents files intergrity check on adding each torrent. Disable this will free some cpu usage on adding operation.",
"Download to": "Download to"
}
}