From 3b5791515531a6379bfa16db2f895be60a66693e Mon Sep 17 00:00:00 2001 From: Alex Jbanca Date: Thu, 6 Jul 2023 11:02:41 +0300 Subject: [PATCH] feat: Implement Community Overview footer with mocked data 1. Adding OverviewSettingsFooter.qml according to design 2. Adding the footer to storybook 3. Add the footer in the overview page 4. Remove the squish tests for the old footer --- storybook/PagesModel.qml | 4 + storybook/figma.json | 3 + .../pages/OverviewSettingsFooterPage.qml | 58 ++++++++ .../src/screens/StatusCommunityScreen.py | 23 +-- .../shared/scripts/community_names.py | 7 - .../shared/steps/communitySteps.py | 8 -- .../tst_communityManageOverview/test.feature | 47 +++---- ui/StatusQ/src/assets.qrc | 1 + .../src/assets/img/icons/external-link.svg | 5 + .../panels/JoinPermissionsOverlayPanel.qml | 7 +- .../panels/OverviewSettingsFooter.qml | 133 ++++++++++++++++++ .../panels/OverviewSettingsPanel.qml | 46 ++---- ui/app/AppLayouts/Communities/panels/qmldir | 1 + .../views/CommunitySettingsView.qml | 1 + ui/imports/utils/Constants.qml | 7 + 15 files changed, 246 insertions(+), 105 deletions(-) create mode 100644 storybook/pages/OverviewSettingsFooterPage.qml create mode 100644 ui/StatusQ/src/assets/img/icons/external-link.svg create mode 100644 ui/app/AppLayouts/Communities/panels/OverviewSettingsFooter.qml diff --git a/storybook/PagesModel.qml b/storybook/PagesModel.qml index 63a5c9d6e2..59639a316b 100644 --- a/storybook/PagesModel.qml +++ b/storybook/PagesModel.qml @@ -181,6 +181,10 @@ ListModel { title: "EditSettingsPanel" section: "Panels" } + ListElement { + title: "OverviewSettingsFooter" + section: "Panels" + } ListElement { title: "BurnTokensPopup" section: "Popups" diff --git a/storybook/figma.json b/storybook/figma.json index 492615c040..514ed0fd1f 100644 --- a/storybook/figma.json +++ b/storybook/figma.json @@ -227,5 +227,8 @@ ], "EditSettingsPanel": [ "https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba⎜Desktop?node-id=3132%3A383870&mode=dev" + ], + "OverviewSettingsFooter": [ + "https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba⎜Desktop?type=design&node-id=31171-629792&mode=design&t=IAlt2Frp5gx0yPAn-0" ] } diff --git a/storybook/pages/OverviewSettingsFooterPage.qml b/storybook/pages/OverviewSettingsFooterPage.qml new file mode 100644 index 0000000000..6d5bc5da31 --- /dev/null +++ b/storybook/pages/OverviewSettingsFooterPage.qml @@ -0,0 +1,58 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +import AppLayouts.Communities.panels 1.0 + +import utils 1.0 + +SplitView { + id: root + + Item { + id: wrapper + SplitView.fillWidth: true + SplitView.fillHeight: true + OverviewSettingsFooter { + id: footer + width: parent.width + anchors.centerIn: parent + isControlNode: controlNodeSwitch.checked + communityName: "Socks" + } + } + + Pane { + SplitView.preferredWidth: 300 + SplitView.fillHeight: true + + ColumnLayout { + Switch { + id: controlNodeSwitch + text: "Control node on/off" + checked: true + } + + ColumnLayout { + Label { + Layout.fillWidth: true + text: "Login type::" + } + + RadioButton { + checked: true + text: qsTr("Password") + onCheckedChanged: if(checked) footer.loginType = Constants.LoginType.Password + } + RadioButton { + text: qsTr("Biometrics") + onCheckedChanged: if(checked) footer.loginType = Constants.LoginType.Biometrics + } + RadioButton { + text: qsTr("Keycard") + onCheckedChanged: if(checked) footer.loginType = Constants.LoginType.Keycard + } + } + } + } +} diff --git a/test/ui-test/src/screens/StatusCommunityScreen.py b/test/ui-test/src/screens/StatusCommunityScreen.py index 122c3cfb9d..dfa5fa14bb 100644 --- a/test/ui-test/src/screens/StatusCommunityScreen.py +++ b/test/ui-test/src/screens/StatusCommunityScreen.py @@ -111,14 +111,7 @@ class CreateOrEditCommunityCategoryPopup(Enum): COMMUNITY_CATEGORY_LIST: str = "createOrEditCommunityCategoryChannelList_ListView" COMMUNITY_CATEGORY_LIST_ITEM_PLACEHOLDER: str = "createOrEditCommunityCategoryChannelList_ListItem_Placeholder" COMMUNITY_CATEGORY_BUTTON: str = "createOrEditCommunityCategoryBtn_StatusButton" - MODAL_CLOSE_BUTTON = "modal_Close_Button" - -class CommunityOverviewScreenComponents(Enum): - # Constants definitions: - COMMUNITY_PRIVATE_KEY_LENGHT_UI = 35 # length of community PK on the Transfer Ownership popup - # Components: - COMMUNITY_OVERVIEW_BACK_UP_BUTTON ="communityOverview_Back_up_StatusButton" - COMMUNITY_OVERVIEW_AIRDROP_TOKENS_BUTTON="communityOverview_Airdrop_Tokens_StatusButton" + MODAL_CLOSE_BUTTON = "modal_Close_Button" class StatusCommunityScreen: @@ -575,18 +568,4 @@ class StatusCommunityScreen: assert BaseElement(str(CommunityWelcomeScreenComponents.ADD_NEW_ITEM_BUTTON.value)).is_enabled button_title = get_obj(CommunityWelcomeScreenComponents.ADD_NEW_ITEM_BUTTON.value).text verify_equals(option, str(button_title)) - - def verify_community_private_key(self): - Button(CommunityOverviewScreenComponents.COMMUNITY_OVERVIEW_BACK_UP_BUTTON.value).click() - transferOwnershipPopup = BackUpCommunityPrivateKeyPopup().wait_until_appears() - transferOwnershipPopup.copy_community_private_key() - community_private_key = transferOwnershipPopup.private_key - assert len(community_private_key) == (CommunityOverviewScreenComponents.COMMUNITY_PRIVATE_KEY_LENGHT_UI.value), f"Current key length: {len(community_private_key)}" - assert community_private_key.startswith("0x"), f"Current private key does not start with 0x: {community_private_key}" - - def open_airdrops_from_overview(self): - Button(CommunityOverviewScreenComponents.COMMUNITY_OVERVIEW_AIRDROP_TOKENS_BUTTON.value).click() - welcome_screen_title = get_obj(CommunityWelcomeScreenComponents.WELCOME_SCREEN_TITLE.value).text - ref_value = CommunityWelcomeScreenComponents.WELCOME_SCREEN_TITLE_OPTION_AIRDROPS.value - assert welcome_screen_title == ref_value, f"Current screen title: {welcome_screen_title}, expected: {ref_value}" \ No newline at end of file diff --git a/test/ui-test/testSuites/suite_communities/shared/scripts/community_names.py b/test/ui-test/testSuites/suite_communities/shared/scripts/community_names.py index d339a463af..eb6195eff3 100644 --- a/test/ui-test/testSuites/suite_communities/shared/scripts/community_names.py +++ b/test/ui-test/testSuites/suite_communities/shared/scripts/community_names.py @@ -85,13 +85,6 @@ communitySettings_EditCommunity_ColorPicker_Button = {"container": communitySett communitySettings_ColorPanel_HexColor_Input = {"container": statusDesktop_mainWindow_overlay, "objectName": "communityColorPanelHexInput", "type": "TextEdit", "visible": True} communitySettings_SaveColor_Button = {"container": statusDesktop_mainWindow_overlay, "objectName": "communityColorPanelSelectColorButton", "type": "StatusButton", "visible": True} -# Community Overview -communityOverview_Back_up_Banner = {"container": statusDesktop_mainWindow, "objectName": "backUpBanner", "type": "BannerPanel", "visible": True} -communityOverview_Back_up_StatusButton = {"container": communityOverview_Back_up_Banner, "objectName": "communityBannerButton", "type": "StatusButton", "visible": True} -communityOverview_Airdrop_Tokens_Banner = {"container": statusDesktop_mainWindow, "objectName": "airdropBanner", "type": "BannerPanel", "visible": True} -communityOverview_Airdrop_Tokens_StatusButton = {"container": communityOverview_Airdrop_Tokens_Banner, "objectName": "communityBannerButton", "type": "StatusButton", "visible": True} -transferOwnerShipTextEdit = {"container": statusDesktop_mainWindow_overlay, "id": "edit", "type": "TextEdit", "unnamed": 1, "visible": True} - # Community transfer ownership copyCommunityPrivateKeyButton = {"container": statusDesktop_mainWindow, "objectName": "copyCommunityPrivateKeyButton", "type": "StatusButton", "visible": True} diff --git a/test/ui-test/testSuites/suite_communities/shared/steps/communitySteps.py b/test/ui-test/testSuites/suite_communities/shared/steps/communitySteps.py index 603828a56a..8a8e88c8a5 100644 --- a/test/ui-test/testSuites/suite_communities/shared/steps/communitySteps.py +++ b/test/ui-test/testSuites/suite_communities/shared/steps/communitySteps.py @@ -267,14 +267,6 @@ def step(context, option:str, list): @Then("\"|any|\" button is present") def step (context, action_button_name): _statusCommunityScreen.verify_action_button_enabled(action_button_name) - -@Then("the user is able to open Back up modal and copy private key") -def step(context): - _statusCommunityScreen.verify_community_private_key() - -@Then("the user is able to click Airdrop Tokens button and navigate to Airdrops screen") -def step(context): - _statusCommunityScreen.open_airdrops_from_overview() ########################################################################### ### COMMON methods used in different steps given/when/then region: diff --git a/test/ui-test/testSuites/suite_communities/tst_communityManageOverview/test.feature b/test/ui-test/testSuites/suite_communities/tst_communityManageOverview/test.feature index 91b58d8f77..c078dbed11 100644 --- a/test/ui-test/testSuites/suite_communities/tst_communityManageOverview/test.feature +++ b/test/ui-test/testSuites/suite_communities/tst_communityManageOverview/test.feature @@ -4,33 +4,22 @@ Feature: Community -> Manage Community -> Overview page -Background: - Given A first time user lands on the status desktop and generates new key - And the user signs up with username "tester123" and password "TesTEr16843/!@00" - And the user lands on the signed in app - And the user opens the community portal section - And the user lands on the community portal section - And the user creates a community named "Test-Community", with description "My community description", intro "Community Intro" and outro "Community Outro" - And the user lands on the community named "Test-Community" + Background: + Given A first time user lands on the status desktop and generates new key + And the user signs up with username "tester123" and password "TesTEr16843/!@00" + And the user lands on the signed in app + And the user opens the community portal section + And the user lands on the community portal section + And the user creates a community named "Test-Community", with description "My community description", intro "Community Intro" and outro "Community Outro" + And the user lands on the community named "Test-Community" -Scenario: Community admin is able to back up community key from community overview page - When "Manage Community" is clicked in the community sidebar - And "Overview" section is selected - Then the user is able to open Back up modal and copy private key - -Scenario: Community admin is able to navigate to Airdrops page from Overview screen - When "Manage Community" is clicked in the community sidebar - And "Overview" section is selected - Then the user is able to click Airdrop Tokens button and navigate to Airdrops screen - - - Scenario Outline: Manage community -> Overview: community admin edits the community name, description and color - When the admin renames the community to "" and description to "" and color to "" - Then the community overview name is "" - And the community overview description is "" - And the community overview color is "" - When the admin goes back to the community - Then the user lands on the community named "" - Examples: - | new_community_name | new_community_description | new_community_color | - | myCommunityNamedChanged | Cool new description 123 | #ff0000 | \ No newline at end of file + Scenario Outline: Manage community -> Overview: community admin edits the community name, description and color + When the admin renames the community to "" and description to "" and color to "" + Then the community overview name is "" + And the community overview description is "" + And the community overview color is "" + When the admin goes back to the community + Then the user lands on the community named "" + Examples: + | new_community_name | new_community_description | new_community_color | + | myCommunityNamedChanged | Cool new description 123 | #ff0000 | \ No newline at end of file diff --git a/ui/StatusQ/src/assets.qrc b/ui/StatusQ/src/assets.qrc index 20ad760c20..6fd71584c2 100644 --- a/ui/StatusQ/src/assets.qrc +++ b/ui/StatusQ/src/assets.qrc @@ -185,6 +185,7 @@ assets/img/icons/ETH.png assets/img/icons/exchange.svg assets/img/icons/external.svg + assets/img/icons/external-link.svg assets/img/icons/face-id.svg assets/img/icons/face-sad.svg assets/img/icons/favourite.svg diff --git a/ui/StatusQ/src/assets/img/icons/external-link.svg b/ui/StatusQ/src/assets/img/icons/external-link.svg new file mode 100644 index 0000000000..d30228d68d --- /dev/null +++ b/ui/StatusQ/src/assets/img/icons/external-link.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/ui/app/AppLayouts/Communities/panels/JoinPermissionsOverlayPanel.qml b/ui/app/AppLayouts/Communities/panels/JoinPermissionsOverlayPanel.qml index f673d6ffb3..38679e9b39 100644 --- a/ui/app/AppLayouts/Communities/panels/JoinPermissionsOverlayPanel.qml +++ b/ui/app/AppLayouts/Communities/panels/JoinPermissionsOverlayPanel.qml @@ -61,11 +61,6 @@ Control { return root.joinCommunity ? (root.requiresRequest ? d.communityRevealAddressWithRequestText : d.communityRevealAddressText) : d.channelRevealAddressText } - function getRevealAddressIcon() { - if(root.loginType == Constants.LoginType.Password) return "password" - return root.loginType == Constants.LoginType.Biometrics ? "touch-id" : "keycard" - } - function filterPermissions(model) { return !!model && (model.tokenCriteriaMet || !model.isPrivate) } @@ -153,7 +148,7 @@ Control { Layout.alignment: Qt.AlignHCenter visible: !root.showOnlyPanels && !root.isJoinRequestRejected && root.requiresRequest text: root.isInvitationPending ? d.getInvitationPendingText() : d.getRevealAddressText() - icon.name: root.isInvitationPending ? "" : d.getRevealAddressIcon() + icon.name: root.isInvitationPending ? "" : Constants.authenticationIconByType[root.loginType] font.pixelSize: 13 enabled: root.requirementsMet || d.communityPermissionsModel.count == 0 onClicked: root.isInvitationPending ? root.invitationPendingClicked() : root.revealAddressClicked() diff --git a/ui/app/AppLayouts/Communities/panels/OverviewSettingsFooter.qml b/ui/app/AppLayouts/Communities/panels/OverviewSettingsFooter.qml new file mode 100644 index 0000000000..f1ed11aeb9 --- /dev/null +++ b/ui/app/AppLayouts/Communities/panels/OverviewSettingsFooter.qml @@ -0,0 +1,133 @@ +import QtQuick 2.15 +import QtQml 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +import StatusQ.Components 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 + +import utils 1.0 + +Control { + id: root + property bool isControlNode: true + property int loginType: Constants.LoginType.Password + property string communityName: "" + + signal primaryButtonClicked + signal secondaryButtonClicked + + QtObject { + id: d + + readonly property real verticalBreakPoint: 950 + readonly property bool twoRowsLayout: contentItem.width <= verticalBreakPoint + + property string paragraphTitle + property string paragraphSubtitle + property string primaryButtonText + property string primaryButtonIcon + property string secondaryButtonText + property string secondaryButtonIcon + property string indicatorBgColor + property string indicatorColor + } + + contentItem: GridLayout { + id: mainGrid + columnSpacing: 16 + rowSpacing: 16 + + StatusRoundIcon { + id: icon + Layout.row: 0 + Layout.column: 0 + color: d.indicatorBgColor + asset.color: d.indicatorColor + asset.name: "desktop" + } + + ColumnLayout { + id: paragraph + Layout.row: 0 + Layout.column: 1 + Layout.columnSpan: d.twoRowsLayout ? 2 : 1 + Layout.fillWidth: true + spacing: 4 + StatusBaseText { + id: title + Layout.fillWidth: true + text: d.paragraphTitle + font.pixelSize: 15 + font.bold: true + color: Theme.palette.directColor1 + wrapMode: Text.WordWrap + } + + StatusBaseText { + id: subtitle + Layout.fillWidth: true + text: d.paragraphSubtitle + font.pixelSize: 15 + color: Theme.palette.baseColor1 + wrapMode: Text.WordWrap + } + } + + Item { + Layout.fillWidth: true + Layout.row: 0 + Layout.column: 3 + } + + RowLayout { + Layout.row: d.twoRowsLayout ? 1 : 0 + Layout.column: d.twoRowsLayout ? 1 : 4 + Layout.alignment: Qt.AlignLeft + + StatusFlatButton { + size: StatusBaseButton.Size.Small + text: d.secondaryButtonText + icon.name: d.secondaryButtonIcon + onClicked: root.secondaryButtonClicked() + } + + StatusButton { + size: StatusBaseButton.Size.Small + text: d.primaryButtonText + icon.name: d.primaryButtonIcon + onClicked: root.primaryButtonClicked() + } + } + } + + // Behavior + states: [ + State { + name: "isControlNode" + when: root.isControlNode + PropertyChanges { target: d; indicatorBgColor: Theme.palette.successColor2 } + PropertyChanges { target: d; indicatorColor: Theme.palette.successColor1 } + PropertyChanges { target: d; paragraphTitle: qsTr("This device is currently the control node for the %1 Community").arg(root.communityName) } + PropertyChanges { target: d; paragraphSubtitle: qsTr("For your Community to function correctly keep this device online with Status running as much as possible.") } + PropertyChanges { target: d; primaryButtonText: qsTr("Move control node") } + PropertyChanges { target: d; primaryButtonIcon: Constants.authenticationIconByType[root.loginType] } + PropertyChanges { target: d; secondaryButtonText: qsTr("Learn more") } + PropertyChanges { target: d; secondaryButtonIcon: "external-link" } + }, + State { + name: "isNotControlNode" + when: !root.isControlNode + PropertyChanges { target: d; indicatorBgColor: Theme.palette.primaryColor3 } + PropertyChanges { target: d; indicatorColor: Theme.palette.primaryColor1 } + PropertyChanges { target: d; paragraphTitle: qsTr("Make this device the control node for the %1 Community").arg(root.communityName) } + PropertyChanges { target: d; paragraphSubtitle: qsTr("You will need to input the Community private key. Ensure this is a device you can keep online with Status running.") } + PropertyChanges { target: d; primaryButtonText: qsTr("Make this device the control node") } + PropertyChanges { target: d; primaryButtonIcon: "" } + PropertyChanges { target: d; secondaryButtonText: qsTr("Learn more") } + PropertyChanges { target: d; secondaryButtonIcon: "external-link" } + } + ] +} diff --git a/ui/app/AppLayouts/Communities/panels/OverviewSettingsPanel.qml b/ui/app/AppLayouts/Communities/panels/OverviewSettingsPanel.qml index 5b788c463c..5fee094a16 100644 --- a/ui/app/AppLayouts/Communities/panels/OverviewSettingsPanel.qml +++ b/ui/app/AppLayouts/Communities/panels/OverviewSettingsPanel.qml @@ -35,6 +35,7 @@ StackLayout { property bool editable: false property bool owned: false + property int loginType: Constants.LoginType.Password function navigateBack() { if (editSettingsPanelLoader.item.dirty) @@ -138,40 +139,19 @@ StackLayout { Item { Layout.fillHeight: true } + } - RowLayout { - BannerPanel { - objectName: "invitePeopleBanner" - text: qsTr("Welcome to your community!") - buttonText: qsTr("Invite new people") - icon.name: "invite-users" - onButtonClicked: root.inviteNewPeopleClicked() - } - Item { - Layout.fillWidth: true - } - BannerPanel { - objectName: "airdropBanner" - visible: root.owned - text: qsTr("Try an airdrop to reward your community for engagement!") - buttonText: qsTr("Airdrop Tokens") - icon.name: "airdrop" - onButtonClicked: root.airdropTokensClicked() - } - - Item { - Layout.fillWidth: true - } - - BannerPanel { - objectName: "backUpBanner" - visible: root.owned - text: qsTr("Back up community key") - buttonText: qsTr("Back up") - icon.name: "objects" - onButtonClicked: root.backUpClicked() - } - } + footer: OverviewSettingsFooter { + rightPadding: 64 + leftPadding: 64 + bottomPadding: 50 + loginType: root.loginType + communityName: root.name + //TODO connect to backend + isControlNode: root.owned + onPrimaryButtonClicked: isControlNode = !isControlNode + //TODO update once the domain changes + onSecondaryButtonClicked: Global.openLink(Constants.statusHelpLinkPrefix + "en/status-communities/about-the-control-node-in-status-communities") } } diff --git a/ui/app/AppLayouts/Communities/panels/qmldir b/ui/app/AppLayouts/Communities/panels/qmldir index e86e874cba..97101da706 100644 --- a/ui/app/AppLayouts/Communities/panels/qmldir +++ b/ui/app/AppLayouts/Communities/panels/qmldir @@ -14,6 +14,7 @@ JoinPermissionsOverlayPanel 1.0 JoinPermissionsOverlayPanel.qml MembersSettingsPanel 1.0 MembersSettingsPanel.qml MintTokensFooterPanel 1.0 MintTokensFooterPanel.qml MintTokensSettingsPanel 1.0 MintTokensSettingsPanel.qml +OverviewSettingsFooter 1.0 OverviewSettingsFooter.qml OverviewSettingsPanel 1.0 OverviewSettingsPanel.qml PermissionConflictWarningPanel 1.0 PermissionConflictWarningPanel.qml PermissionQualificationPanel 1.0 PermissionQualificationPanel.qml diff --git a/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml b/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml index 46c5dcdfd6..72c9c35d31 100644 --- a/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml +++ b/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml @@ -169,6 +169,7 @@ StatusSectionLayout { pinMessagesEnabled: root.community.pinMessageAllMembersEnabled editable: true owned: root.community.memberRole === Constants.memberRole.owner + loginType: root.rootStore.loginType onEdited: { const error = root.chatCommunitySectionModule.editCommunity( diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml index 42ae60527d..69daa1d74f 100644 --- a/ui/imports/utils/Constants.qml +++ b/ui/imports/utils/Constants.qml @@ -848,6 +848,7 @@ QtObject { readonly property string communityLinkPrefix: externalStatusLinkWithHttps + '/c/' readonly property string userLinkPrefix: externalStatusLinkWithHttps + '/u/' readonly property string statusLinkPrefix: 'https://status.im/' + readonly property string statusHelpLinkPrefix: `https://help.status.im/` readonly property int maxUploadFiles: 5 readonly property double maxUploadFilesizeMB: 10 @@ -914,6 +915,12 @@ QtObject { Biometrics, Keycard } + // Needs to match the enum above + readonly property var authenticationIconByType: [ + "password", + "touch-id", + "keycard", + ] enum ComputeFeeErrorCode { Success,