From ad299d3b81f1f76cebda50c613a6f0f7f4dfa5d8 Mon Sep 17 00:00:00 2001 From: Matt Lichtenstein Date: Thu, 18 Jan 2024 14:27:33 -0500 Subject: [PATCH] VPN-4687: Add DNS settings help sheet (#8864) --- nebula/ui/components/MZHelpSheet.qml | 19 +++++-- nebula/ui/components/MZIconButton.qml | 1 + nebula/ui/components/MZMenu.qml | 5 +- nebula/ui/resources/CMakeLists.txt | 2 + nebula/ui/resources/question.svg | 3 + nebula/ui/resources/tip-filled.svg | 11 ++++ src/constants.h | 3 + src/feature/featurelist.h | 7 +++ src/mozillavpn.cpp | 3 + src/translations/strings.yaml | 20 +++++++ src/ui/screens/settings/ViewDNSSettings.qml | 61 +++++++++++++++++---- 11 files changed, 116 insertions(+), 19 deletions(-) create mode 100644 nebula/ui/resources/question.svg create mode 100644 nebula/ui/resources/tip-filled.svg diff --git a/nebula/ui/components/MZHelpSheet.qml b/nebula/ui/components/MZHelpSheet.qml index 1b08557317..7719ad6931 100644 --- a/nebula/ui/components/MZHelpSheet.qml +++ b/nebula/ui/components/MZHelpSheet.qml @@ -23,7 +23,6 @@ import Mozilla.Shared 1.0 /* MZHelpSheet { title: "MZHelpSheet" - iconSource: "qrc:/ui/resources/connection-info-dark.svg" model: [ {type: MZHelpSheet.BlockType.Title, text: "title"}, @@ -39,7 +38,6 @@ import Mozilla.Shared 1.0 MZBottomSheet { id: bottomSheet - property alias iconSource: icon.source property alias title: title.text required property var model @@ -65,6 +63,7 @@ MZBottomSheet { id: headerLayout Layout.topMargin: 8 + Layout.preferredWidth: parent.width spacing: 0 @@ -82,7 +81,8 @@ MZBottomSheet { id: icon anchors.centerIn: parent - sourceSize.width: MZTheme.theme.iconSize + source: "qrc:/nebula/resources/tip-filled.svg" + sourceSize.width: MZTheme.theme.iconSize * 1.5 mirror: MZLocalizer.isRightToLeft fillMode: Image.PreserveAspectFit @@ -96,10 +96,12 @@ MZBottomSheet { Layout.topMargin: MZTheme.theme.windowMargin / 2 Layout.leftMargin: 8 Layout.alignment: Qt.AlignTop + Layout.fillWidth: true verticalAlignment: Text.AlignVCenter lineHeightMode: Text.FixedHeight lineHeight: 24 + elide: Text.ElideRight } Item { @@ -107,13 +109,18 @@ MZBottomSheet { } MZIconButton { - id: iconButton - Layout.rightMargin: MZTheme.theme.windowMargin / 2 Layout.preferredHeight: MZTheme.theme.rowHeight Layout.preferredWidth: MZTheme.theme.rowHeight + //Hacky workaround because for some reason, when opening a sheet via + //the right menu button in MZMenu, this close button is in a + //"Hovered" state, even though it wasn't hovered + //Likely something to do with both icon buttons being in the same position + //Relative to their parent (top right corner) + mouseArea.hoverEnabled: bottomSheet.opened + onClicked: bottomSheet.close() accessibleName: MZI18n.GlobalClose @@ -133,7 +140,7 @@ MZBottomSheet { Rectangle { Layout.topMargin: 8 Layout.preferredHeight: MZTheme.theme.dividerHeight - Layout.preferredWidth: parent.width + Layout.fillWidth: true color: MZTheme.colors.grey10 } diff --git a/nebula/ui/components/MZIconButton.qml b/nebula/ui/components/MZIconButton.qml index 8e602a46e8..6ebdda9b7e 100644 --- a/nebula/ui/components/MZIconButton.qml +++ b/nebula/ui/components/MZIconButton.qml @@ -12,6 +12,7 @@ MZButtonBase { property bool skipEnsureVisible: false property var accessibleName property var buttonColorScheme: MZTheme.theme.iconButtonLightBackground + property alias mouseArea: mouseArea property alias backgroundRadius: uiStates.radius property alias uiStatesVisible: uiStates.visible diff --git a/nebula/ui/components/MZMenu.qml b/nebula/ui/components/MZMenu.qml index 77ce5a35fd..0d86fb2f13 100644 --- a/nebula/ui/components/MZMenu.qml +++ b/nebula/ui/components/MZMenu.qml @@ -103,10 +103,11 @@ Item { sourceComponent: menuBar.rightButtonComponent onItemChanged: { - if (item instanceof Text) { + //item.item is for right button components that might be inside a loader itself + if (item instanceof Text || (item instanceof Loader && item.item instanceof Text)) { anchors.rightMargin = MZTheme.theme.windowMargin } - else if(item instanceof MZIconButton) { + else if(item instanceof MZIconButton || (item instanceof Loader && item.item instanceof MZIconButton)) { anchors.rightMargin = MZTheme.theme.windowMargin / 2 } } diff --git a/nebula/ui/resources/CMakeLists.txt b/nebula/ui/resources/CMakeLists.txt index c780ca5f24..6243591928 100644 --- a/nebula/ui/resources/CMakeLists.txt +++ b/nebula/ui/resources/CMakeLists.txt @@ -71,5 +71,7 @@ qt_add_qml_module(resources info.svg lock.svg startup.svg + question.svg + tip-filled.svg ) diff --git a/nebula/ui/resources/question.svg b/nebula/ui/resources/question.svg new file mode 100644 index 0000000000..bc8c9e258d --- /dev/null +++ b/nebula/ui/resources/question.svg @@ -0,0 +1,3 @@ + + + diff --git a/nebula/ui/resources/tip-filled.svg b/nebula/ui/resources/tip-filled.svg new file mode 100644 index 0000000000..6eede736d6 --- /dev/null +++ b/nebula/ui/resources/tip-filled.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/constants.h b/src/constants.h index cf9d7092d6..aef33c901d 100644 --- a/src/constants.h +++ b/src/constants.h @@ -211,6 +211,9 @@ constexpr const char* GOOGLE_SUBSCRIPTIONS_URL = constexpr const char* MOZILLA_VPN_SUMO_URL = "https://support.mozilla.org/en-US/products/firefox-private-network-vpn"; +constexpr const char* SUMO_DNS = + "https://support.mozilla.org/kb/how-do-i-change-my-dns-settings"; + PRODBETAEXPR(QString, contactSupportUrl, "https://accounts.firefox.com/support", "https://accounts.stage.mozaws.net/support") diff --git a/src/feature/featurelist.h b/src/feature/featurelist.h index ee1cc02b05..1704b8136b 100644 --- a/src/feature/featurelist.h +++ b/src/feature/featurelist.h @@ -89,6 +89,13 @@ FEATURE(gleanRust, // Feature ID QStringList(), // feature dependencies FeatureCallback_true) +FEATURE(helpSheets, // Feature ID + "Help sheets", // Feature name + FeatureCallback_true, // Can be flipped on + FeatureCallback_true, // Can be flipped off + QStringList(), // feature dependencies + FeatureCallback_false) + FEATURE(inAppAccountCreate, // Feature ID "In-app Account Creation", // Feature name FeatureCallback_true, // Can be flipped on diff --git a/src/mozillavpn.cpp b/src/mozillavpn.cpp index 13619beec7..421ac9263b 100644 --- a/src/mozillavpn.cpp +++ b/src/mozillavpn.cpp @@ -1381,6 +1381,9 @@ void MozillaVPN::registerUrlOpenerLabels() { uo->registerUrlLabel("upgradeToAnnualUrl", []() -> QString { return Constants::upgradeToAnnualUrl(); }); + + uo->registerUrlLabel("sumoDns", + []() -> QString { return Constants::SUMO_DNS; }); } void MozillaVPN::errorHandled() { diff --git a/src/translations/strings.yaml b/src/translations/strings.yaml index 89614fdaf5..d218ae2a79 100644 --- a/src/translations/strings.yaml +++ b/src/translations/strings.yaml @@ -953,6 +953,20 @@ devices: value: My devices comment: Title for the menu bar when viewing the devices or device limit pages +helpSheets: + dnsTitle: + value: Custom DNS settings + comment: Title label for the custom dns help sheet + dnsHeader: + value: What is a custom DNS? + comment: Header label for the custom dns help sheet + dnsBody1: + value: Whenever you connect to a website, a DNS (domain name system) first turns the domain name (e.g. www.mozilla.org) into an IP address that allows your internet traffic to reach that destination. + comment: Body text for the custom dns help sheet + dnsBody2: + value: Mozilla VPN allows you to choose a custom DNS server if you prefer. If you use one, you won’t be able to use other privacy features in the VPN like tracker blocking. + comment: Body text for the custom dns help sheet + global: expand: value: Expand @@ -1002,6 +1016,12 @@ global: getStarted: value: Get started comment: Label for a button used to begin something / proceed + help: + value: Help + comment: Action taken that will help the user + learnMore: + value: Learn more + comment: Label for link to allow the user to learn more about a topic getHelp: helpCenter: Help Center diff --git a/src/ui/screens/settings/ViewDNSSettings.qml b/src/ui/screens/settings/ViewDNSSettings.qml index 98e5b54932..370a23f9ef 100644 --- a/src/ui/screens/settings/ViewDNSSettings.qml +++ b/src/ui/screens/settings/ViewDNSSettings.qml @@ -21,6 +21,24 @@ MZViewBase { property bool privacyDialogNeeded: true property bool dnsSelectionChanged: false readonly property string telemetryScreenId : "dns_settings" + property Component rightMenuButton: Component { + Loader { + active: MZFeatureList.get("helpSheets").isSupported + sourceComponent: MZIconButton { + onClicked: helpSheetLoader.active = true + + accessibleName: MZI18n.GlobalHelp + + Image { + anchors.centerIn: parent + + source: "qrc:/nebula/resources/question.svg" + fillMode: Image.PreserveAspectFit + } + } + } + } + function applyFrontendChanges(settingValue) { if (settingValue === MZSettings.Gateway) { @@ -73,7 +91,7 @@ MZViewBase { function reset() { root.customDNS = MZSettings.dnsProviderFlags === MZSettings.Custom; root.privacyDialogNeeded = MZSettings.dnsProviderFlags !== MZSettings.Custom && - MZSettings.dnsProviderFlags !== MZSettings.Gateway; + MZSettings.dnsProviderFlags !== MZSettings.Gateway; ipInput.text = MZSettings.userDNS; } @@ -224,9 +242,9 @@ MZViewBase { } onActiveFocusChanged: { - if (!activeFocus && !ipInput.focusReasonA11y) { - maybeSaveChange(); - } + if (!activeFocus && !ipInput.focusReasonA11y) { + maybeSaveChange(); + } } } @@ -258,8 +276,8 @@ MZViewBase { Component.onCompleted: { Glean.impression.dnsSettingsScreen.record({ - screen: telemetryScreenId, - }); + screen: telemetryScreenId, + }); reset(); } @@ -268,11 +286,11 @@ MZViewBase { } onVisibleChanged: { - if (!visible) { - maybeSaveChange(); - } else { - reset(); - } + if (!visible) { + maybeSaveChange(); + } else { + reset(); + } } Loader { @@ -315,5 +333,26 @@ MZViewBase { onActiveChanged: if (active) { item.open() } } + + Loader { + id: helpSheetLoader + + active: false + + onActiveChanged: if (active) item.open() + + sourceComponent: MZHelpSheet { + title: MZI18n.HelpSheetsDnsTitle + + model: [ + {type: MZHelpSheet.BlockType.Title, text: MZI18n.HelpSheetsDnsHeader}, + {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsDnsBody1, margin: 8}, + {type: MZHelpSheet.BlockType.Text, text:MZI18n.HelpSheetsDnsBody2, margin: 16}, + {type: MZHelpSheet.BlockType.LinkButton, text: MZI18n.GlobalLearnMore, margin: 16, action: () => { MZUrlOpener.openUrlLabel("sumoDns") } }, + ] + + onClosed: helpSheetLoader.active = false + } + } }