summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2020-02-06 16:20:41 +0100
committerOskar Nyberg <oskar@mullvad.net>2020-02-06 16:20:41 +0100
commit42442bb8701b2e976dc73e4b4d3a1308732cdcab (patch)
tree2c50a37f4de3b574e40acab9342dcbaee7d6d983
parent033e58637a99a84a7ace29ff1c23bf7c3b456d48 (diff)
parent17bf4b6afdaff028ffc8b11d16a8e4b0e50a1a16 (diff)
downloadmullvadvpn-42442bb8701b2e976dc73e4b4d3a1308732cdcab.tar.xz
mullvadvpn-42442bb8701b2e976dc73e4b4d3a1308732cdcab.zip
Merge branch 'desktop-add-reconnect-button'
-rw-r--r--CHANGELOG.md3
-rw-r--r--gui/assets/images/icon-reload.svg1
-rw-r--r--gui/src/main/daemon-rpc.ts4
-rw-r--r--gui/src/main/index.ts1
-rw-r--r--gui/src/renderer/app.tsx4
-rw-r--r--gui/src/renderer/components/Connect.tsx2
-rw-r--r--gui/src/renderer/components/TunnelControl.tsx37
-rw-r--r--gui/src/renderer/containers/ConnectPage.tsx7
-rw-r--r--gui/src/shared/ipc-event-channel.ts5
9 files changed, 59 insertions, 5 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8042ac35e5..06743eb420 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,9 @@ Line wrap the file at 100 chars. Th
## [Unreleased]
+### Added
+- Add reconnect button to the desktop app
+
### Changed
- Change project copyright and company name from Amagicom AB to Mullvad VPN AB
- Only reconnect when settings change if a relevant tunnel protocol is used.
diff --git a/gui/assets/images/icon-reload.svg b/gui/assets/images/icon-reload.svg
new file mode 100644
index 0000000000..33c7e5ec2c
--- /dev/null
+++ b/gui/assets/images/icon-reload.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="feather feather-rotate-cw"><polyline points="23 4 23 10 17 10"></polyline><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path></svg> \ No newline at end of file
diff --git a/gui/src/main/daemon-rpc.ts b/gui/src/main/daemon-rpc.ts
index 78748b70ab..7491b20901 100644
--- a/gui/src/main/daemon-rpc.ts
+++ b/gui/src/main/daemon-rpc.ts
@@ -496,6 +496,10 @@ export class DaemonRpc {
await this.transport.send('disconnect');
}
+ public async reconnectTunnel(): Promise<void> {
+ await this.transport.send('reconnect');
+ }
+
public async getLocation(): Promise<ILocation | undefined> {
const response = await this.transport.send('get_current_location', [], NETWORK_CALL_TIMEOUT);
try {
diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts
index a335a9f372..6663a5574e 100644
--- a/gui/src/main/index.ts
+++ b/gui/src/main/index.ts
@@ -943,6 +943,7 @@ class ApplicationMain {
IpcMainEventChannel.tunnel.handleConnect(() => this.daemonRpc.connectTunnel());
IpcMainEventChannel.tunnel.handleDisconnect(() => this.daemonRpc.disconnectTunnel());
+ IpcMainEventChannel.tunnel.handleReconnect(() => this.daemonRpc.reconnectTunnel());
IpcMainEventChannel.guiSettings.handleEnableSystemNotifications((flag: boolean) => {
this.guiSettings.enableSystemNotifications = flag;
diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx
index 5fb48f701f..58243ce22a 100644
--- a/gui/src/renderer/app.tsx
+++ b/gui/src/renderer/app.tsx
@@ -276,6 +276,10 @@ export default class AppRenderer {
return IpcRendererEventChannel.tunnel.disconnect();
}
+ public reconnectTunnel(): Promise<void> {
+ return IpcRendererEventChannel.tunnel.reconnect();
+ }
+
public updateRelaySettings(relaySettings: RelaySettingsUpdate) {
return IpcRendererEventChannel.settings.updateRelaySettings(relaySettings);
}
diff --git a/gui/src/renderer/components/Connect.tsx b/gui/src/renderer/components/Connect.tsx
index 7f73fb7ea0..4cb63c6a5b 100644
--- a/gui/src/renderer/components/Connect.tsx
+++ b/gui/src/renderer/components/Connect.tsx
@@ -23,6 +23,7 @@ interface IProps {
onSelectLocation: () => void;
onConnect: () => void;
onDisconnect: () => void;
+ onReconnect: () => void;
onExternalLinkWithAuth: (url: string) => Promise<void>;
}
@@ -163,6 +164,7 @@ export default class Connect extends Component<IProps, IState> {
country={this.props.connection.country}
onConnect={this.props.onConnect}
onDisconnect={this.props.onDisconnect}
+ onReconnect={this.props.onReconnect}
onSelectLocation={this.props.onSelectLocation}
/>
diff --git a/gui/src/renderer/components/TunnelControl.tsx b/gui/src/renderer/components/TunnelControl.tsx
index 700603bd2e..5fbfaebc86 100644
--- a/gui/src/renderer/components/TunnelControl.tsx
+++ b/gui/src/renderer/components/TunnelControl.tsx
@@ -5,6 +5,7 @@ import { TunnelState } from '../../shared/daemon-rpc-types';
import { messages } from '../../shared/gettext';
import ConnectionPanelContainer from '../containers/ConnectionPanelContainer';
import * as AppButton from './AppButton';
+import ImageView from './ImageView';
import SecuredLabel, { SecuredDisplayStyle } from './SecuredLabel';
interface ITunnelControlProps {
@@ -14,6 +15,7 @@ interface ITunnelControlProps {
country?: string;
onConnect: () => void;
onDisconnect: () => void;
+ onReconnect: () => void;
onSelectLocation: () => void;
}
@@ -58,6 +60,16 @@ const styles = {
letterSpacing: -0.9,
color: colors.white,
}),
+ button_row: Styles.createViewStyle({
+ flexDirection: 'row',
+ }),
+ large_button: Styles.createViewStyle({
+ flex: 1,
+ }),
+ reconnect_button: Styles.createViewStyle({
+ marginLeft: 16,
+ paddingHorizontal: 12,
+ }),
};
export default class TunnelControl extends Component<ITunnelControlProps> {
@@ -94,17 +106,23 @@ export default class TunnelControl extends Component<ITunnelControlProps> {
);
const Disconnect = () => (
- <AppButton.RedTransparentButton onPress={this.props.onDisconnect}>
+ <AppButton.RedTransparentButton onPress={this.props.onDisconnect} style={styles.large_button}>
{messages.pgettext('tunnel-control', 'Disconnect')}
</AppButton.RedTransparentButton>
);
const Cancel = () => (
- <AppButton.RedTransparentButton onPress={this.props.onDisconnect}>
+ <AppButton.RedTransparentButton onPress={this.props.onDisconnect} style={styles.large_button}>
{messages.pgettext('tunnel-control', 'Cancel')}
</AppButton.RedTransparentButton>
);
+ const Reconnect = () => (
+ <AppButton.TransparentButton onPress={this.props.onReconnect} style={styles.reconnect_button}>
+ <ImageView height={22} width={22} source="icon-reload" tintColor="white" />
+ </AppButton.TransparentButton>
+ );
+
const Secured = ({ displayStyle }: { displayStyle: SecuredDisplayStyle }) => (
<SecuredLabel style={styles.status_security} displayStyle={displayStyle} />
);
@@ -148,7 +166,10 @@ export default class TunnelControl extends Component<ITunnelControlProps> {
</Body>
<Footer>
<SwitchLocation />
- <Cancel />
+ <View style={styles.button_row}>
+ <Cancel />
+ <Reconnect />
+ </View>
</Footer>
</Wrapper>
);
@@ -165,7 +186,10 @@ export default class TunnelControl extends Component<ITunnelControlProps> {
</Body>
<Footer>
<SwitchLocation />
- <Disconnect />
+ <View style={styles.button_row}>
+ <Disconnect />
+ <Reconnect />
+ </View>
</Footer>
</Wrapper>
);
@@ -178,7 +202,10 @@ export default class TunnelControl extends Component<ITunnelControlProps> {
</Body>
<Footer>
<SwitchLocation />
- <Cancel />
+ <View style={styles.button_row}>
+ <Cancel />
+ <Reconnect />
+ </View>
</Footer>
</Wrapper>
);
diff --git a/gui/src/renderer/containers/ConnectPage.tsx b/gui/src/renderer/containers/ConnectPage.tsx
index e5261a161a..e4c37f19cc 100644
--- a/gui/src/renderer/containers/ConnectPage.tsx
+++ b/gui/src/renderer/containers/ConnectPage.tsx
@@ -99,6 +99,13 @@ const mapDispatchToProps = (dispatch: ReduxDispatch, props: IAppContext) => {
log.error(`Failed to disconnect the tunnel: ${error.message}`);
}
},
+ onReconnect: async () => {
+ try {
+ await props.app.reconnectTunnel();
+ } catch (error) {
+ log.error(`Failed to reconnect the tunnel: ${error.message}`);
+ }
+ },
onExternalLinkWithAuth: (url: string) => props.app.openLinkWithAuth(url),
};
};
diff --git a/gui/src/shared/ipc-event-channel.ts b/gui/src/shared/ipc-event-channel.ts
index a612660c99..5502a6698a 100644
--- a/gui/src/shared/ipc-event-channel.ts
+++ b/gui/src/shared/ipc-event-channel.ts
@@ -56,11 +56,13 @@ interface IReceiver<T> {
interface ITunnelMethods extends IReceiver<TunnelState> {
connect(): Promise<void>;
disconnect(): Promise<void>;
+ reconnect(): Promise<void>;
}
interface ITunnelHandlers extends ISender<TunnelState> {
handleConnect(fn: () => Promise<void>): void;
handleDisconnect(fn: () => Promise<void>): void;
+ handleReconnect(fn: () => Promise<void>): void;
}
interface ISettingsMethods extends IReceiver<ISettings> {
@@ -150,6 +152,7 @@ const DAEMON_DISCONNECTED = 'daemon-disconnected';
const TUNNEL_STATE_CHANGED = 'tunnel-state-changed';
const CONNECT_TUNNEL = 'connect-tunnel';
const DISCONNECT_TUNNEL = 'disconnect-tunnel';
+const RECONNECT_TUNNEL = 'reconnect-tunnel';
const SETTINGS_CHANGED = 'settings-changed';
const SET_ALLOW_LAN = 'set-allow-lan';
@@ -223,6 +226,7 @@ export class IpcRendererEventChannel {
listen: listen(TUNNEL_STATE_CHANGED),
connect: requestSender(CONNECT_TUNNEL),
disconnect: requestSender(DISCONNECT_TUNNEL),
+ reconnect: requestSender(RECONNECT_TUNNEL),
};
public static settings: ISettingsMethods = {
@@ -315,6 +319,7 @@ export class IpcMainEventChannel {
notify: sender(TUNNEL_STATE_CHANGED),
handleConnect: requestHandler(CONNECT_TUNNEL),
handleDisconnect: requestHandler(DISCONNECT_TUNNEL),
+ handleReconnect: requestHandler(RECONNECT_TUNNEL),
};
public static location: ISender<ILocation> = {