summaryrefslogtreecommitdiffhomepage
path: root/gui/src/renderer/components
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2021-05-20 10:19:10 +0200
committerOskar Nyberg <oskar@mullvad.net>2021-05-21 10:38:59 +0200
commit5a8a3fc7f615ab13fe38e28908a9b09383bff086 (patch)
treecd8f6a13afba068d41d9b9738c18cf87fda68ddf /gui/src/renderer/components
parent25fe65cea4876a780ddf87da0576802951d32eff (diff)
downloadmullvadvpn-5a8a3fc7f615ab13fe38e28908a9b09383bff086.tar.xz
mullvadvpn-5a8a3fc7f615ab13fe38e28908a9b09383bff086.zip
Add ad/tracker blocking settings to desktop app
Diffstat (limited to 'gui/src/renderer/components')
-rw-r--r--gui/src/renderer/components/AdvancedSettings.tsx81
-rw-r--r--gui/src/renderer/components/Preferences.tsx90
-rw-r--r--gui/src/renderer/components/PreferencesStyles.tsx6
3 files changed, 158 insertions, 19 deletions
diff --git a/gui/src/renderer/components/AdvancedSettings.tsx b/gui/src/renderer/components/AdvancedSettings.tsx
index a81981263a..ef59798a46 100644
--- a/gui/src/renderer/components/AdvancedSettings.tsx
+++ b/gui/src/renderer/components/AdvancedSettings.tsx
@@ -42,6 +42,7 @@ import {
import Selector, { ISelectorItem } from './cell/Selector';
import SettingsHeader, { HeaderTitle } from './SettingsHeader';
import Accordion from './Accordion';
+import { formatMarkdown } from '../markdown-formatter';
const MIN_MSSFIX_VALUE = 1000;
const MAX_MSSFIX_VALUE = 1450;
@@ -448,7 +449,7 @@ export default class AdvancedSettings extends React.Component<IProps, IState> {
)}
</StyledButtonCellGroup>
- <StyledCustomDnsSwitchContainer>
+ <StyledCustomDnsSwitchContainer disabled={!this.customDnsAvailable()}>
<AriaInputGroup>
<AriaLabel>
<Cell.InputLabel>
@@ -458,13 +459,17 @@ export default class AdvancedSettings extends React.Component<IProps, IState> {
<AriaInput>
<Cell.Switch
ref={this.customDnsSwitchRef}
- isOn={this.props.dns.custom || this.state.showAddCustomDns}
+ isOn={this.props.dns.state === 'custom' || this.state.showAddCustomDns}
onChange={this.setCustomDnsEnabled}
/>
</AriaInput>
</AriaInputGroup>
</StyledCustomDnsSwitchContainer>
- <Accordion expanded={this.props.dns.custom || this.state.showAddCustomDns}>
+ <Accordion
+ expanded={
+ this.customDnsAvailable() &&
+ (this.props.dns.state === 'custom' || this.state.showAddCustomDns)
+ }>
<CellList items={this.customDnsItems()} onRemove={this.removeDnsAddress} />
{this.state.showAddCustomDns && (
@@ -502,9 +507,13 @@ export default class AdvancedSettings extends React.Component<IProps, IState> {
<StyledCustomDnsFotter>
<Cell.FooterText>
- {messages.pgettext(
- 'advanced-settings-view',
- 'Enable to add at least one DNS server.',
+ {this.customDnsAvailable() ? (
+ messages.pgettext(
+ 'advanced-settings-view',
+ 'Enable to add at least one DNS server.',
+ )
+ ) : (
+ <CustomDnsDisabledMessage />
)}
</Cell.FooterText>
</StyledCustomDnsFotter>
@@ -520,15 +529,22 @@ export default class AdvancedSettings extends React.Component<IProps, IState> {
);
}
+ private customDnsAvailable(): boolean {
+ return (
+ this.props.dns.state === 'custom' ||
+ (!this.props.dns.defaultOptions.blockAds && !this.props.dns.defaultOptions.blockTrackers)
+ );
+ }
+
private setCustomDnsEnabled = async (enabled: boolean) => {
- if (this.props.dns.addresses.length > 0) {
+ if (this.props.dns.customOptions.addresses.length > 0) {
await this.props.setDnsOptions({
- custom: enabled,
- addresses: this.props.dns.addresses,
+ ...this.props.dns,
+ state: enabled ? 'custom' : 'default',
});
}
- if (enabled && this.props.dns.addresses.length === 0) {
+ if (enabled && this.props.dns.customOptions.addresses.length === 0) {
this.showAddCustomDnsRow();
}
@@ -538,7 +554,7 @@ export default class AdvancedSettings extends React.Component<IProps, IState> {
};
private customDnsItems(): ICellListItem<string>[] {
- return this.props.dns.addresses.map((address) => ({
+ return this.props.dns.customOptions.addresses.map((address) => ({
label: address,
value: address,
}));
@@ -589,8 +605,12 @@ export default class AdvancedSettings extends React.Component<IProps, IState> {
if (ipAddress.isLocal() || confirmed) {
await this.props.setDnsOptions({
- custom: this.props.dns.custom || this.state.showAddCustomDns,
- addresses: [...this.props.dns.addresses, address],
+ ...this.props.dns,
+ state:
+ this.props.dns.state === 'custom' || this.state.showAddCustomDns ? 'custom' : 'default',
+ customOptions: {
+ addresses: [...this.props.dns.customOptions.addresses, address],
+ },
});
this.hideAddCustomDnsRow();
} else {
@@ -602,11 +622,14 @@ export default class AdvancedSettings extends React.Component<IProps, IState> {
};
private removeDnsAddress = (address: string) => {
- const addresses = this.props.dns.addresses.filter((item) => item !== address);
+ const addresses = this.props.dns.customOptions.addresses.filter((item) => item !== address);
consumePromise(
this.props.setDnsOptions({
- custom: addresses.length > 0 && this.props.dns.custom,
- addresses,
+ ...this.props.dns,
+ state: addresses.length > 0 && this.props.dns.state === 'custom' ? 'custom' : 'default',
+ customOptions: {
+ addresses,
+ },
}),
);
};
@@ -758,3 +781,29 @@ export default class AdvancedSettings extends React.Component<IProps, IState> {
);
}
}
+
+function CustomDnsDisabledMessage() {
+ const blockAdsFeatureName = messages.pgettext('preferences-view', 'Block ads');
+ const blockTrackersFeatureName = messages.pgettext('preferences-view', 'Block trackers');
+ const preferencesPageName = messages.pgettext('preferences-nav', 'Preferences');
+
+ // TRANSLATORS: This is displayed when either or both of the block ads/trackers settings are
+ // TRANSLATORS: turned on which makes the custom DNS setting disabled. The text enclosed in "**"
+ // TRANSLATORS: will appear bold.
+ // TRANSLATORS: Available placeholders:
+ // TRANSLATORS: %(blockAdsFeatureName)s - The name displayed next to the "Block ads" toggle.
+ // TRANSLATORS: %(blockTrackersFeatureName)s - The name displayed next to the "Block trackers" toggle.
+ // TRANSLATORS: %(preferencesPageName)s - The page title showed on top in the preferences page.
+ const customDnsDisabledMessage = messages.pgettext(
+ 'preferences-view',
+ 'Disable **%(blockAdsFeatureName)s** and **%(blockTrackersFeatureName)s** (under %(preferencesPageName)s) to activate this setting.',
+ );
+
+ return formatMarkdown(
+ sprintf(customDnsDisabledMessage, {
+ blockAdsFeatureName,
+ blockTrackersFeatureName,
+ preferencesPageName,
+ }),
+ );
+}
diff --git a/gui/src/renderer/components/Preferences.tsx b/gui/src/renderer/components/Preferences.tsx
index d47a7315c6..c91330aee0 100644
--- a/gui/src/renderer/components/Preferences.tsx
+++ b/gui/src/renderer/components/Preferences.tsx
@@ -1,5 +1,8 @@
import * as React from 'react';
+import { sprintf } from 'sprintf-js';
+import { IDnsOptions } from '../../shared/daemon-rpc-types';
import { messages } from '../../shared/gettext';
+import { formatMarkdown } from '../markdown-formatter';
import { AriaDescription, AriaInput, AriaInputGroup, AriaLabel } from './AriaGroup';
import * as Cell from './cell';
import { Layout } from './Layout';
@@ -24,6 +27,7 @@ export interface IProps {
monochromaticIcon: boolean;
startMinimized: boolean;
unpinnedWindow: boolean;
+ dns: IDnsOptions;
setAutoStart: (autoStart: boolean) => void;
setEnableSystemNotifications: (flag: boolean) => void;
setAutoConnect: (autoConnect: boolean) => void;
@@ -32,6 +36,7 @@ export interface IProps {
setStartMinimized: (startMinimized: boolean) => void;
setMonochromaticIcon: (monochromaticIcon: boolean) => void;
setUnpinnedWindow: (unpinnedWindow: boolean) => void;
+ setDnsOptions: (dns: IDnsOptions) => Promise<void>;
onClose: () => void;
}
@@ -105,6 +110,47 @@ export default class Preferences extends React.Component<IProps> {
</AriaInputGroup>
<AriaInputGroup>
+ <Cell.Container disabled={this.props.dns.state === 'custom'}>
+ <AriaLabel>
+ <Cell.InputLabel>
+ {messages.pgettext('preferences-view', 'Block ads')}
+ </Cell.InputLabel>
+ </AriaLabel>
+ <AriaInput>
+ <Cell.Switch
+ isOn={
+ this.props.dns.state === 'default' &&
+ this.props.dns.defaultOptions.blockAds
+ }
+ onChange={this.setBlockAds}
+ />
+ </AriaInput>
+ </Cell.Container>
+ </AriaInputGroup>
+ <StyledSeparator />
+ <AriaInputGroup>
+ <Cell.Container disabled={this.props.dns.state === 'custom'}>
+ <AriaLabel>
+ <Cell.InputLabel>
+ {messages.pgettext('preferences-view', 'Block trackers')}
+ </Cell.InputLabel>
+ </AriaLabel>
+ <AriaInput>
+ <Cell.Switch
+ isOn={
+ this.props.dns.state === 'default' &&
+ this.props.dns.defaultOptions.blockTrackers
+ }
+ onChange={this.setBlockTrackers}
+ />
+ </AriaInput>
+ </Cell.Container>
+ {this.props.dns.state === 'custom' && <CustomDnsEnabledFooter />}
+ </AriaInputGroup>
+
+ {this.props.dns.state !== 'custom' && <StyledSeparator height={20} />}
+
+ <AriaInputGroup>
<Cell.Container>
<AriaLabel>
<Cell.InputLabel>
@@ -275,4 +321,48 @@ export default class Preferences extends React.Component<IProps> {
</Layout>
);
}
+
+ private setBlockAds = async (enabled: boolean) => {
+ await this.props.setDnsOptions({
+ ...this.props.dns,
+ defaultOptions: {
+ ...this.props.dns.defaultOptions,
+ blockAds: enabled,
+ },
+ });
+ };
+
+ private setBlockTrackers = async (enabled: boolean) => {
+ await this.props.setDnsOptions({
+ ...this.props.dns,
+ defaultOptions: {
+ ...this.props.dns.defaultOptions,
+ blockTrackers: enabled,
+ },
+ });
+ };
+}
+
+function CustomDnsEnabledFooter() {
+ const customDnsFeatureName = messages.pgettext('advanced-settings-view', 'Use custom DNS server');
+
+ // TRANSLATORS: This is displayed when the custom DNS setting is turned on which makes the block
+ // TRANSLATORS: ads/trackers settings disabled. The text enclosed in "**" will appear bold.
+ // TRANSLATORS: Advanced settings refer to the name of the page with the title "Advanced".
+ // TRANSLATORS: Available placeholders:
+ // TRANSLATORS: %(customDnsFeatureName)s - The name displayed next to the custom DNS toggle.
+ const blockingDisabledText = messages.pgettext(
+ 'preferences-view',
+ 'Disable **%(customDnsFeatureName)s** (under Advanced settings) to activate these settings.',
+ );
+
+ return (
+ <Cell.Footer>
+ <AriaDescription>
+ <Cell.FooterText>
+ {formatMarkdown(sprintf(blockingDisabledText, { customDnsFeatureName }))}
+ </Cell.FooterText>
+ </AriaDescription>
+ </Cell.Footer>
+ );
}
diff --git a/gui/src/renderer/components/PreferencesStyles.tsx b/gui/src/renderer/components/PreferencesStyles.tsx
index b9986f2c38..f4fa114469 100644
--- a/gui/src/renderer/components/PreferencesStyles.tsx
+++ b/gui/src/renderer/components/PreferencesStyles.tsx
@@ -13,6 +13,6 @@ export const StyledContent = styled.div({
marginBottom: '2px',
});
-export const StyledSeparator = styled.div({
- height: '1px',
-});
+export const StyledSeparator = styled.div((props: { height?: number }) => ({
+ height: `${props.height ?? 1}px`,
+}));