From 52fe774975a8345f933d7c9596d6515514a1dea7 Mon Sep 17 00:00:00 2001 From: Michal Iskierko Date: Fri, 19 Jul 2024 14:15:50 +0200 Subject: [PATCH] feat(@desktop/metrics): Show metrics popup when starting application Adding local setting: metrics_popup_seen Small refactoring: showing popup from main.qml Showing popup: 1. on welcome screen, 2. in Settings/Privacy page and 3. after login when the popup has not been shown yet Issue #15628 --- src/app/global/local_app_settings.nim | 15 +++++ src/app_service/service/metrics/service.nim | 56 +++++++++++-------- .../Onboarding/OnboardingLayout.qml | 2 - .../Onboarding/views/KeysMainView.qml | 38 ++----------- .../Onboarding/views/WelcomeView.qml | 14 ++++- ui/app/AppLayouts/Profile/ProfileLayout.qml | 5 +- .../Profile/views/PrivacyAndSecurityView.qml | 25 +++------ ui/app/mainui/AppMain.qml | 4 +- .../shared/popups/MetricsEnablePopup.qml | 8 ++- ui/imports/shared/stores/MetricsStore.qml | 4 +- ui/imports/utils/Global.qml | 3 + ui/main.qml | 39 ++++++++++++- 12 files changed, 123 insertions(+), 90 deletions(-) diff --git a/src/app/global/local_app_settings.nim b/src/app/global/local_app_settings.nim index c6cb462220..34149da4d7 100644 --- a/src/app/global/local_app_settings.nim +++ b/src/app/global/local_app_settings.nim @@ -25,6 +25,8 @@ const LAS_KEY_TRANSLATIONS_ENABLED = "global/translations_enabled" const DEFAULT_LAS_KEY_TRANSLATIONS_ENABLED = false const DEFAULT_LAS_KEY_CREATE_COMMUNITIES_ENABLED = false const LAS_KEY_REFRESH_TOKEN_ENABLED = "global/refresh_token_enabled" +const LAS_KEY_METRICS_POPUP_SEEN = "global/metrics_popup_seen" +const DEFAULT_LAS_KEY_METRICS_POPUP_SEEN = false QtObject: type LocalAppSettings* = ref object of QObject @@ -229,3 +231,16 @@ QtObject: QtProperty[string] walletConnectProjectID: read = getWalletConnectProjectID + + + proc refreshMetricsPopupSeen*(self: LocalAppSettings) {.signal.} + proc getMetricsPopupSeen*(self: LocalAppSettings): bool {.slot.} = + self.settings.value(LAS_KEY_METRICS_POPUP_SEEN, newQVariant(DEFAULT_LAS_KEY_METRICS_POPUP_SEEN)).boolVal + proc setMetricsPopupSeen*(self: LocalAppSettings, enabled: bool) {.slot.} = + self.settings.setValue(LAS_KEY_METRICS_POPUP_SEEN, newQVariant(enabled)) + self.refreshMetricsPopupSeen() + + QtProperty[bool] metricsPopupSeen: + read = getMetricsPopupSeen + write = setMetricsPopupSeen + notify = refreshMetricsPopupSeen \ No newline at end of file diff --git a/src/app_service/service/metrics/service.nim b/src/app_service/service/metrics/service.nim index 3c2c7789bc..ccdca12f53 100644 --- a/src/app_service/service/metrics/service.nim +++ b/src/app_service/service/metrics/service.nim @@ -19,28 +19,6 @@ QtObject: new(result, delete) result.QObject.setup - proc toggleCentralizedMetrics*(self: MetricsService, enabled: bool) {.slot.} = - try: - let payload = %* {"enabled": enabled} - let response = status_go.toggleCentralizedMetrics($payload) - let jsonObj = response.parseJson - if jsonObj.hasKey("error"): - error "toggleCentralizedMetrics", errorMsg=jsonObj["error"].getStr - except Exception: - discard - - proc isCentralizedMetricsEnabled*(self: MetricsService): bool {.slot.} = - try: - let response = status_go.centralizedMetricsInfo() - let jsonObj = response.parseJson - if jsonObj.hasKey("error"): - error "isCentralizedMetricsEnabled", errorMsg=jsonObj["error"].getStr - return false - let metricsInfo = toCentralizedMetricsInfoDto(jsonObj) - return metricsInfo.enabled - except Exception: - return false - # for testing, needs to be discussed proc addCentralizedMetric*(self: MetricsService) = try: @@ -58,4 +36,36 @@ QtObject: if jsonObj.hasKey("error"): error "addCentralizedMetric", errorMsg=jsonObj["error"].getStr except Exception: - discard \ No newline at end of file + discard + + proc centralizedMetricsEnabledChaned*(self: MetricsService) {.signal.} + proc isCentralizedMetricsEnabled*(self: MetricsService): bool {.slot.} = + try: + let response = status_go.centralizedMetricsInfo() + let jsonObj = response.parseJson + if jsonObj.hasKey("error"): + error "isCentralizedMetricsEnabled", errorMsg=jsonObj["error"].getStr + return false + let metricsInfo = toCentralizedMetricsInfoDto(jsonObj) + return metricsInfo.enabled + except Exception: + return false + + QtProperty[bool] isCentralizedMetricsEnabled: + read = isCentralizedMetricsEnabled + notify = centralizedMetricsEnabledChaned + + proc toggleCentralizedMetrics*(self: MetricsService, enabled: bool) {.slot.} = + try: + let isEnabled = self.isCentralizedMetricsEnabled() + if enabled == isEnabled: + return + let payload = %* {"enabled": enabled} + let response = status_go.toggleCentralizedMetrics($payload) + let jsonObj = response.parseJson + if jsonObj{"error"}.getStr.len > 0: + error "toggleCentralizedMetrics", errorMsg=jsonObj["error"].getStr + else: + self.centralizedMetricsEnabledChaned() + except Exception as e: + error "toggleCentralizedMetrics", exceptionMsg = e.msg diff --git a/ui/app/AppLayouts/Onboarding/OnboardingLayout.qml b/ui/app/AppLayouts/Onboarding/OnboardingLayout.qml index be45d78a00..d01ade3a86 100644 --- a/ui/app/AppLayouts/Onboarding/OnboardingLayout.qml +++ b/ui/app/AppLayouts/Onboarding/OnboardingLayout.qml @@ -19,7 +19,6 @@ OnboardingBasePage { id: root property var startupStore: StartupStore {} - property var metricsStore: MetricsStore {} backButtonVisible: root.startupStore.currentStartupState ? root.startupStore.currentStartupState.displayBackButton : false @@ -235,7 +234,6 @@ following the \"Add existing Status user\" flow, using your seed phrase.") id: keysMainViewComponent KeysMainView { startupStore: root.startupStore - metricsStore: root.metricsStore } } diff --git a/ui/app/AppLayouts/Onboarding/views/KeysMainView.qml b/ui/app/AppLayouts/Onboarding/views/KeysMainView.qml index e0ebe86f0a..fdc4a6f7a8 100644 --- a/ui/app/AppLayouts/Onboarding/views/KeysMainView.qml +++ b/ui/app/AppLayouts/Onboarding/views/KeysMainView.qml @@ -23,7 +23,6 @@ Item { id: root property StartupStore startupStore - property MetricsStore metricsStore Component.onCompleted: { if (button1.visible) { @@ -39,17 +38,8 @@ Item { readonly property int infoTextWidth: d.infoWidth - 2 * d.infoMargin readonly property int imgKeysWH: 160 readonly property int imgSeedPhraseWH: 257 - - - function showMetricsAndRunAction(action) { - if (root.startupStore.currentStartupState.stateType === Constants.startupState.welcomeNewStatusUser) { - metricsEnablePopup.actionOnClose = action - metricsEnablePopup.visible = true - } else { - action() - } - } } + ColumnLayout { anchors.centerIn: parent height: Constants.onboarding.loginHeight @@ -233,12 +223,12 @@ Item { Layout.alignment: Qt.AlignHCenter visible: text !== "" onClicked: { - d.showMetricsAndRunAction(root.startupStore.doPrimaryAction) + root.startupStore.doPrimaryAction() } Keys.onPressed: { if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { event.accepted = true - d.showMetricsAndRunAction(root.startupStore.doPrimaryAction) + root.startupStore.doPrimaryAction() } } } @@ -261,7 +251,7 @@ Item { parent.font.underline = false } onClicked: { - d.showMetricsAndRunAction(root.startupStore.doSecondaryAction) + root.startupStore.doSecondaryAction() } } } @@ -297,7 +287,7 @@ Item { Qt.openUrlExternally(button3.link) return } - d.showMetricsAndRunAction(root.startupStore.doTertiaryAction) + root.startupStore.doTertiaryAction() } } } @@ -321,24 +311,6 @@ Item { } } - component MetricsEnablePopupWithActionOnClose: MetricsEnablePopup { - property var actionOnClose - } - - MetricsEnablePopupWithActionOnClose { - id: metricsEnablePopup - isOnboarding: true - - function finalAction(enable) { - if (!!actionOnClose) - actionOnClose() - root.metricsStore.toggleCentralizedMetrics(enable) - } - - onAccepted: finalAction(true) - onRejected: finalAction(false) - } - states: [ State { name: Constants.startupState.welcomeOldStatusUser diff --git a/ui/app/AppLayouts/Onboarding/views/WelcomeView.qml b/ui/app/AppLayouts/Onboarding/views/WelcomeView.qml index 724f45a4d6..3c02050270 100644 --- a/ui/app/AppLayouts/Onboarding/views/WelcomeView.qml +++ b/ui/app/AppLayouts/Onboarding/views/WelcomeView.qml @@ -24,6 +24,14 @@ Item { btnNewUser.forceActiveFocus() } + QtObject { + id: d + + function showMetricsAndRunAction(action) { + Global.openMetricsEnablePopupRequested(true, popup => popup.closed.connect(() => action())) + } + } + BeforeGetStartedModal { id: beforeGetStartedModal onClosed: { @@ -81,12 +89,12 @@ Item { anchors.horizontalCenter: parent.horizontalCenter text: qsTr("I am new to Status") onClicked: { - root.startupStore.doPrimaryAction() + d.showMetricsAndRunAction(root.startupStore.doPrimaryAction) } Keys.onPressed: { if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { event.accepted = true - root.startupStore.doPrimaryAction() + d.showMetricsAndRunAction(root.startupStore.doPrimaryAction) } } } @@ -98,7 +106,7 @@ Item { anchors.topMargin: Style.current.bigPadding anchors.horizontalCenter: parent.horizontalCenter onClicked: { - root.startupStore.doSecondaryAction() + d.showMetricsAndRunAction(root.startupStore.doSecondaryAction) } } } diff --git a/ui/app/AppLayouts/Profile/ProfileLayout.qml b/ui/app/AppLayouts/Profile/ProfileLayout.qml index 4cf416b9a3..fb20b0300b 100644 --- a/ui/app/AppLayouts/Profile/ProfileLayout.qml +++ b/ui/app/AppLayouts/Profile/ProfileLayout.qml @@ -44,7 +44,7 @@ StatusSectionLayout { required property WalletAssetsStore walletAssetsStore required property CollectiblesStore collectiblesStore required property SharedStores.CurrenciesStore currencyStore - required property SharedStores.MetricsStore metricsStore + required property bool isCentralizedMetricsEnabled backButtonName: root.store.backButtonName notificationCount: activityCenterStore.unreadNotificationsCount @@ -463,8 +463,7 @@ StatusSectionLayout { active: false asynchronous: true sourceComponent: PrivacyAndSecurityView { - metricsStore: root.metricsStore - + isCentralizedMetricsEnabled: root.isCentralizedMetricsEnabled implicitWidth: parent.width implicitHeight: parent.height diff --git a/ui/app/AppLayouts/Profile/views/PrivacyAndSecurityView.qml b/ui/app/AppLayouts/Profile/views/PrivacyAndSecurityView.qml index 6a25502848..b8afe209cc 100644 --- a/ui/app/AppLayouts/Profile/views/PrivacyAndSecurityView.qml +++ b/ui/app/AppLayouts/Profile/views/PrivacyAndSecurityView.qml @@ -23,39 +23,28 @@ import SortFilterProxyModel 0.2 SettingsContentBase { id: root - required property MetricsStore metricsStore + required property bool isCentralizedMetricsEnabled - Component.onCompleted: { - enableMetricsSwitch.checked = metricsStore.isCentralizedMetricsEnabled() - } - - function enableMetrics(enable) { - enableMetricsSwitch.checked = enable - metricsStore.toggleCentralizedMetrics(enable) + function refreshSwitch() { + enableMetricsSwitch.checked = Qt.binding(function() { return root.isCentralizedMetricsEnabled }) } ColumnLayout { StatusListItem { Layout.preferredWidth: root.contentWidth title: qsTr("Share usage data with Status") + subTitle: qsTr("From all profiles on device") components: [ StatusSwitch { id: enableMetricsSwitch + checked: root.isCentralizedMetricsEnabled onClicked: { - Global.openPopup(metricsEnabledPopupComponent) + Global.openMetricsEnablePopupRequested(false, popup => popup.toggleMetrics.connect(refreshSwitch)) } } ] onClicked: { - Global.openPopup(metricsEnabledPopupComponent) - } - } - - Component { - id: metricsEnabledPopupComponent - MetricsEnablePopup { - onAccepted: root.enableMetrics(true) - onRejected: root.enableMetrics(false) + Global.openMetricsEnablePopupRequested(false, popup => popup.toggleMetrics.connect(refreshSwitch)) } } } diff --git a/ui/app/mainui/AppMain.qml b/ui/app/mainui/AppMain.qml index 2e69fc1e81..d1b6ca525b 100644 --- a/ui/app/mainui/AppMain.qml +++ b/ui/app/mainui/AppMain.qml @@ -72,7 +72,6 @@ Item { property NetworkConnectionStore networkConnectionStore: NetworkConnectionStore {} property CommunityTokensStore communityTokensStore: CommunityTokensStore {} property CommunitiesStore communitiesStore: CommunitiesStore {} - property MetricsStore metricsStore: MetricsStore {} readonly property WalletStore.TokensStore tokensStore: WalletStore.RootStore.tokensStore readonly property WalletStore.WalletAssetsStore walletAssetsStore: WalletStore.RootStore.walletAssetsStore readonly property WalletStore.CollectiblesStore walletCollectiblesStore: WalletStore.RootStore.collectiblesStore @@ -82,6 +81,7 @@ Item { tokensStore: appMain.tokensStore currencyStore: appMain.currencyStore } + required property bool isCentralizedMetricsEnabled // set from main.qml property var sysPalette @@ -1441,7 +1441,7 @@ Item { walletAssetsStore: appMain.walletAssetsStore collectiblesStore: appMain.walletCollectiblesStore currencyStore: appMain.currencyStore - metricsStore: appMain.metricsStore + isCentralizedMetricsEnabled: appMain.isCentralizedMetricsEnabled } } diff --git a/ui/imports/shared/popups/MetricsEnablePopup.qml b/ui/imports/shared/popups/MetricsEnablePopup.qml index dbda57d9e9..b9f2b7024d 100644 --- a/ui/imports/shared/popups/MetricsEnablePopup.qml +++ b/ui/imports/shared/popups/MetricsEnablePopup.qml @@ -16,6 +16,8 @@ StatusModal { property bool isOnboarding: false + signal toggleMetrics(bool enabled) + width: 640 title: qsTr("Help us improve Status") hasCloseButton: true @@ -90,7 +92,8 @@ StatusModal { StatusButton { text: qsTr("Share usage data") onClicked: { - root.accept() + root.toggleMetrics(true) + close() } objectName: "shareMetricsButton" } @@ -100,7 +103,8 @@ StatusModal { StatusButton { text: qsTr("Not now") onClicked: { - root.reject() + root.toggleMetrics(false) + close() } objectName: "notShareMetricsButton" normalColor: "transparent" diff --git a/ui/imports/shared/stores/MetricsStore.qml b/ui/imports/shared/stores/MetricsStore.qml index b0f94b61ef..037e23b89a 100644 --- a/ui/imports/shared/stores/MetricsStore.qml +++ b/ui/imports/shared/stores/MetricsStore.qml @@ -7,7 +7,5 @@ QtObject { metrics.toggleCentralizedMetrics(enabled) } - function isCentralizedMetricsEnabled() { - return metrics.isCentralizedMetricsEnabled() - } + readonly property bool isCentralizedMetricsEnabled : metrics.isCentralizedMetricsEnabled } diff --git a/ui/imports/utils/Global.qml b/ui/imports/utils/Global.qml index 163049f5a8..028ba54dca 100644 --- a/ui/imports/utils/Global.qml +++ b/ui/imports/utils/Global.qml @@ -109,6 +109,9 @@ QtObject { // BuyCrypto signal openBuyCryptoModalRequested() + // Metrics + signal openMetricsEnablePopupRequested(bool isOnboarding, var cb) + ///////////////////////////////////////////////////// // WalletConnect POC - to remove signal popupWalletConnect() diff --git a/ui/main.qml b/ui/main.qml index 9cdb49f804..da2ee745fc 100644 --- a/ui/main.qml +++ b/ui/main.qml @@ -11,6 +11,7 @@ import utils 1.0 import shared 1.0 import shared.panels 1.0 import shared.popups 1.0 +import shared.stores 1.0 import mainui 1.0 import AppLayouts.Onboarding 1.0 @@ -19,11 +20,14 @@ import StatusQ 0.1 // Force import StatusQ plugin to load all StatusQ resources import StatusQ.Core.Theme 0.1 StatusWindow { + id: applicationWindow + property bool appIsReady: false + property MetricsStore metricsStore: MetricsStore {} + Universal.theme: Universal.System - id: applicationWindow objectName: "mainWindow" minimumWidth: 1200 minimumHeight: 680 @@ -285,6 +289,8 @@ StatusWindow { Style.changeTheme(Universal.System, systemPalette.isCurrentSystemThemeDark()); restoreAppState(); + + Global.openMetricsEnablePopupRequested.connect(openMetricsEnablePopup) } signal navigateTo(string path) @@ -296,6 +302,17 @@ StatusWindow { applicationWindow.requestActivate() } + function openMetricsEnablePopup(isOnboarding, cb = null) { + metricsPopupLoader.active = true + metricsPopupLoader.item.visible = true + metricsPopupLoader.item.isOnboarding = isOnboarding + if (cb) + cb(metricsPopupLoader.item) + if(!localAppSettings.metricsPopupSeen) { + localAppSettings.metricsPopupSeen = true + } + } + StatusTrayIcon { id: systemTray objectName: "systemTray" @@ -320,6 +337,7 @@ StatusWindow { AppMain { sysPalette: systemPalette visible: !appLoadingAnimation.active + isCentralizedMetricsEnabled: metricsStore.isCentralizedMetricsEnabled } } @@ -339,6 +357,15 @@ StatusWindow { } } } + onActiveChanged: { + if (!active) { + // animation is finished, app main will be shown + // open metrics popup only if it has not been seen + if(!localAppSettings.metricsPopupSeen) { + openMetricsEnablePopup(true, null) + } + } + } } OnboardingLayout { @@ -347,6 +374,16 @@ StatusWindow { anchors.fill: parent } + Loader { + id: metricsPopupLoader + active: false + sourceComponent: MetricsEnablePopup { + visible: true + onClosed: metricsPopupLoader.active = false + onToggleMetrics: applicationWindow.metricsStore.toggleCentralizedMetrics(enabled) + } + } + MacTrafficLights { // FIXME should be a direct part of StatusAppNavBar anchors.left: parent.left anchors.top: parent.top