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
This commit is contained in:
Michal Iskierko 2024-07-19 14:15:50 +02:00 committed by Michał Iskierko
parent 7ec4230a32
commit 52fe774975
12 changed files with 123 additions and 90 deletions

View File

@ -25,6 +25,8 @@ const LAS_KEY_TRANSLATIONS_ENABLED = "global/translations_enabled"
const DEFAULT_LAS_KEY_TRANSLATIONS_ENABLED = false const DEFAULT_LAS_KEY_TRANSLATIONS_ENABLED = false
const DEFAULT_LAS_KEY_CREATE_COMMUNITIES_ENABLED = false const DEFAULT_LAS_KEY_CREATE_COMMUNITIES_ENABLED = false
const LAS_KEY_REFRESH_TOKEN_ENABLED = "global/refresh_token_enabled" 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: QtObject:
type LocalAppSettings* = ref object of QObject type LocalAppSettings* = ref object of QObject
@ -229,3 +231,16 @@ QtObject:
QtProperty[string] walletConnectProjectID: QtProperty[string] walletConnectProjectID:
read = getWalletConnectProjectID 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

View File

@ -19,28 +19,6 @@ QtObject:
new(result, delete) new(result, delete)
result.QObject.setup 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 # for testing, needs to be discussed
proc addCentralizedMetric*(self: MetricsService) = proc addCentralizedMetric*(self: MetricsService) =
try: try:
@ -59,3 +37,35 @@ QtObject:
error "addCentralizedMetric", errorMsg=jsonObj["error"].getStr error "addCentralizedMetric", errorMsg=jsonObj["error"].getStr
except Exception: except Exception:
discard 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

View File

@ -19,7 +19,6 @@ OnboardingBasePage {
id: root id: root
property var startupStore: StartupStore {} property var startupStore: StartupStore {}
property var metricsStore: MetricsStore {}
backButtonVisible: root.startupStore.currentStartupState ? root.startupStore.currentStartupState.displayBackButton backButtonVisible: root.startupStore.currentStartupState ? root.startupStore.currentStartupState.displayBackButton
: false : false
@ -235,7 +234,6 @@ following the \"Add existing Status user\" flow, using your seed phrase.")
id: keysMainViewComponent id: keysMainViewComponent
KeysMainView { KeysMainView {
startupStore: root.startupStore startupStore: root.startupStore
metricsStore: root.metricsStore
} }
} }

View File

