summaryrefslogtreecommitdiffhomepage
path: root/app/components
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@codeispoetry.ru>2017-02-17 15:17:20 +0000
committerAndrej Mihajlov <and@codeispoetry.ru>2017-02-17 15:17:20 +0000
commit00b82cb3aa904b34d7000854bcecd3b72e012c8e (patch)
treeac314579a84d6c5b6fbbda8f0a0984f023364870 /app/components
parente88018b890c8ddf62895101439d57ca206d9379b (diff)
downloadmullvadvpn-00b82cb3aa904b34d7000854bcecd3b72e012c8e.tar.xz
mullvadvpn-00b82cb3aa904b34d7000854bcecd3b72e012c8e.zip
Add switch control and hook up settings reducer & actions
Diffstat (limited to 'app/components')
-rw-r--r--app/components/Settings.css2
-rw-r--r--app/components/Settings.js11
-rw-r--r--app/components/Switch.css44
-rw-r--r--app/components/Switch.js107
4 files changed, 161 insertions, 3 deletions
diff --git a/app/components/Settings.css b/app/components/Settings.css
index 30186446e4..350ae406a5 100644
--- a/app/components/Settings.css
+++ b/app/components/Settings.css
@@ -101,7 +101,7 @@
}
.settings__cell-value {
-
+ flex: 0 0 auto;
}
.settings__cell-footer {
diff --git a/app/components/Settings.js b/app/components/Settings.js
index 5b36d8a64c..8089482f02 100644
--- a/app/components/Settings.js
+++ b/app/components/Settings.js
@@ -1,16 +1,23 @@
import React, { Component, PropTypes } from 'react';
import { Layout, Container, Header } from './Layout';
+import Switch from './Switch';
export default class Settings extends Component {
static propTypes = {
- logout: PropTypes.func.isRequired
+ logout: PropTypes.func.isRequired,
+ updateSettings: PropTypes.func.isRequired
}
onClose() {
this.props.router.push('/connect');
}
+ handleAutoSecure(isOn) {
+ console.log('autoSecure: ' + isOn);
+ this.props.updateSettings({ autoSecure: isOn });
+ }
+
render() {
return (
<Layout>
@@ -31,7 +38,7 @@ export default class Settings extends Component {
<div className="settings__cell">
<div className="settings__cell-label">Auto-secure</div>
<div className="settings__cell-value">
- <input type="checkbox" className="settings__switch" />
+ <Switch onChange={ ::this.handleAutoSecure } isOn={ this.props.settings.autoSecure } />
</div>
</div>
<div className="settings__cell-footer">
diff --git a/app/components/Switch.css b/app/components/Switch.css
new file mode 100644
index 0000000000..961312c103
--- /dev/null
+++ b/app/components/Switch.css
@@ -0,0 +1,44 @@
+.switch {
+ display: block;
+ position: relative;
+ -webkit-appearance: none;
+ border-radius: 16px;
+ width: 50px;
+ height: 30px;
+ border: 2px solid white;
+ background-color: transparent;
+ transition: 300ms ease-in-out all;
+}
+
+.switch:checked {
+ text-align: right;
+}
+
+.switch::after {
+ position: absolute;
+ left: 1px;
+ top: 1px;
+ display: block;
+ content: '';
+ width: 24px;
+ height: 24px;
+ border-radius: 24px;
+ background-color: #D0021B;
+ transition: 300ms ease-in-out all;
+ transform: translate3d(0, 0, 0);
+}
+
+.switch:active::after {
+ width: 28px;
+}
+
+.switch:active:checked::after {
+ transform: translate3d(0, 0, 0);
+ left: 17px;
+}
+
+.switch:checked::after {
+ background-color: #44AD4D;
+ transform: translate3d(0, 0, 0);
+ left: 21px;
+} \ No newline at end of file
diff --git a/app/components/Switch.js b/app/components/Switch.js
new file mode 100644
index 0000000000..16b64b2211
--- /dev/null
+++ b/app/components/Switch.js
@@ -0,0 +1,107 @@
+import React, { Component, PropTypes } from 'react';
+
+export default class Switch extends Component {
+
+ static propTypes = {
+ isOn: PropTypes.bool,
+ onChange: PropTypes.func
+ }
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ isTracking: false,
+ ignoreChange: false,
+ initialPos: null,
+ startTime: null,
+ target: null
+ };
+ }
+
+ handleMouseDown(e) {
+ const { pageX: x, pageY: y } = e;
+ this.setState({
+ isTracking: true,
+ initialPos: { x, y },
+ startTime: e.timeStamp
+ });
+ }
+
+ handleMouseMove(e) {
+ if(!this.state.isTracking) {
+ return;
+ }
+
+ const thresholdX = 10, thresholdY = 50;
+ const { x: x0, y: y0 } = this.state.initialPos;
+ const { pageX: x, pageY: y } = e;
+
+ const dx = Math.abs(x0 - x);
+ const dy = Math.abs(y0 - y);
+
+ if(dx < thresholdX || dy > thresholdY) {
+ return;
+ }
+
+ const isOn = !!this.props.isOn;
+ let nextOn = isOn;
+
+ if(x < x0 && isOn) {
+ nextOn = false;
+ } else if(x > x0 && !isOn) {
+ nextOn = true;
+ }
+
+ if(isOn !== nextOn) {
+ this.setState({ initialPos: { x, y } });
+ this.refs.input.checked = nextOn;
+ this.notify(nextOn);
+ this.setState({ ignoreChange: true });
+ }
+ }
+
+ handleMouseUp() {
+ if(this.state.isTracking) {
+ this.setState({ isTracking: false, initialPos: null });
+ console.log('mouseup');
+ }
+ }
+
+ handleChange(e) {
+ console.log('ONCHANGE ' + e.target.checked);
+ const delta = e.timeStamp - this.state.startTime;
+ const threshold = 1000;
+
+ if(this.state.ignoreChange) {
+ e.preventDefault();
+ this.setState({ ignoreChange: false });
+ } else if(delta > threshold) {
+ e.preventDefault();
+ } else {
+ this.notify(e.target.checked);
+ }
+ }
+
+ notify(isOn) {
+ if(this.props.onChange) {
+ this.props.onChange(isOn);
+ }
+ }
+
+ componentDidMount() {
+ document.addEventListener('mousemove', ::this.handleMouseMove);
+ document.addEventListener('mouseup', ::this.handleMouseUp);
+ }
+
+ componentWillUnmount() {
+ document.removeEventListener('mousemove', ::this.handleMouseMove);
+ document.removeEventListener('mouseup', ::this.handleMouseUp);
+ }
+
+ render() {
+ return (
+ <input type="checkbox" ref="input" className="switch" checked={ this.props.isOn }
+ onMouseDown={ ::this.handleMouseDown } onChange={ ::this.handleChange } />
+ );
+ }
+} \ No newline at end of file