feat(@desktop/metrics): Add metrics management page

Add new settings page for metrics management - Privacy and security
Add popup to enable/disable metrics on Onboarding and Privacy screens
Add MetricsStore in QML

Issue #15490
This commit is contained in:
Michal Iskierko 2024-07-15 15:34:40 +02:00
parent aee9db4b5c
commit 15f23dfb87
15 changed files with 289 additions and 27 deletions

View File

@ -0,0 +1,39 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import shared.popups 1.0
import Storybook 1.0
SplitView {
orientation: Qt.Vertical
Item {
SplitView.fillWidth: true
SplitView.fillHeight: true
PopupBackground {
anchors.fill: parent
}
Button {
anchors.centerIn: parent
text: "Reopen"
onClicked: popup.open()
}
}
MetricsEnablePopup {
id: popup
anchors.centerIn: parent
modal: false
visible: true
isOnboarding: true
}
}
// category: Popups
// https://www.figma.com/design/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=24721-503547&t=a7IsC44aG7YQuInQ-0

View File

@ -201,10 +201,7 @@ StatusModal {
type: StatusBaseButton.Type.Danger
text: qsTr("Delete Category")
onClicked: {
Global.openPopup(deleteCategoryConfirmationDialogComponent, {
"headerSettings.title": qsTr("Delete '%1' category").arg(nameInput.text),
confirmationText: qsTr("Are you sure you want to delete '%1' category? Channels inside the category wont be deleted.").arg(nameInput.text)
})
Global.openPopup(deleteCategoryConfirmationDialogComponent)
}
},
StatusButton {

View File

@ -8,6 +8,7 @@ import StatusQ.Core.Theme 0.1
import utils 1.0
import shared.popups.keycard 1.0
import shared.stores 1.0
import "controls"
import "views"
@ -18,6 +19,7 @@ OnboardingBasePage {
id: root
property var startupStore: StartupStore {}
property var metricsStore: MetricsStore {}
backButtonVisible: root.startupStore.currentStartupState ? root.startupStore.currentStartupState.displayBackButton
: false
@ -233,6 +235,7 @@ following the \"Add existing Status user\" flow, using your seed phrase.")
id: keysMainViewComponent
KeysMainView {
startupStore: root.startupStore
metricsStore: root.metricsStore
}
}

View File

@ -115,14 +115,6 @@ QtObject {
return root.startupModuleInst.getSeedPhrase()
}
function toggleCentralizedMetrics(enabled) {
metrics.toggleCentralizedMetrics(enabled)
}
function isCentralizedMetricsEnabled() {
return metrics.isCentralizedMetricsEnabled()
}
function validateLocalPairingConnectionString(connectionString) {
return root.startupModuleInst.validateLocalPairingConnectionString(connectionString)
}

View File

@ -10,6 +10,9 @@ import StatusQ.Components 0.1
import shared 1.0
import shared.panels 1.0
import shared.popups 1.0
import shared.stores 1.0
import "../popups"
import "../controls"
import "../stores"
@ -20,12 +23,12 @@ Item {
id: root
property StartupStore startupStore
property MetricsStore metricsStore
Component.onCompleted: {
if (button1.visible) {
button1.forceActiveFocus()
}
enableCentricMetrics.checked = root.startupStore.isCentralizedMetricsEnabled()
}
QtObject {
@ -36,6 +39,16 @@ 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
@ -220,12 +233,12 @@ Item {
Layout.alignment: Qt.AlignHCenter
visible: text !== ""
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)
}
}
}
@ -248,7 +261,7 @@ Item {
parent.font.underline = false
}
onClicked: {
root.startupStore.doSecondaryAction()
d.showMetricsAndRunAction(root.startupStore.doSecondaryAction)
}
}
}
@ -284,7 +297,7 @@ Item {
Qt.openUrlExternally(button3.link)
return
}
root.startupStore.doTertiaryAction()
d.showMetricsAndRunAction(root.startupStore.doTertiaryAction)
}
}
}
@ -302,19 +315,29 @@ Item {
}
}
StatusCheckBox {
id: enableCentricMetrics
text: qsTr("Enable centric metrics")
Layout.alignment: Qt.AlignHCenter
onToggled: root.startupStore.toggleCentralizedMetrics(checked)
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
}
}
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 {

View File

@ -44,6 +44,7 @@ StatusSectionLayout {
required property WalletAssetsStore walletAssetsStore
required property CollectiblesStore collectiblesStore
required property SharedStores.CurrenciesStore currencyStore
required property SharedStores.MetricsStore metricsStore
backButtonName: root.store.backButtonName
notificationCount: activityCenterStore.unreadNotificationsCount
@ -457,6 +458,20 @@ StatusSectionLayout {
}
}
}
Loader {
active: false
asynchronous: true
sourceComponent: PrivacyAndSecurityView {
metricsStore: root.metricsStore
implicitWidth: parent.width
implicitHeight: parent.height
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.privacyAndSecurity)
contentWidth: d.contentWidth
}
}
}
showRightPanel: d.isProfilePanelActive && d.sideBySidePreviewAvailable

View File

