mirror of
https://github.com/zoriya/flood.git
synced 2026-05-27 17:11:58 +00:00
Add settings modal with speed limit presets
This commit is contained in:
@@ -41,7 +41,10 @@ export default class Modal extends React.Component {
|
||||
let content = this.props.content;
|
||||
let footer = null;
|
||||
let contentClasses = classnames('modal__content__wrapper',
|
||||
`modal--align-${this.props.alignment}`);
|
||||
`modal--align-${this.props.alignment}`, {
|
||||
'modal--orientation--horizontal': this.props.orientation === 'horizontal',
|
||||
'modal--orientation--vertical': this.props.orientation === 'vertical'
|
||||
}, this.props.classNames);
|
||||
let headerClasses = classnames('modal__header', {
|
||||
'has-tabs': this.props.tabs
|
||||
});
|
||||
@@ -58,7 +61,10 @@ export default class Modal extends React.Component {
|
||||
}
|
||||
|
||||
if (this.props.actions) {
|
||||
footer = <ModalActions actions={this.props.actions} dismiss={this.props.dismiss} />;
|
||||
footer = (
|
||||
<ModalActions actions={this.props.actions}
|
||||
dismiss={this.props.dismiss} />
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -79,5 +85,7 @@ export default class Modal extends React.Component {
|
||||
}
|
||||
|
||||
Modal.defaultProps = {
|
||||
alignment: 'left'
|
||||
alignment: 'left',
|
||||
classNames: null,
|
||||
orientation: 'horizontal'
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ import ConfirmModal from './ConfirmModal';
|
||||
import EventTypes from '../../constants/EventTypes';
|
||||
import Modal from './Modal';
|
||||
import MoveTorrents from './MoveTorrents';
|
||||
import SettingsModal from './SettingsModal';
|
||||
import UIActions from '../../actions/UIActions';
|
||||
import UIStore from '../../stores/UIStore';
|
||||
|
||||
@@ -23,7 +24,8 @@ export default class Modals extends React.Component {
|
||||
this.modals = {
|
||||
confirm: ConfirmModal,
|
||||
'move-torrents': MoveTorrents,
|
||||
'add-torrents': AddTorrents
|
||||
'add-torrents': AddTorrents,
|
||||
'settings': SettingsModal
|
||||
};
|
||||
|
||||
this.state = {
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
import classnames from 'classnames';
|
||||
import React from 'react';
|
||||
|
||||
import EventTypes from '../../constants/EventTypes';
|
||||
import Modal from './Modal';
|
||||
import SettingsSpeedLimit from './SettingsSpeedLimit';
|
||||
import SettingsStore from '../../stores/SettingsStore';
|
||||
|
||||
const METHODS_TO_BIND = [
|
||||
'handleSettingsChange',
|
||||
'handleSaveSettingsClick',
|
||||
'handleSettingsFetchRequestSuccess'
|
||||
];
|
||||
|
||||
export default class AddTorrents extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
settings: {
|
||||
speedLimits: {
|
||||
download: null,
|
||||
upload: null
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
METHODS_TO_BIND.forEach((method) => {
|
||||
this[method] = this[method].bind(this);
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
SettingsStore.listen(EventTypes.SETTINGS_FETCH_REQUEST_SUCCESS, this.handleSettingsFetchRequestSuccess);
|
||||
SettingsStore.fetchSettings(EventTypes.SETTINGS_FETCH_REQUEST_ERROR, this.handleSettingsFetchRequestError);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
SettingsStore.unlisten(EventTypes.SETTINGS_FETCH_REQUEST_SUCCESS, this.handleSettingsFetchRequestSuccess);
|
||||
}
|
||||
|
||||
getActions() {
|
||||
let icon = null;
|
||||
let primaryButtonText = 'Add Torrent';
|
||||
|
||||
if (this.state.isAddingTorrents) {
|
||||
icon = <LoadingIndicatorDots viewBox="0 0 32 32" />;
|
||||
primaryButtonText = 'Adding...';
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
clickHandler: null,
|
||||
content: 'Cancel',
|
||||
triggerDismiss: true,
|
||||
type: 'secondary'
|
||||
},
|
||||
{
|
||||
clickHandler: this.handleSaveSettingsClick,
|
||||
content: 'Save Settings',
|
||||
triggerDismiss: false,
|
||||
type: 'primary'
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
handleSaveSettingsClick() {
|
||||
SettingsStore.saveSettings(this.state.settings);
|
||||
}
|
||||
|
||||
handleSettingsFetchRequestError() {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
handleSettingsFetchRequestSuccess() {
|
||||
this.setState({
|
||||
settings: SettingsStore.getSettings()
|
||||
});
|
||||
}
|
||||
|
||||
handleSettingsChange(changedSettings) {
|
||||
let settings = this.mergeObjects(this.state.settings, changedSettings);
|
||||
this.setState({settings});
|
||||
}
|
||||
|
||||
mergeObjects(objA, objB) {
|
||||
Object.keys(objB).forEach((key) => {
|
||||
if (!objB.hasOwnProperty(key) || objB[key] == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If it's an object, then recursive merge.
|
||||
if (!Array.isArray(objB[key]) && !Array.isArray(objB[key]) && typeof objA[key] === 'object' && typeof objB[key] === 'object') {
|
||||
objA[key] = this.mergeObjects(objA[key], objB[key]);
|
||||
} else {
|
||||
objA[key] = objB[key];
|
||||
}
|
||||
});
|
||||
|
||||
return objA;
|
||||
}
|
||||
|
||||
render() {
|
||||
let tabs = {
|
||||
'speed-limit': {
|
||||
content: (
|
||||
<SettingsSpeedLimit onSettingsChange={this.handleSettingsChange}
|
||||
settings={this.state.settings} />
|
||||
),
|
||||
label: 'Speed Limits'
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal actions={this.getActions()} classNames="modal--large"
|
||||
heading="Settings" orientation="vertical" dismiss={this.props.dismiss}
|
||||
tabs={tabs} />
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
import React from 'react';
|
||||
|
||||
const METHODS_TO_BIND = ['handleDownloadTextChange', 'handleUploadTextChange'];
|
||||
|
||||
export default class AddTorrents extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
downloadValue: null,
|
||||
uploadValue: null
|
||||
}
|
||||
|
||||
METHODS_TO_BIND.forEach((method) => {
|
||||
this[method] = this[method].bind(this);
|
||||
});
|
||||
}
|
||||
|
||||
arrayToString(array) {
|
||||
return array.join(', ');
|
||||
}
|
||||
|
||||
getTextboxValue(input = []) {
|
||||
if (Array.isArray(input)) {
|
||||
return this.arrayToString(input);
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
handleDownloadTextChange(event) {
|
||||
this.setState({
|
||||
downloadValue: event.target.value
|
||||
});
|
||||
|
||||
this.props.onSettingsChange({
|
||||
speedLimits: {
|
||||
download: this.processSpeedsForSave(event.target.value)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
handleUploadTextChange(event) {
|
||||
this.setState({
|
||||
uploadValue: event.target.value
|
||||
});
|
||||
|
||||
this.props.onSettingsChange({
|
||||
speedLimits: {
|
||||
upload: this.processSpeedsForSave(event.target.value)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getDownloadValue() {
|
||||
let displayedValue = this.state.downloadValue;
|
||||
|
||||
if (displayedValue == null) {
|
||||
displayedValue = this.processSpeedsForDisplay(this.props.settings.speedLimits.download);
|
||||
}
|
||||
|
||||
return displayedValue;
|
||||
}
|
||||
|
||||
getUploadValue() {
|
||||
let displayedValue = this.state.uploadValue;
|
||||
|
||||
if (displayedValue == null) {
|
||||
displayedValue = this.processSpeedsForDisplay(this.props.settings.speedLimits.upload);
|
||||
}
|
||||
|
||||
return displayedValue;
|
||||
}
|
||||
|
||||
processSpeedsForDisplay(speeds = []) {
|
||||
if (!speeds || speeds.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.arrayToString(speeds.map((speed) => {
|
||||
return Number(speed) / 1024;
|
||||
}));
|
||||
}
|
||||
|
||||
processSpeedsForSave(speeds = '') {
|
||||
if (speeds === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
return this.stringToArray(speeds).map((speed) => {
|
||||
return Number(speed) * 1024;
|
||||
});
|
||||
}
|
||||
|
||||
stringToArray(string = '') {
|
||||
return string.replace(/\s/g, '').split(',');
|
||||
}
|
||||
|
||||
render() {
|
||||
let downloadValue = this.getDownloadValue();
|
||||
let uploadValue = this.getUploadValue();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p className="modal__tab__introduction">
|
||||
Provide a comma-separated list of speed values (in kilobytes per second). 0 represents unlimited.
|
||||
</p>
|
||||
<div className="form">
|
||||
<div className="form__row">
|
||||
<label className="form__label">
|
||||
Download Presets
|
||||
</label>
|
||||
<input className="textbox" type="text"
|
||||
onChange={this.handleDownloadTextChange}
|
||||
value={downloadValue} />
|
||||
</div>
|
||||
<div className="form__row">
|
||||
<label className="form__label">
|
||||
Upload Presets
|
||||
</label>
|
||||
<input className="textbox" type="text"
|
||||
onChange={this.handleUploadTextChange}
|
||||
value={uploadValue} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user