From e8c0275137863c6d545e3fdaa2db5530f8edcde6 Mon Sep 17 00:00:00 2001 From: Noelia Date: Mon, 23 Oct 2023 13:35:20 +0200 Subject: [PATCH] feat(ActivityCenter): Transfer ownership messages - It created all possible AC notification types and notification component for transfer ownership flow. - It adds `storybook` support for the new component. - It adds call from activity center to finalise ownership popup. Part of #12175 a --- ...ficationCommunityMembershipRequestPage.qml | 12 +- ...ivityNotificationTransferOwnershipPage.qml | 114 +++++++++ ui/StatusQ/src/assets.qrc | 1 + ui/StatusQ/src/assets/img/icons/crown-off.svg | 3 + .../popups/ActivityCenterPopup.qml | 78 +++++-- .../stores/ActivityCenterStore.qml | 7 +- .../ActivityNotificationTransferOwnership.qml | 216 ++++++++++++++++++ ui/app/mainui/activitycenter/views/qmldir | 3 +- 8 files changed, 403 insertions(+), 31 deletions(-) create mode 100644 storybook/pages/ActivityNotificationTransferOwnershipPage.qml create mode 100644 ui/StatusQ/src/assets/img/icons/crown-off.svg create mode 100644 ui/app/mainui/activitycenter/views/ActivityNotificationTransferOwnership.qml diff --git a/storybook/pages/ActivityNotificationCommunityMembershipRequestPage.qml b/storybook/pages/ActivityNotificationCommunityMembershipRequestPage.qml index a9d40be7fb..45062bed24 100644 --- a/storybook/pages/ActivityNotificationCommunityMembershipRequestPage.qml +++ b/storybook/pages/ActivityNotificationCommunityMembershipRequestPage.qml @@ -58,11 +58,12 @@ SplitView { valueRole: "value" model: ListModel { id: model - ListElement { text: "Pending"; value: ActivityCenterStore.ActivityCenterMembershipStatus.Pending } - ListElement { text: "Accepted"; value: ActivityCenterStore.ActivityCenterMembershipStatus.Accepted } - ListElement { text: "Declined"; value: ActivityCenterStore.ActivityCenterMembershipStatus.Declined } - ListElement { text: "AcceptedPending"; value: ActivityCenterStore.ActivityCenterMembershipStatus.AcceptedPending } - ListElement { text: "DeclinedPending"; value: ActivityCenterStore.ActivityCenterMembershipStatus.DeclinedPending } + + ListElement { text: "Pending"; value: 1 } // ActivityCenterStore.ActivityCenterMembershipStatus.Pending } + ListElement { text: "Accepted"; value: 2 } //ActivityCenterStore.ActivityCenterMembershipStatus.Accepted } + ListElement { text: "Declined"; value: 3 } //ActivityCenterStore.ActivityCenterMembershipStatus.Declined } + ListElement { text: "AcceptedPending"; value: 4 } //ActivityCenterStore.ActivityCenterMembershipStatus.AcceptedPending } + ListElement { text: "DeclinedPending"; value: 5 } //ActivityCenterStore.ActivityCenterMembershipStatus.DeclinedPending } } } } @@ -178,4 +179,5 @@ SplitView { } } +// category: Activity Center // https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba⎜Desktop?type=design&node-id=35909-606817&mode=design&t=Ia7Z0AzyYIjkuPtr-0 diff --git a/storybook/pages/ActivityNotificationTransferOwnershipPage.qml b/storybook/pages/ActivityNotificationTransferOwnershipPage.qml new file mode 100644 index 0000000000..24a67044fa --- /dev/null +++ b/storybook/pages/ActivityNotificationTransferOwnershipPage.qml @@ -0,0 +1,114 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +import Qt.labs.settings 1.0 + +import mainui.activitycenter.views 1.0 +import mainui.activitycenter.stores 1.0 + +import Storybook 1.0 + +SplitView { + id: root + + orientation: Qt.Vertical + + Logs { id: logs } + + QtObject { + id: notificationMock + + property string id: "1" + property string communityId: "1" + property string sectionId: "1" + property int notificationType: 1 + property int timestamp: Date.now() + property int previousTimestamp: 0 + property bool read: false + property bool dismissed: false + property bool accepted: false + } + + Item { + SplitView.fillHeight: true + SplitView.fillWidth: true + + ActivityNotificationTransferOwnership { + id: notification + + anchors.centerIn: parent + width: parent.width - 50 + height: implicitHeight + + type: ActivityNotificationTransferOwnership.OwnershipState.Pending + store: undefined + notification: notificationMock + communityName: communityNameText.text + communityColor: colorSwitch.checked ? "green" : "orange" + + onFinaliseOwnershipClicked: logs.logEvent("ActivityNotificationOwnerTokenReceived::onFinaliseOwnershipClicked") + onNavigateToCommunityClicked: logs.logEvent("ActivityNotificationOwnerTokenReceived::onNavigateToCommunityClicked") + } + + } + + LogsAndControlsPanel { + SplitView.minimumHeight: 100 + SplitView.preferredHeight: 160 + + logsView.logText: logs.logText + + Column { + Row { + Label { + text: "Community Name: " + } + + TextInput { + id: communityNameText + + text: "Doodles" + } + } + + Switch { + id: colorSwitch + + text: "Orange OR Green" + checked: true + } + + Row { + RadioButton { + text: "Pending" + checked: true + onCheckedChanged: if(checked) notification.type = ActivityNotificationTransferOwnership.OwnershipState.Pending + } + + RadioButton { + text: "Declined" + onCheckedChanged: if(checked) notification.type = ActivityNotificationTransferOwnership.OwnershipState.Declined + } + + RadioButton { + text: "Succeded" + onCheckedChanged: if(checked) notification.type = ActivityNotificationTransferOwnership.OwnershipState.Succeeded + } + + RadioButton { + text: "Failed" + onCheckedChanged: if(checked) notification.type = ActivityNotificationTransferOwnership.OwnershipState.Failed + } + + RadioButton { + text: "No longer control node" + onCheckedChanged: if(checked) notification.type = ActivityNotificationTransferOwnership.OwnershipState.NoLongerControlNode + } + } + } + } +} + +// category: Activity Center +// https://www.figma.com/file/qHfFm7C9LwtXpfdbxssCK3/Kuba%E2%8E%9CDesktop---Communities?type=design&node-id=37206%3A86911&mode=design&t=LuuR3YcDBwDkWIBw-1 diff --git a/ui/StatusQ/src/assets.qrc b/ui/StatusQ/src/assets.qrc index be2f22ebd8..86c15111b7 100644 --- a/ui/StatusQ/src/assets.qrc +++ b/ui/StatusQ/src/assets.qrc @@ -10407,5 +10407,6 @@ assets/twemoji/LICENSE assets/twemoji/twemoji.js assets/img/icons/caution.svg + assets/img/icons/crown-off.svg diff --git a/ui/StatusQ/src/assets/img/icons/crown-off.svg b/ui/StatusQ/src/assets/img/icons/crown-off.svg new file mode 100644 index 0000000000..2e3cfe7ef7 --- /dev/null +++ b/ui/StatusQ/src/assets/img/icons/crown-off.svg @@ -0,0 +1,3 @@ + + + diff --git a/ui/app/mainui/activitycenter/popups/ActivityCenterPopup.qml b/ui/app/mainui/activitycenter/popups/ActivityCenterPopup.qml index 35a07ad510..e649556c57 100644 --- a/ui/app/mainui/activitycenter/popups/ActivityCenterPopup.qml +++ b/ui/app/mainui/activitycenter/popups/ActivityCenterPopup.qml @@ -4,6 +4,7 @@ import QtGraphicalEffects 1.15 import StatusQ.Core 0.1 import StatusQ.Controls 0.1 +import StatusQ.Core.Theme 0.1 import shared 1.0 import shared.popups 1.0 @@ -72,8 +73,8 @@ Popup { onGroupTriggered: activityCenterStore.setActiveNotificationGroup(group) onMarkAllReadClicked: activityCenterStore.markAllActivityCenterNotificationsRead() onShowHideReadNotifications: activityCenterStore.setActivityCenterReadType(hideReadNotifications ? - ActivityCenterStore.ActivityCenterReadType.Unread : - ActivityCenterStore.ActivityCenterReadType.All) + ActivityCenterStore.ActivityCenterReadType.Unread : + ActivityCenterStore.ActivityCenterReadType.All) } StatusListView { @@ -95,28 +96,34 @@ Popup { sourceComponent: { switch (model.notificationType) { - case ActivityCenterStore.ActivityCenterNotificationType.Mention: - return mentionNotificationComponent - case ActivityCenterStore.ActivityCenterNotificationType.Reply: - return replyNotificationComponent - case ActivityCenterStore.ActivityCenterNotificationType.ContactRequest: - return contactRequestNotificationComponent - case ActivityCenterStore.ActivityCenterNotificationType.ContactVerification: - return verificationRequestNotificationComponent - case ActivityCenterStore.ActivityCenterNotificationType.CommunityInvitation: - return communityInvitationNotificationComponent - case ActivityCenterStore.ActivityCenterNotificationType.CommunityMembershipRequest: - return membershipRequestNotificationComponent - case ActivityCenterStore.ActivityCenterNotificationType.CommunityRequest: - return communityRequestNotificationComponent - case ActivityCenterStore.ActivityCenterNotificationType.CommunityKicked: - return communityKickedNotificationComponent - case ActivityCenterStore.ActivityCenterNotificationType.ContactRemoved: - return contactRemovedComponent - case ActivityCenterStore.ActivityCenterNotificationType.NewKeypairAddedToPairedDevice: - return newKeypairFromPairedDeviceComponent - default: - return null + case ActivityCenterStore.ActivityCenterNotificationType.Mention: + return mentionNotificationComponent + case ActivityCenterStore.ActivityCenterNotificationType.Reply: + return replyNotificationComponent + case ActivityCenterStore.ActivityCenterNotificationType.ContactRequest: + return contactRequestNotificationComponent + case ActivityCenterStore.ActivityCenterNotificationType.ContactVerification: + return verificationRequestNotificationComponent + case ActivityCenterStore.ActivityCenterNotificationType.CommunityInvitation: + return communityInvitationNotificationComponent + case ActivityCenterStore.ActivityCenterNotificationType.CommunityMembershipRequest: + return membershipRequestNotificationComponent + case ActivityCenterStore.ActivityCenterNotificationType.CommunityRequest: + return communityRequestNotificationComponent + case ActivityCenterStore.ActivityCenterNotificationType.CommunityKicked: + return communityKickedNotificationComponent + case ActivityCenterStore.ActivityCenterNotificationType.ContactRemoved: + return contactRemovedComponent + case ActivityCenterStore.ActivityCenterNotificationType.NewKeypairAddedToPairedDevice: + return newKeypairFromPairedDeviceComponent + case ActivityCenterStore.ActivityCenterNotificationType.OwnerTokenReceived: + case ActivityCenterStore.ActivityCenterNotificationType.OwnershipDeclined: + case ActivityCenterStore.ActivityCenterNotificationType.OwnershipSucceeded: + case ActivityCenterStore.ActivityCenterNotificationType.OwnershipFailed: + case ActivityCenterStore.ActivityCenterNotificationType.NoLongerControlNode: + return ownerTokenReceivedNotificationComponent + default: + return null } } } @@ -232,4 +239,27 @@ Popup { onCloseActivityCenter: root.close() } } + + Component { + id: ownerTokenReceivedNotificationComponent + + ActivityNotificationTransferOwnership { + + readonly property var community : notification ? root.store.getCommunityDetailsAsJson(notification.communityId) : null + + type: setType(notification) + + communityName: community ? community.name : "" + communityColor: community ? community.color : Theme.palette.directColor1 + + filteredIndex: parent.filteredIndex + notification: parent.notification + store: root.store + activityCenterStore: root.activityCenterStore + onCloseActivityCenter: root.close() + + onFinaliseOwnershipClicked: Global.openFinaliseOwnershipPopup(notification.communityId) + onNavigateToCommunityClicked: root.store.setActiveCommunity(notification.communityId) + } + } } diff --git a/ui/app/mainui/activitycenter/stores/ActivityCenterStore.qml b/ui/app/mainui/activitycenter/stores/ActivityCenterStore.qml index 76a81f2ae4..44b3710465 100644 --- a/ui/app/mainui/activitycenter/stores/ActivityCenterStore.qml +++ b/ui/app/mainui/activitycenter/stores/ActivityCenterStore.qml @@ -30,7 +30,12 @@ QtObject { CommunityKicked = 9, ContactVerification = 10, ContactRemoved = 11, - NewKeypairAddedToPairedDevice = 12 + NewKeypairAddedToPairedDevice = 12, + OwnerTokenReceived = 13, + OwnershipDeclined = 14, + OwnershipSucceeded = 15, + OwnershipFailed = 16, + NoLongerControlNode = 17 } enum ActivityCenterReadType { diff --git a/ui/app/mainui/activitycenter/views/ActivityNotificationTransferOwnership.qml b/ui/app/mainui/activitycenter/views/ActivityNotificationTransferOwnership.qml new file mode 100644 index 0000000000..298b76617e --- /dev/null +++ b/ui/app/mainui/activitycenter/views/ActivityNotificationTransferOwnership.qml @@ -0,0 +1,216 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.14 + +import StatusQ.Controls 0.1 +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Components 0.1 + +import shared 1.0 +import shared.panels 1.0 +import utils 1.0 + +import "../panels" +import "../popups" +import "../stores" + +ActivityNotificationBase { + id: root + + required property string communityName + required property string communityColor + required property int type // Possible values [OwnershipState] + + signal finaliseOwnershipClicked + signal navigateToCommunityClicked + + function setType(notification) { + if(notification) + switch(notification.notificationType){ + + case ActivityCenterStore.ActivityCenterNotificationType.OwnerTokenReceived: + return ActivityNotificationTransferOwnership.OwnershipState.Pending + + case ActivityCenterStore.ActivityCenterNotificationType.OwnershipDeclined: + return ActivityNotificationTransferOwnership.OwnershipState.Declined + + case ActivityCenterStore.ActivityCenterNotificationType.OwnershipReceived: + return ActivityNotificationTransferOwnership.OwnershipState.Succeeded + + case ActivityCenterStore.ActivityCenterNotificationType.OwnershipFailed: + return ActivityNotificationTransferOwnership.OwnershipState.Failed + + case ActivityCenterStore.ActivityCenterNotificationType.OwnershipLost: + return ActivityNotificationTransferOwnership.OwnershipState.NoLongerControlNode + + } + return ActivityNotificationTransferOwnership.OwnershipState.Failed + } + + enum OwnershipState { + Pending, + Declined, + Succeeded, + Failed, + NoLongerControlNode + } + + QtObject { + id: d + + property string title: "" + property string info: "" + property string assetColor: "" + property string assetName: "" + property string assetBgColor: "" + property string ctaText: "" + property var actionSourceComponent: undefined + + readonly property string crownAssetName: "crown" + } + + bodyComponent: RowLayout { + spacing: 8 + + StatusSmartIdenticon { + Layout.preferredWidth: 40 + Layout.preferredHeight: 40 + Layout.alignment: Qt.AlignTop + Layout.leftMargin: Style.current.padding + Layout.topMargin: 2 + + asset { + width: 24 + height: width + name: d.assetName + color: d.assetColor + bgWidth: 40 + bgHeight: 40 + bgColor: d.assetBgColor + } + } + + ColumnLayout { + spacing: 2 + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true + + StatusMessageHeader { + displayNameLabel.text: d.title + timestamp: root.notification.timestamp + } + + RowLayout { + spacing: Style.current.padding + + StatusBaseText { + Layout.fillWidth: true + text: d.info + font.italic: true + wrapMode: Text.WordWrap + color: Theme.palette.baseColor1 + } + + Loader { sourceComponent: d.actionSourceComponent } + + } + } + } + + ctaComponent: undefined + + states: [ + State { + when: root.type === ActivityNotificationTransferOwnership.OwnershipState.Pending + PropertyChanges { + target: d + title: qsTr("You received the owner token from %1").arg(root.communityName) + info: qsTr("To finalise your ownership of the %1 Community, make your device the control node").arg(root.communityName) + ctaText: qsTr("Finalise ownership") + assetColor: root.communityColor + assetBgColor: Theme.palette.getColor(d.assetColor, 0.1) + assetName: d.crownAssetName + actionSourceComponent: ctaFlatBtnComponent + } + }, + State { + when: root.type === ActivityNotificationTransferOwnership.OwnershipState.Declined + PropertyChanges { + target: d + title: qsTr("You received the owner token from %1").arg(root.communityName) + info: qsTr("To finalise your ownership of the %1 Community, make your device the control node").arg(root.communityName) + ctaText: qsTr("Ownership Declined") + assetColor: root.communityColor + assetBgColor: Theme.palette.getColor(d.assetColor, 0.1) + assetName: d.crownAssetName + actionSourceComponent: ctaTextComponent + } + }, + State { + when: root.type === ActivityNotificationTransferOwnership.OwnershipState.Succeeded + PropertyChanges { + target: d + title: qsTr("Your device is now the control node for %1").arg(root.communityName) + info: qsTr("Congratulations, you are now the official owner of the %1 Community with full admin rights").arg(root.communityName) + ctaText: qsTr("Community admin") + assetColor: root.communityColor + assetBgColor: Theme.palette.getColor(d.assetColor, 0.1) + assetName: d.crownAssetName + actionSourceComponent: ctaFlatBtnComponent + } + }, + State { + when: root.type === ActivityNotificationTransferOwnership.OwnershipState.Failed + PropertyChanges { + target: d + title: qsTr("%1 smart contract update failed").arg(root.communityName) + info: qsTr("You will need to retry the transaction in order to finalise your ownership of the %1 community").arg(root.communityName) + ctaText: qsTr("Finalise ownership") + assetColor: Theme.palette.dangerColor1 + assetBgColor: Theme.palette.dangerColor3 + assetName: "warning" + actionSourceComponent: ctaFlatBtnComponent + } + }, + State { + when: root.type === ActivityNotificationTransferOwnership.OwnershipState.NoLongerControlNode + PropertyChanges { + target: d + title: qsTr("Your device is no longer the control node for %1").arg(root.communityName) + info: qsTr("Your ownership and admin rights for %1 have been removed and transferred to the new owner").arg(root.communityName) + ctaText: "" + assetColor: Theme.palette.dangerColor1 + assetBgColor: Theme.palette.dangerColor3 + assetName: "crown-off" + actionSourceComponent: undefined + } + } + ] + + Component { + id: ctaFlatBtnComponent + + StatusFlatButton { + size: StatusBaseButton.Size.Small + text: d.ctaText + onClicked: { + if((root.type === ActivityNotificationTransferOwnership.OwnershipState.Pending) || + (root.type === ActivityNotificationTransferOwnership.OwnershipState.Failed)) + root.finaliseOwnershipClicked() + else if(root.type === ActivityNotificationTransferOwnership.OwnershipState.Succeeded) + root.navigateToCommunityClicked() + } + } + } + + Component { + id: ctaTextComponent + + StatusBaseText { + text: d.ctaText + font.pixelSize: Style.current.additionalTextSize + color: Theme.palette.dangerColor1 + padding: 10 + } + } +} diff --git a/ui/app/mainui/activitycenter/views/qmldir b/ui/app/mainui/activitycenter/views/qmldir index 675ac97c5e..64e97907d0 100644 --- a/ui/app/mainui/activitycenter/views/qmldir +++ b/ui/app/mainui/activitycenter/views/qmldir @@ -1 +1,2 @@ -ActivityNotificationCommunityMembershipRequest 1.0 ActivityNotificationCommunityMembershipRequest.qml \ No newline at end of file +ActivityNotificationCommunityMembershipRequest 1.0 ActivityNotificationCommunityMembershipRequest.qml +ActivityNotificationTransferOwnership 1.0 ActivityNotificationTransferOwnership.qml