@ -23,7 +23,6 @@ Item {
id: root id: root
property StartupStore startupStore property StartupStore startupStore
property MetricsStore metricsStore
Component.onCompleted: { Component.onCompleted: {
if (button1.visible) { if (button1.visible) {
@ -39,17 +38,8 @@ Item {
readonly property int infoTextWidth: d.infoWidth - 2 * d.infoMargin readonly property int infoTextWidth: d.infoWidth - 2 * d.infoMargin
readonly property int imgKeysWH: 160 readonly property int imgKeysWH: 160
readonly property int imgSeedPhraseWH: 257 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 { ColumnLayout {
anchors.centerIn: parent anchors.centerIn: parent
height: Constants.onboarding.loginHeight height: Constants.onboarding.loginHeight
@ -233,12 +223,12 @@ Item {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
visible: text !== "" visible: text !== ""
onClicked: { onClicked: {
d.showMetricsAndRunAction(root.startupStore.doPrimaryAction) root.startupStore.doPrimaryAction()
} }
Keys.onPressed: { Keys.onPressed: {
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
event.accepted = true event.accepted = true
d.showMetricsAndRunAction(root.startupStore.doPrimaryAction) root.startupStore.doPrimaryAction()
} }
} }
} }
@ -261,7 +251,7 @@ Item {
parent.font.underline = false parent.font.underline = false
} }
onClicked: { onClicked: {
d.showMetricsAndRunAction(root.startupStore.doSecondaryAction) root.startupStore.doSecondaryAction()
} }
} }
} }
@ -297,7 +287,7 @@ Item {
Qt.openUrlExternally(button3.link) Qt.openUrlExternally(button3.link)
return 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: [ states: [
State { State {
name: Constants.startupState.welcomeOldStatusUser name: Constants.startupState.welcomeOldStatusUser

View File

@ -24,6 +24,14 @@ Item {
btnNewUser.forceActiveFocus() btnNewUser.forceActiveFocus()
} }
QtObject {
id: d
function showMetricsAndRunAction(action) {
Global.openMetricsEnablePopupRequested(true, popup => popup.closed.connect(() => action()))
}
}
BeforeGetStartedModal { BeforeGetStartedModal {
id: beforeGetStartedModal id: beforeGetStartedModal
onClosed: { onClosed: {
@ -81,12 +89,12 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
text: qsTr("I am new to Status") text: qsTr("I am new to Status")
onClicked: { onClicked: {
root.startupStore.doPrimaryAction() d.showMetricsAndRunAction(root.startupStore.doPrimaryAction)
} }
Keys.onPressed: { Keys.onPressed: {
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
event.accepted = true event.accepted = true
root.startupStore.doPrimaryAction() d.showMetricsAndRunAction(root.startupStore.doPrimaryAction)
} }
} }
} }
@ -98,7 +106,7 @@ Item {
anchors.topMargin: Style.current.bigPadding anchors.topMargin: Style.current.bigPadding
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
onClicked: { onClicked: {
root.startupStore.doSecondaryAction() d.showMetricsAndRunAction(root.startupStore.doSecondaryAction)
} }
} }
} }

View File

@ -44,7 +44,7 @@ StatusSectionLayout {
required property WalletAssetsStore walletAssetsStore required property WalletAssetsStore walletAssetsStore
required property CollectiblesStore collectiblesStore required property CollectiblesStore collectiblesStore
required property SharedStores.CurrenciesStore currencyStore required property SharedStores.CurrenciesStore currencyStore
required property SharedStores.MetricsStore metricsStore required property bool isCentralizedMetricsEnabled
backButtonName: root.store.backButtonName backButtonName: root.store.backButtonName
notificationCount: activityCenterStore.unreadNotificationsCount notificationCount: activityCenterStore.unreadNotificationsCount
@ -463,8 +463,7 @@ StatusSectionLayout {
active: false active: false
asynchronous: true asynchronous: true
sourceComponent: PrivacyAndSecurityView { sourceComponent: PrivacyAndSecurityView {
metricsStore: root.metricsStore isCentralizedMetricsEnabled: root.isCentralizedMetricsEnabled
implicitWidth: parent.width implicitWidth: parent.width
implicitHeight: parent.height implicitHeight: parent.height

View File

@ -23,39 +23,28 @@ import SortFilterProxyModel 0.2
SettingsContentBase { SettingsContentBase {
id: root id: root
required property MetricsStore metricsStore required property bool isCentralizedMetricsEnabled
Component.onCompleted: { function refreshSwitch() {
enableMetricsSwitch.checked = metricsStore.isCentralizedMetricsEnabled() enableMetricsSwitch.checked = Qt.binding(function() { return root.isCentralizedMetricsEnabled })
}
function enableMetrics(enable) {
enableMetricsSwitch.checked = enable
metricsStore.toggleCentralizedMetrics(enable)
} }
ColumnLayout { ColumnLayout {
StatusListItem { StatusListItem {
Layout.preferredWidth: root.contentWidth Layout.preferredWidth: root.contentWidth
title: qsTr("Share usage data with Status") title: qsTr("Share usage data with Status")
subTitle: qsTr("From all profiles on device")
components: [ components: [
StatusSwitch { StatusSwitch {
id: enableMetricsSwitch id: enableMetricsSwitch
checked: root.isCentralizedMetricsEnabled
onClicked: { onClicked: {
Global.openPopup(metricsEnabledPopupComponent) Global.openMetricsEnablePopupRequested(false, popup => popup.toggleMetrics.connect(refreshSwitch))
} }
} }
] ]
onClicked: { onClicked: {
Global.openPopup(metricsEnabledPopupComponent) Global.openMetricsEnablePopupRequested(false, popup => popup.toggleMetrics.connect(refreshSwitch))
}
}
Component {
id: metricsEnabledPopupComponent
MetricsEnablePopup {
onAccepted: root.enableMetrics(true)
onRejected: root.enableMetrics(false)
} }
} }
} }

View File

@ -72,7 +72,6 @@ Item {
property NetworkConnectionStore networkConnectionStore: NetworkConnectionStore {} property NetworkConnectionStore networkConnectionStore: NetworkConnectionStore {}
property CommunityTokensStore communityTokensStore: CommunityTokensStore {} property CommunityTokensStore communityTokensStore: CommunityTokensStore {}
property CommunitiesStore communitiesStore: CommunitiesStore {} property CommunitiesStore communitiesStore: CommunitiesStore {}
property MetricsStore metricsStore: MetricsStore {}
readonly property WalletStore.TokensStore tokensStore: WalletStore.RootStore.tokensStore readonly property WalletStore.TokensStore tokensStore: WalletStore.RootStore.tokensStore
readonly property WalletStore.WalletAssetsStore walletAssetsStore: WalletStore.RootStore.walletAssetsStore readonly property WalletStore.WalletAssetsStore walletAssetsStore: WalletStore.RootStore.walletAssetsStore
readonly property WalletStore.CollectiblesStore walletCollectiblesStore: WalletStore.RootStore.collectiblesStore readonly property WalletStore.CollectiblesStore walletCollectiblesStore: WalletStore.RootStore.collectiblesStore
@ -82,6 +81,7 @@ Item {
tokensStore: appMain.tokensStore tokensStore: appMain.tokensStore
currencyStore: appMain.currencyStore currencyStore: appMain.currencyStore
} }
required property bool isCentralizedMetricsEnabled
// set from main.qml // set from main.qml
property var sysPalette property var sysPalette
@ -1441,7 +1441,7 @@ Item {
walletAssetsStore: appMain.walletAssetsStore walletAssetsStore: appMain.walletAssetsStore
collectiblesStore: appMain.walletCollectiblesStore collectiblesStore: appMain.walletCollectiblesStore
currencyStore: appMain.currencyStore currencyStore: appMain.currencyStore
metricsStore: appMain.metricsStore isCentralizedMetricsEnabled: appMain.isCentralizedMetricsEnabled
} }
} }

View File

@ -16,6 +16,8 @@ StatusModal {
property bool isOnboarding: false property bool isOnboarding: false
signal toggleMetrics(bool enabled)
width: 640 width: 640
title: qsTr("Help us improve Status") title: qsTr("Help us improve Status")
hasCloseButton: true hasCloseButton: true
@ -90,7 +92,8 @@ StatusModal {
StatusButton { StatusButton {
text: qsTr("Share usage data") text: qsTr("Share usage data")
onClicked: { onClicked: {
root.accept() root.toggleMetrics(true)
close()
} }
objectName: "shareMetricsButton" objectName: "shareMetricsButton"
} }
@ -100,7 +103,8 @@ StatusModal {
StatusButton { StatusButton {
text: qsTr("Not now") text: qsTr("Not now")
onClicked: { onClicked: {
root.reject() root.toggleMetrics(false)
close()
} }
objectName: "notShareMetricsButton" objectName: "notShareMetricsButton"
normalColor: "transparent" normalColor: "transparent"

View File

@ -7,7 +7,5 @@ QtObject {
metrics.toggleCentralizedMetrics(enabled) metrics.toggleCentralizedMetrics(enabled)
} }
function isCentralizedMetricsEnabled() { readonly property bool isCentralizedMetricsEnabled : metrics.isCentralizedMetricsEnabled
return metrics.isCentralizedMetricsEnabled()
}
} }

View File

@ -109,6 +109,9 @@ QtObject {
// BuyCrypto // BuyCrypto
signal openBuyCryptoModalRequested() signal openBuyCryptoModalRequested()
// Metrics
signal openMetricsEnablePopupRequested(bool isOnboarding, var cb)
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
// WalletConnect POC - to remove // WalletConnect POC - to remove
signal popupWalletConnect() signal popupWalletConnect()

View File

@ -11,6 +11,7 @@ import utils 1.0
import shared 1.0 import shared 1.0
import shared.panels 1.0 import shared.panels 1.0
import shared.popups 1.0 import shared.popups 1.0
import shared.stores 1.0
import mainui 1.0 import mainui 1.0
import AppLayouts.Onboarding 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 import StatusQ.Core.Theme 0.1
StatusWindow { StatusWindow {
id: applicationWindow
property bool appIsReady: false property bool appIsReady: false
property MetricsStore metricsStore: MetricsStore {}
Universal.theme: Universal.System Universal.theme: Universal.System
id: applicationWindow
objectName: "mainWindow" objectName: "mainWindow"
minimumWidth: 1200 minimumWidth: 1200
minimumHeight: 680 minimumHeight: 680
@ -285,6 +289,8 @@ StatusWindow {
Style.changeTheme(Universal.System, systemPalette.isCurrentSystemThemeDark()); Style.changeTheme(Universal.System, systemPalette.isCurrentSystemThemeDark());
restoreAppState(); restoreAppState();
Global.openMetricsEnablePopupRequested.connect(openMetricsEnablePopup)
} }
signal navigateTo(string path) signal navigateTo(string path)
@ -296,6 +302,17 @@ StatusWindow {
applicationWindow.requestActivate() 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 { StatusTrayIcon {
id: systemTray id: systemTray
objectName: "systemTray" objectName: "systemTray"
@ -320,6 +337,7 @@ StatusWindow {
AppMain { AppMain {
sysPalette: systemPalette sysPalette: systemPalette
visible: !appLoadingAnimation.active 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 { OnboardingLayout {
@ -347,6 +374,16 @@ StatusWindow {
anchors.fill: parent 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 MacTrafficLights { // FIXME should be a direct part of StatusAppNavBar
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top