diff --git a/storybook/pages/CopyButtonPage.qml b/storybook/pages/CopyButtonPage.qml new file mode 100644 index 0000000000..b6f8c86a07 --- /dev/null +++ b/storybook/pages/CopyButtonPage.qml @@ -0,0 +1,21 @@ +import QtQuick 2.15 +import QtQuick.Layouts 1.15 + +import shared.controls 1.0 + +Item { + RowLayout { + anchors.centerIn: parent + + CopyButton { + textToCopy: "Some text" + } + + CopyButtonWithCircle { + textToCopy: "Some text" + successCircleVisible: true + } + } +} + +// category: Controls diff --git a/storybook/pages/ReceiveModalPage.qml b/storybook/pages/ReceiveModalPage.qml new file mode 100644 index 0000000000..7da99f8cab --- /dev/null +++ b/storybook/pages/ReceiveModalPage.qml @@ -0,0 +1,100 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +import Storybook 1.0 +import Models 1.0 +import AppLayouts.Wallet.popups 1.0 + +SplitView { + orientation: Qt.Horizontal + + PopupBackground { + id: popupBg + + property var popupIntance: null + + SplitView.fillWidth: true + SplitView.fillHeight: true + + Button { + id: reopenButton + anchors.centerIn: parent + text: "Reopen" + enabled: !dialog.visible + + onClicked: dialog.open() + } + + ReceiveModal { + id: dialog + + visible: true + accounts: ListModel { + ListElement { + position: 0 + name: "My account" + } + } + selectedAccount: { + "name": "My account", + "emoji": "", + "address": "0x1234567890123456789012345678901234567890", + "preferredSharingChainIds": "opt:eth:" + } + switchingAccounsEnabled: true + changingPreferredChainsEnabled: true + hasFloatingButtons: true + qrImageSource: "https://upload.wikimedia.org/wikipedia/commons/4/41/QR_Code_Example.svg" + getNetworkShortNames: function (chainIDsString) { + return networksNames + } + + property string networksNames: "opt:arb:eth:" + + store: NetworksModel + } + } + + Pane { + SplitView.minimumWidth: 300 + SplitView.preferredWidth: 300 + + Column { + spacing: 12 + + Label { + text: "Test extended footer" + font.bold: true + } + + Column { + RadioButton { + text: "Medium length address" + onCheckedChanged: { + dialog.networksNames = "opt:arb:eth:arb:solana:status:other:" + } + } + + RadioButton { + text: "Super long address" + onCheckedChanged: { + dialog.networksNames = "opt:arb:eth:arb:solana:status:other:something:hey:whatsapp:tele:viber:do:it:now:blackjack:some:black:number:check:it:out:heyeey:dosay:what:are:you:going:to:do:with:me:forever:young:michael:jackson:super:long:string:crasy:daisy:this:is:amazing:whatever:you:do:whenever:you:go:" + } + } + + RadioButton { + checked: true + text: "Short address" + onCheckedChanged: { + dialog.networksNames = "opt:arb:eth:" + } + } + } + } + } +} + +// category: Popups + +// https://www.figma.com/file/FkFClTCYKf83RJWoifWgoX/Wallet-v2?type=design&node-id=20734-337595&mode=design&t=2O68lxNGG9g1b1tx-4 diff --git a/ui/app/AppLayouts/Wallet/controls/qmldir b/ui/app/AppLayouts/Wallet/controls/qmldir index 4f7f38ae48..3d43a86c06 100644 --- a/ui/app/AppLayouts/Wallet/controls/qmldir +++ b/ui/app/AppLayouts/Wallet/controls/qmldir @@ -11,3 +11,4 @@ ManageTokensCommunityTag 1.0 ManageTokensCommunityTag.qml ManageTokensDelegate 1.0 ManageTokensDelegate.qml ManageTokensGroupDelegate 1.0 ManageTokensGroupDelegate.qml InformationTileAssetDetails 1.0 InformationTileAssetDetails.qml +StatusNetworkListItemTag 1.0 StatusNetworkListItemTag.qml diff --git a/ui/app/AppLayouts/Wallet/popups/ReceiveModal.qml b/ui/app/AppLayouts/Wallet/popups/ReceiveModal.qml index 3819bf138b..8f75e58ca4 100644 --- a/ui/app/AppLayouts/Wallet/popups/ReceiveModal.qml +++ b/ui/app/AppLayouts/Wallet/popups/ReceiveModal.qml @@ -18,6 +18,8 @@ import shared.popups 1.0 import shared.popups.send.controls 1.0 import AppLayouts.stores 1.0 +import AppLayouts.Wallet.controls 1.0 + import ".." import "../stores" @@ -30,6 +32,13 @@ StatusModal { property bool switchingAccounsEnabled: true property bool changingPreferredChainsEnabled: true + property string qrImageSource: RootStore.getQrCode(d.visibleAddress) + property var getNetworkShortNames: function(chainIDsString) { + return RootStore.getNetworkShortNames(chainIDsString) + } + + property var store: RootStore + signal selectedAccountIndexChanged(int selectedIndex) signal updatePreferredChains(string address, string preferredChains) @@ -53,7 +62,7 @@ StatusModal { } selectedAccount: root.selectedAccount - getNetworkShortNames: RootStore.getNetworkShortNames + getNetworkShortNames: root.getNetworkShortNames onSelectedIndexChanged: { root.selectedAccountIndexChanged(selectedIndex) } @@ -63,10 +72,11 @@ StatusModal { showAdvancedFooter: true advancedFooterComponent: Rectangle { width: parent.width - height: d.advanceFooterHeight + height: rowLayout.height + 56 // Makes it totally 88 for one liner text as per design color: Theme.palette.baseColor4 - radius: 16 + radius: 8 + // Hide round corners of the upper part Rectangle { anchors.left: parent.left anchors.top: parent.top @@ -75,6 +85,7 @@ StatusModal { color: parent.color } + // Divider Rectangle { anchors.left: parent.left anchors.top: parent.top @@ -83,24 +94,39 @@ StatusModal { color: Theme.palette.baseColor2 } - StatusBaseText { - anchors.left: parent.left - anchors.leftMargin: Style.current.bigPadding - anchors.verticalCenter: parent.verticalCenter - text: WalletUtils.colorizedChainPrefix(d.preferredChainShortNames) + root.selectedAccount.address - font.pixelSize: 15 - color: Theme.palette.directColor1 - } + Item { // Needed to avoid binding loop warnings + anchors.centerIn: parent + height: childrenRect.height + width: parent.width - StatusRoundButton { - width: 32 - height: 32 - anchors.right: parent.right - anchors.rightMargin: Style.current.bigPadding - anchors.verticalCenter: parent.verticalCenter - icon.name: "copy" - type: StatusRoundButton.Type.Tertiary - onClicked: RootStore.copyToClipboard(d.visibleAddress) + RowLayout { + id: rowLayout + + width: parent.width + + StatusBaseText { + Layout.leftMargin: Style.current.bigPadding + Layout.preferredWidth: parent.width - copyButton.width + Layout.fillWidth: true + verticalAlignment: Text.AlignVCenter + textFormat: TextEdit.RichText + wrapMode: Text.WrapAnywhere + text: WalletUtils.colorizedChainPrefix(d.preferredChainShortNames) + root.selectedAccount.address + font.pixelSize: 15 + color: Theme.palette.directColor1 + } + + CopyButtonWithCircle { + id: copyButton + + Layout.rightMargin: Style.current.bigPadding + Layout.preferredWidth: 32 + Layout.preferredHeight: 32 + Layout.fillWidth: true + textToCopy: d.visibleAddress + successCircleVisible: true + } + } } } @@ -117,12 +143,10 @@ StatusModal { property var preferredChainIdsArray: root.selectedAccount.preferredSharingChainIds.split(":").filter(Boolean) property var preferredChainIds: d.preferredChainIdsArray.join(":") - readonly property string preferredChainShortNames: d.multiChainView? RootStore.getNetworkShortNames(d.preferredChainIds) : "" + readonly property string preferredChainShortNames: d.multiChainView? root.getNetworkShortNames(d.preferredChainIds) : "" readonly property string visibleAddress: "%1%2".arg(d.preferredChainShortNames).arg(root.selectedAccount.address) readonly property var networkProxies: [layer1NetworksClone, layer2NetworksClone] - - } Column { @@ -191,23 +215,21 @@ StatusModal { fillMode: Image.PreserveAspectFit mipmap: true smooth: false - source: RootStore.getQrCode(d.visibleAddress) + source: root.qrImageSource } Rectangle { anchors.centerIn: qrCodeImage - width: 78 - height: 78 + width: 88 + height: 88 color: "white" + radius: width / 2 StatusSmartIdenticon { anchors.centerIn: parent - anchors.margins: 2 - width: 78 - height: 78 name: root.selectedAccount.name asset { - width: 78 - height: 78 + width: 72 + height: 72 name: !root.selectedAccount.name && !root.selectedAccount.emoji? "status-logo-icon" : "" color: !root.selectedAccount.name && !root.selectedAccount.emoji? "transparent" : Utils.getColorForId(root.selectedAccount.colorId) emoji: root.selectedAccount.emoji @@ -241,11 +263,11 @@ StatusModal { model: d.networkProxies.length delegate: Repeater { model: d.networkProxies[index] - delegate: InformationTag { - tagPrimaryLabel.text: model.shortName - tagPrimaryLabel.color: model.chainColor + delegate: StatusNetworkListItemTag { + enabled: false + button.visible: false + title: model.shortName asset.name: Style.svg("tiny/" + model.iconUrl) - asset.isImage: true visible: d.preferredChainIdsArray.includes(model.chainId.toString()) } } @@ -269,7 +291,9 @@ StatusModal { id: selectPopup x: editButton.width - width - y: editButton.height + 8 + y: editButton.height + 2 + + margins: -1 // to allow positioning outside the bounds of the dialog layer1Networks: layer1NetworksClone layer2Networks: layer2NetworksClone @@ -291,7 +315,7 @@ StatusModal { CloneModel { id: layer1NetworksClone - sourceModel: RootStore.layer1Networks + sourceModel: root.store.layer1Networks roles: ["layer", "chainId", "chainColor", "chainName","shortName", "iconUrl", "isEnabled"] // rowData used to clone returns string. Convert it to bool for bool arithmetics rolesOverride: [{ @@ -303,7 +327,7 @@ StatusModal { CloneModel { id: layer2NetworksClone - sourceModel: RootStore.layer2Networks + sourceModel: root.store.layer2Networks roles: layer1NetworksClone.roles rolesOverride: layer1NetworksClone.rolesOverride } diff --git a/ui/imports/shared/controls/CopyButtonWithCircle.qml b/ui/imports/shared/controls/CopyButtonWithCircle.qml new file mode 100644 index 0000000000..9d36f942f3 --- /dev/null +++ b/ui/imports/shared/controls/CopyButtonWithCircle.qml @@ -0,0 +1,69 @@ +import QtQuick 2.15 +import QtQml 2.15 + +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 + +import utils 1.0 +import shared.stores 1.0 + +StatusRoundButton { + id: root + + required property string textToCopy + + icon.name: d.copied ? "tiny/checkmark" : "copy" + icon.width: 20 + icon.height: 20 + + type: StatusRoundButton.Type.Tertiary + + property bool successCircleVisible: false + + implicitWidth: 32 + implicitHeight: 32 + + Binding on icon.color { + when: successCircleVisible && d.copied + value: Theme.palette.successColor1 + restoreMode: Binding.RestoreBindingOrValue + } + + Binding on icon.hoverColor { + when: successCircleVisible && d.copied + value: Theme.palette.successColor1 + restoreMode: Binding.RestoreBindingOrValue + } + + Binding on color { + when: successCircleVisible && d.copied + value: Theme.palette.successColor2 + restoreMode: Binding.RestoreBindingOrValue + } + + Rectangle { + id: greenCircleAroundIcon + + anchors.centerIn: parent + width: icon.width + height: width + radius: width / 2 + border.width: 1 + border.color: d.copied ? Theme.palette.successColor1 : "transparent" + color: "transparent" + visible: root.successCircleVisible + } + + QtObject { + id: d + property bool copied: false + } + + onClicked: { + RootStore.copyToClipboard(root.textToCopy) + d.copied = true + Backpressure.debounce(root, 1500, function () { + d.copied = false + })() + } +} diff --git a/ui/imports/shared/controls/qmldir b/ui/imports/shared/controls/qmldir index 3f61361ed9..89efaca741 100644 --- a/ui/imports/shared/controls/qmldir +++ b/ui/imports/shared/controls/qmldir @@ -6,6 +6,7 @@ AssetsDetailsHeader 1.0 AssetsDetailsHeader.qml ContactSelector 1.0 ContactSelector.qml ContactsListAndSearch 1.0 ContactsListAndSearch.qml CopyButton 1.0 CopyButton.qml +CopyButtonWithCircle 1.0 CopyButtonWithCircle.qml CopyToClipBoardButton 1.0 CopyToClipBoardButton.qml CurrencyAmountInput 1.0 CurrencyAmountInput.qml DisabledTooltipButton 1.0 DisabledTooltipButton.qml