@ -133,6 +133,9 @@ QtObject {
property ListModel settingsMenuItems: ListModel {
Component.onCompleted: {
append({subsection: Constants.settingsSubsection.privacyAndSecurity,
text: qsTr("Privacy and security"),
icon: "security"})
append({subsection: Constants.settingsSubsection.appearance,
text: qsTr("Appearance"),
icon: "appearance"})

View File

@ -0,0 +1,62 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import utils 1.0
import shared.panels 1.0
import shared.popups 1.0
import shared.stores 1.0
import StatusQ 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1 as StatusQUtils
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import AppLayouts.Profile.stores 1.0
import "../popups"
import SortFilterProxyModel 0.2
SettingsContentBase {
id: root
required property MetricsStore metricsStore
Component.onCompleted: {
enableMetricsSwitch.checked = metricsStore.isCentralizedMetricsEnabled()
}
function enableMetrics(enable) {
enableMetricsSwitch.checked = enable
metricsStore.toggleCentralizedMetrics(enable)
}
ColumnLayout {
StatusListItem {
Layout.preferredWidth: root.contentWidth
title: qsTr("Share usage data with Status")
components: [
StatusSwitch {
id: enableMetricsSwitch
onClicked: {
Global.openPopup(metricsEnabledPopupComponent)
}
}
]
onClicked: {
Global.openPopup(metricsEnabledPopupComponent)
}
}
Component {
id: metricsEnabledPopupComponent
MetricsEnablePopup {
onAccepted: root.enableMetrics(true)
onRejected: root.enableMetrics(false)
}
}
}
}

View File

@ -6,3 +6,4 @@ CommunitiesView 1.0 CommunitiesView.qml
LanguageView 1.0 LanguageView.qml
NotificationsView 1.0 NotificationsView.qml
SyncingView 1.0 SyncingView.qml
PrivacyAndSecurityView 1.0 PrivacyAndSecurityView.qml

View File

@ -72,6 +72,7 @@ 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
@ -1334,6 +1335,7 @@ Item {
walletAssetsStore: appMain.walletAssetsStore
collectiblesStore: appMain.walletCollectiblesStore
currencyStore: appMain.currencyStore
metricsStore: appMain.metricsStore
}
}

View File

@ -0,0 +1,109 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import StatusQ.Popups.Dialog 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
import utils 1.0
StatusModal {
id: root
property bool isOnboarding: false
width: 640
title: qsTr("Help us improve Status")
hasCloseButton: true
verticalPadding: 20
closePolicy: Popup.CloseOnEscape
component Paragraph: StatusBaseText {
lineHeightMode: Text.FixedHeight
lineHeight: 22
visible: true
wrapMode: Text.Wrap
}
component AgreementSection: ColumnLayout {
property alias title: titleItem.text
property alias body: bodyItem.text
spacing: 8
Paragraph {
id: titleItem
Layout.fillWidth: true
Layout.fillHeight: true
font.weight: Font.Bold
}
Paragraph {
id: bodyItem
Layout.fillWidth: true
Layout.fillHeight: true
}
}
StatusScrollView {
id: scrollView
anchors.fill: parent
contentWidth: availableWidth
ColumnLayout {
id: layout
width: scrollView.availableWidth
spacing: 20
Paragraph {
Layout.fillWidth: true
Layout.fillHeight: true
text: qsTr("Collecting usage data helps us improve Status.")
}
AgreementSection {
title: qsTr("What we will receive:")
body: qsTr(" IP address
Universally Unique Identifiers of device
Logs of actions within the app, including button presses and screen visits")
}
AgreementSection {
title: qsTr("What we wont receive:")
body: qsTr(" Your profile information
Your addresses
Information you input and send")
}
Paragraph {
Layout.fillWidth: true
Layout.fillHeight: true
text: qsTr("Usage data will be shared from all profiles added to device. %1").arg(root.isOnboarding ? "Sharing usage data can be turned off anytime in Settings / Privacy and Security." : "")
}
}
}
rightButtons: [
StatusButton {
text: qsTr("Share usage data")
onClicked: {
root.accept()
}
objectName: "shareMetricsButton"
}
]
leftButtons: [
StatusButton {
text: qsTr("Not now")
onClicked: {
root.reject()
}
objectName: "notShareMetricsButton"
normalColor: "transparent"
}
]
}

View File

@ -31,5 +31,6 @@ SendContactRequestModal 1.0 SendContactRequestModal.qml
SettingsDirtyToastMessage 1.0 SettingsDirtyToastMessage.qml
UnblockContactConfirmationDialog 1.0 UnblockContactConfirmationDialog.qml
UserAgreementPopup 1.0 UserAgreementPopup.qml
MetricsEnablePopup 1.0 MetricsEnablePopup.qml
UserStatusContextMenu 1.0 UserStatusContextMenu.qml
ImageContextMenu 1.0 ImageContextMenu.qml

View File

@ -0,0 +1,13 @@
import QtQml 2.15
QtObject {
id: root
function toggleCentralizedMetrics(enabled) {
metrics.toggleCentralizedMetrics(enabled)
}
function isCentralizedMetricsEnabled() {
return metrics.isCentralizedMetricsEnabled()
}
}

View File

@ -6,5 +6,6 @@ ChartStoreBase 1.0 ChartStoreBase.qml
PermissionsStore 1.0 PermissionsStore.qml
TokenBalanceHistoryStore 1.0 TokenBalanceHistoryStore.qml
TokenMarketValuesStore 1.0 TokenMarketValuesStore.qml
MetricsStore 1.0 MetricsStore.qml
NetworkConnectionStore 1.0 NetworkConnectionStore.qml
DAppsStore 1.0 DAppsStore.qml
DAppsStore 1.0 DAppsStore.qml

View File

@ -349,10 +349,11 @@ QtObject {
readonly property int keycard: 14
readonly property int about_terms: 15 // a subpage under "About"
readonly property int about_privacy: 16 // a subpage under "About"
readonly property int privacyAndSecurity: 17
// special treatment; these do not participate in the main settings' StackLayout
readonly property int signout: 17
readonly property int backUpSeed: 18
readonly property int signout: 18
readonly property int backUpSeed: 19
}
readonly property QtObject walletSettingsSubsection: QtObject {