diff --git a/scss/main.scss b/scss/main.scss
index c8ea8e3..f7d2557 100644
--- a/scss/main.scss
+++ b/scss/main.scss
@@ -88,3 +88,18 @@
}
}
}
+
+.btn-very-sm {
+ padding: 0 0.75rem;
+ line-height: 1;
+}
+
+.btn-group {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 1rem;
+
+ .btn-group {
+ margin-bottom: 0;
+ }
+}
diff --git a/src/reducers/files.js b/src/reducers/files.js
new file mode 100644
index 0000000..6b1b068
--- /dev/null
+++ b/src/reducers/files.js
@@ -0,0 +1,24 @@
+import {
+ UPDATE_RESOURCES,
+ RESOURCES_REMOVED
+} from '../actions/resources';
+
+export default function files(state = {}, action) {
+ switch (action.type) {
+ case UPDATE_RESOURCES:
+ return {
+ ...state,
+ ...action.resources
+ .filter(r => r.type === "file")
+ .reduce((s, r) => ({
+ ...s,
+ [r.id]: { ...state[r.id], ...r }
+ }), {})
+ };
+ case RESOURCES_REMOVED:
+ return Object.values(state)
+ .filter(r => action.ids.indexOf(r.id) === -1)
+ .reduce((s, r) => ({ ...s, [r.id]: r }), {});
+ }
+ return state;
+}
diff --git a/src/reducers/index.js b/src/reducers/index.js
index 709c0f6..ba1dc2b 100644
--- a/src/reducers/index.js
+++ b/src/reducers/index.js
@@ -3,11 +3,13 @@ import { routerReducer } from 'react-router-redux'
import subscribe from './subscribe';
import filter_subscribe from './filter_subscribe';
import torrents from './torrents';
+import files from './files';
const root = combineReducers({
subscribe,
filter_subscribe,
torrents,
+ files,
router: routerReducer
});
diff --git a/src/ui/torrent_details.js b/src/ui/torrent_details.js
index e69af7f..bb6fb8d 100644
--- a/src/ui/torrent_details.js
+++ b/src/ui/torrent_details.js
@@ -1,26 +1,140 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { activeTorrents } from '../torrent_state';
+import FontAwesome from 'react-fontawesome';
import {
- Button,
ButtonGroup,
ButtonDropdown,
DropdownToggle,
DropdownMenu,
- DropdownItem
+ DropdownItem,
+ Collapse,
+ Card,
+ CardBlock,
+ Progress
} from 'reactstrap';
+import ws_send from '../socket';
// TODO: use component lifecycle functions here to invoke
// torrent_state.updateSubscriptions
+// TODO: fix navigating directly to torrent pages
-function Torrent(props) {
+function File({ file }) {
+ // TODO: show progress bar
+ // TODO: edit priority
return (
-
-
{props.torrent.name}
-
+
+ {file.path} |
+ {file.priority} |
+ {file.availability} |
+
);
}
+// TODO: move to separate component
+function CollapseToggle({ text, onToggle, open }) {
+ return (
+
+ );
+}
+
+class Torrent extends Component {
+ constructor() {
+ super();
+ this.state = {
+ infoShown: false,
+ filesShown: false,
+ trackersShown: false,
+ peersShown: false
+ };
+ }
+
+ toggleTorrentState(torrent) {
+ if (torrent.status === "paused") {
+ ws_send("RESUME_TORRENT", { id: torrent.id });
+ } else {
+ ws_send("PAUSE_TORRENT", { id: torrent.id });
+ }
+ }
+
+ render() {
+ const { torrent, files } = this.props;
+ const status = s => s[0].toUpperCase() + s.slice(1);
+
+ return (
+
+
{torrent.name}
+
+
+ State:
+
+ {status(torrent.status)}
+
+
+
+
+ this.setState({ infoShown: !this.state.infoShown })}
+ open={this.state.infoShown}
+ />
+ this.setState({ filesShown: !this.state.filesShown })}
+ open={this.state.filesShown}
+ />
+ this.setState({ trackersShown: !this.state.trackersShown })}
+ open={this.state.trackersShown}
+ />
+ this.setState({ peersShown: !this.state.peersShown })}
+ open={this.state.peersShown}
+ />
+
+
+
+ - Downloading to
+ - {torrent.path}
+ - Created
+ - {torrent.created}
+
+
+
+
+
+
+
+ {files.map(file => )}
+
+
+
+
+
+
+ );
+ }
+}
+
class TorrentDetails extends Component {
constructor() {
super();
@@ -34,13 +148,13 @@ class TorrentDetails extends Component {
{active.length} torrents
- {' '}
- {' '}
+
+
this.setState({ removeDropdown: !this.state.removeDropdown })}
>
-
+
Remove
@@ -56,10 +170,17 @@ class TorrentDetails extends Component {
render() {
const active = activeTorrents();
const { torrents } = this.props;
+ const { files } = this.props;
+ const _files = Object.values(files).reduce((s, f) => ({
+ ...s, [f.torrent_id]: [...(s[f.torrent_id] || []), f]
+ }), {});
return (
{active.length > 1 ? this.renderHeader(active) : null}
- {active.map(id => )}
+ {active.map(id => )}
);
}
@@ -67,5 +188,6 @@ class TorrentDetails extends Component {
export default connect(state => ({
router: state.router,
- torrents: state.torrents
+ torrents: state.torrents,
+ files: state.files
}))(TorrentDetails);
diff --git a/src/ui/torrent_table.js b/src/ui/torrent_table.js
index e582ded..6dee8ef 100644
--- a/src/ui/torrent_table.js
+++ b/src/ui/torrent_table.js
@@ -33,7 +33,7 @@ class TorrentTable extends Component {
{Object.values(torrents).map(t =>
|