From fa85173e0a374796c09e367cfafa90f07a232489 Mon Sep 17 00:00:00 2001 From: Emil Sawicki Date: Mon, 2 Dec 2024 08:37:54 +0100 Subject: [PATCH] feat: Card fixes --- storybook/pages/LinksMessageViewPage.qml | 6 +++++ .../AppLayouts/Chat/views/ChatColumnView.qml | 14 +++++++++- .../AppLayouts/Chat/views/ChatContentView.qml | 4 +++ .../Chat/views/ChatMessagesView.qml | 4 +++ ui/app/mainui/AppMain.qml | 7 ++++- .../chat/ChatInputLinksPreviewArea.qml | 12 ++++++--- .../delegates/PaymentRequestCardDelegate.qml | 21 ++++++++++++--- ui/imports/shared/popups/send/SendModal.qml | 26 +++++++++++++++---- .../shared/popups/send/views/AmountToSend.qml | 16 ++++++++++++ ui/imports/shared/status/StatusChatInput.qml | 7 +++-- .../shared/views/chat/LinksMessageView.qml | 14 ++++++++-- ui/imports/shared/views/chat/MessageView.qml | 12 +++++---- 12 files changed, 120 insertions(+), 23 deletions(-) diff --git a/storybook/pages/LinksMessageViewPage.qml b/storybook/pages/LinksMessageViewPage.qml index 96d9f8f636..d2585a1706 100644 --- a/storybook/pages/LinksMessageViewPage.qml +++ b/storybook/pages/LinksMessageViewPage.qml @@ -32,6 +32,7 @@ SplitView { linkPreviewModel: mockedLinkPreviewModel gifLinks: [ "https://media.tenor.com/qN_ytiwLh24AAAAC/cold.gif" ] paymentRequestModel: mockedPaymentRequestModel + areTestNetworksEnabled: false senderName: "Alice" @@ -77,6 +78,11 @@ SplitView { checked: linksMessageView.isOnline onToggled: linksMessageView.isOnline = !linksMessageView.isOnline } + CheckBox { + text: qsTr("Testnet enabled") + checked: linksMessageView.areTestNetworksEnabled + onToggled: linksMessageView.areTestNetworksEnabled = !linksMessageView.areTestNetworksEnabled + } } } } diff --git a/ui/app/AppLayouts/Chat/views/ChatColumnView.qml b/ui/app/AppLayouts/Chat/views/ChatColumnView.qml index 0272ccab33..9f9c7394b5 100644 --- a/ui/app/AppLayouts/Chat/views/ChatColumnView.qml +++ b/ui/app/AppLayouts/Chat/views/ChatColumnView.qml @@ -200,6 +200,14 @@ Item { // Call later to make sure activeUsersStore and activeMessagesStore bindings are updated Qt.callLater(d.restoreInputState, preservedText) } + + function formatBalance(amount, symbol) { + let asset = ModelUtils.getByKey(WalletStore.RootStore.tokensStore.flatTokensModel, "symbol", symbol) + if (!asset) + return "0" + const num = AmountsArithmetic.toNumber(amount, asset.decimals) + return root.rootStore.currencyStore.formatCurrencyAmount(num, symbol, {noSynbol: true}) + } } EmptyChatPanel { @@ -238,11 +246,13 @@ Item { utilsStore: root.utilsStore rootStore: root.rootStore contactsStore: root.contactsStore + formatBalance: d.formatBalance emojiPopup: root.emojiPopup stickersPopup: root.stickersPopup stickersLoaded: root.stickersLoaded isBlocked: model.blocked sendViaPersonalChatEnabled: root.sendViaPersonalChatEnabled + areTestNetworksEnabled: root.areTestNetworksEnabled onOpenStickerPackPopup: { root.openStickerPackPopup(stickerPackId) } @@ -294,6 +304,8 @@ Item { sharedStore: root.sharedRootStore linkPreviewModel: !!d.activeChatContentModule ? d.activeChatContentModule.inputAreaModule.linkPreviewModel : null + paymentRequestModel: !!d.activeChatContentModule ? d.activeChatContentModule.inputAreaModule.paymentRequestModel : null + formatBalance: d.formatBalance urlsList: d.urlsList askToEnableLinkPreview: { if(!d.activeChatContentModule || !d.activeChatContentModule.inputAreaModule || !d.activeChatContentModule.inputAreaModule.preservedProperties) @@ -391,7 +403,7 @@ Item { d.activeChatContentModule.inputAreaModule.setLinkPreviewEnabledForCurrentMessage(false) } onDismissLinkPreview: (index) => d.activeChatContentModule.inputAreaModule.removeLinkPreviewData(index) - onRemovePaymentRequestPreviewRequested: (index) => d.activeChatContentModule.inputAreaModule.removePaymentRequestPreviewData(index) + onRemovePaymentRequestPreview: (index) => d.activeChatContentModule.inputAreaModule.removePaymentRequestPreviewData(index) } ChatPermissionQualificationPanel { diff --git a/ui/app/AppLayouts/Chat/views/ChatContentView.qml b/ui/app/AppLayouts/Chat/views/ChatContentView.qml index b638956c81..cfd60e6305 100644 --- a/ui/app/AppLayouts/Chat/views/ChatContentView.qml +++ b/ui/app/AppLayouts/Chat/views/ChatContentView.qml @@ -38,8 +38,10 @@ ColumnLayout { property ContactsStore contactsStore property string chatId property int chatType: Constants.chatType.unknown + property var formatBalance readonly property alias chatMessagesLoader: chatMessagesLoader + property bool areTestNetworksEnabled property var emojiPopup property var stickersPopup @@ -94,6 +96,7 @@ ColumnLayout { rootStore: root.rootStore contactsStore: root.contactsStore messageStore: root.messageStore + formatBalance: root.formatBalance emojiPopup: root.emojiPopup stickersPopup: root.stickersPopup usersStore: root.usersStore @@ -103,6 +106,7 @@ ColumnLayout { isChatBlocked: root.isBlocked || !root.isUserAllowedToSendMessage channelEmoji: !chatContentModule ? "" : (chatContentModule.chatDetails.emoji || "") sendViaPersonalChatEnabled: root.sendViaPersonalChatEnabled + areTestNetworksEnabled: root.areTestNetworksEnabled onShowReplyArea: (messageId, senderId) => { root.showReplyArea(messageId) } diff --git a/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml b/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml index f0a5aeb6d1..2f0e5a164b 100644 --- a/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml +++ b/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml @@ -39,9 +39,11 @@ Item { property UsersStore usersStore property ContactsStore contactsStore property string channelEmoji + property var formatBalance property var emojiPopup property var stickersPopup + property bool areTestNetworksEnabled property string chatId: "" property bool stickersLoaded: false @@ -283,10 +285,12 @@ Item { stickersPopup: root.stickersPopup chatLogView: ListView.view chatContentModule: root.chatContentModule + formatBalance: root.formatBalance isChatBlocked: root.isChatBlocked sendViaPersonalChatEnabled: root.sendViaPersonalChatEnabled + areTestNetworksEnabled: root.areTestNetworksEnabled chatId: root.chatId messageId: model.id diff --git a/ui/app/mainui/AppMain.qml b/ui/app/mainui/AppMain.qml index 452f5ee361..9f3ed7aae2 100644 --- a/ui/app/mainui/AppMain.qml +++ b/ui/app/mainui/AppMain.qml @@ -713,7 +713,7 @@ Item { sendModal.preSelectedHoldingType = Constants.TokenType.ERC20 } if (!!amount) { - sendModal.preDefinedAmountToSend = amount + sendModal.preDefinedRawAmountToSend = amount } if (!!chainId) { sendModal.preSelectedChainId = chainId @@ -1882,6 +1882,7 @@ Item { property int preSelectedHoldingType: Constants.TokenType.Unknown property int preSelectedSendType: Constants.SendType.Unknown property string preDefinedAmountToSend + property string preDefinedRawAmountToSend property int preSelectedChainId: 0 property bool onlyAssets: false @@ -1910,6 +1911,7 @@ Item { sendModal.preSelectedAccountAddress = "" sendModal.preSelectedRecipient = undefined sendModal.preDefinedAmountToSend = "" + sendModal.preDefinedRawAmountToSend = "" sendModal.preSelectedChainId = 0 sendModal.stickersPackId = "" @@ -1936,6 +1938,9 @@ Item { if (sendModal.preDefinedAmountToSend != "") { item.preDefinedAmountToSend = sendModal.preDefinedAmountToSend } + if (sendModal.preDefinedRawAmountToSend != "") { + item.preDefinedRawAmountToSend = sendModal.preDefinedRawAmountToSend + } if (!!sendModal.preSelectedChainId) { item.preSelectedChainId = sendModal.preSelectedChainId } diff --git a/ui/imports/shared/controls/chat/ChatInputLinksPreviewArea.qml b/ui/imports/shared/controls/chat/ChatInputLinksPreviewArea.qml index 27daf19e18..8192552dba 100644 --- a/ui/imports/shared/controls/chat/ChatInputLinksPreviewArea.qml +++ b/ui/imports/shared/controls/chat/ChatInputLinksPreviewArea.qml @@ -39,6 +39,8 @@ Control { */ required property var paymentRequestModel + property var formatBalance: null + readonly property alias hoveredUrl: d.hoveredUrl readonly property bool hasContent: imagePreviewArray.length > 0 || showLinkPreviewSettings || linkPreviewRepeater.count > 0 || paymentRequestRepeater.count > 0 @@ -47,7 +49,7 @@ Control { signal linkReload(string link) signal linkClicked(string link) - signal removePaymentRequestPreviewRequested(int index) + signal removePaymentRequestPreview(int index) signal enableLinkPreview() signal enableLinkPreviewForThisMessage() @@ -110,9 +112,13 @@ Control { delegate: PaymentRequestMiniCardDelegate { required property var model - amount: model.amount + amount: { + if (!root.formatBalance) + return model.amount + return root.formatBalance(model.amount, model.symbol) + } symbol: model.symbol - onClose: root.removePaymentRequestPreviewRequested(model.index) + onClose: root.removePaymentRequestPreview(model.index) } } Repeater { diff --git a/ui/imports/shared/controls/delegates/PaymentRequestCardDelegate.qml b/ui/imports/shared/controls/delegates/PaymentRequestCardDelegate.qml index cea1547818..c5a507e754 100644 --- a/ui/imports/shared/controls/delegates/PaymentRequestCardDelegate.qml +++ b/ui/imports/shared/controls/delegates/PaymentRequestCardDelegate.qml @@ -7,6 +7,7 @@ import QtGraphicalEffects 1.15 import StatusQ.Core.Theme 0.1 import StatusQ.Components 0.1 +import StatusQ.Controls 0.1 import shared.controls.chat 1.0 @@ -19,6 +20,8 @@ CalloutCard { required property string symbol required property string address + required property bool areTestNetworksEnabled + property string senderName property string senderThumbnailImage property int senderColorId @@ -42,9 +45,8 @@ CalloutCard { QtObject { id: d - property real bannerImageMargins: 1 / Screen.devicePixelRatio // image size isn't pixel perfect.. - property bool highlight: root.highlight || root.hovered - property string bannerImageSource: "" + readonly property bool highlight: (root.highlight || root.hovered) && isAvailable + readonly property bool isAvailable: !root.areTestNetworksEnabled } contentItem: ColumnLayout { @@ -132,11 +134,22 @@ CalloutCard { } } + StatusToolTip { + text: qsTr("Not available in the testnet mode") + visible: !d.isAvailable && root.hovered + y: -height + } + MouseArea { + id: ma anchors.fill: root hoverEnabled: true cursorShape: Qt.PointingHandCursor acceptedButtons: Qt.LeftButton | Qt.RightButton - onClicked: root.clicked(mouse) + onClicked: { + if (!d.isAvailable) + return + root.clicked(mouse) + } } } diff --git a/ui/imports/shared/popups/send/SendModal.qml b/ui/imports/shared/popups/send/SendModal.qml index d2981d7714..46973a7315 100644 --- a/ui/imports/shared/popups/send/SendModal.qml +++ b/ui/imports/shared/popups/send/SendModal.qml @@ -41,6 +41,7 @@ StatusDialog { property alias preSelectedRecipientType: recipientInputLoader.selectedRecipientType property string preDefinedAmountToSend + property string preDefinedRawAmountToSend property int preSelectedChainId: 0 property string stickersPackId @@ -99,8 +100,8 @@ StatusDialog { return Constants.NoError } - readonly property double maxFiatBalance: isSelectedHoldingValidAsset ? selectedHolding.currencyBalance : 0 - readonly property double maxCryptoBalance: isSelectedHoldingValidAsset ? selectedHolding.currentBalance : 0 + readonly property double maxFiatBalance: isSelectedHoldingValidAsset && !!selectedHolding.currencyBalance ? selectedHolding.currencyBalance : 0 + readonly property double maxCryptoBalance: isSelectedHoldingValidAsset && !!selectedHolding.currencyBalance ? selectedHolding.currentBalance : 0 readonly property double maxInputBalance: amountToSend.fiatMode ? maxFiatBalance : maxCryptoBalance readonly property string tokenSymbol: !!d.selectedHolding && !!d.selectedHolding.symbol ? d.selectedHolding.symbol: "" @@ -234,13 +235,24 @@ StatusDialog { if (popup.preSelectedHoldingType === Constants.TokenType.Native || popup.preSelectedHoldingType === Constants.TokenType.ERC20) { - const entry = SQUtils.ModelUtils.getByKey( + let iconSource = "" + let entry = SQUtils.ModelUtils.getByKey( assetsAdaptor.outputAssetsModel, "tokensKey", popup.preSelectedHoldingID) + + if (entry) { + iconSource = entry.iconSource + } else { + entry = SQUtils.ModelUtils.getByKey( + popup.store.walletAssetStore.renamedTokensBySymbolModel, "tokensKey", + popup.preSelectedHoldingID) + iconSource = Constants.tokenIcon(entry.symbol) + } + d.selectedHoldingType = Constants.TokenType.ERC20 d.selectedHolding = entry - holdingSelector.setSelection(entry.symbol, entry.iconSource, + holdingSelector.setSelection(entry.symbol, iconSource, popup.preSelectedHoldingID) holdingSelector.selectedItem = entry } else { @@ -260,6 +272,7 @@ StatusDialog { holdingSelector.currentTab = TokenSelectorPanel.Tabs.Collectibles } } + if(!!popup.preDefinedAmountToSend) { // TODO: At this stage the number should not be localized. However // in many places when initializing popup the number is provided @@ -267,9 +280,12 @@ StatusDialog { // number consistently. Only the displaying component should apply // final localized formatting. const delocalized = popup.preDefinedAmountToSend.replace(LocaleUtils.userInputLocale.decimalPoint, ".") - amountToSend.setValue(delocalized) } + + if (!!popup.preDefinedRawAmountToSend) { + amountToSend.setRawValue(popup.preDefinedRawAmountToSend) + } if (!!popup.preSelectedChainId) { popup.preDefinedAmountToSend = popup.preDefinedAmountToSend.replace(Qt.locale().decimalPoint, '.') diff --git a/ui/imports/shared/popups/send/views/AmountToSend.qml b/ui/imports/shared/popups/send/views/AmountToSend.qml index b1b67b6c53..5c62aab902 100644 --- a/ui/imports/shared/popups/send/views/AmountToSend.qml +++ b/ui/imports/shared/popups/send/views/AmountToSend.qml @@ -107,6 +107,22 @@ Control { textField.text = d.localize(trimmed) } + function setRawValue(valueString) { + if (!valueString) + valueString = "0" + + if (d.fiatMode) { + setValue(valueString) + return + } + + const divisor = SQUtils.AmountsArithmetic.fromExponent(root.multiplierIndex) + const stringNumber = SQUtils.AmountsArithmetic.div(SQUtils.AmountsArithmetic.fromString(valueString), divisor).toFixed(root.multiplierIndex) + const trimmed = d.removeDecimalTrailingZeros(stringNumber) + + textField.text = d.localize(trimmed) + } + function clear() { textField.clear() } diff --git a/ui/imports/shared/status/StatusChatInput.qml b/ui/imports/shared/status/StatusChatInput.qml index a88a51c4b1..4a201d588e 100644 --- a/ui/imports/shared/status/StatusChatInput.qml +++ b/ui/imports/shared/status/StatusChatInput.qml @@ -37,7 +37,7 @@ Rectangle { signal disableLinkPreview() signal dismissLinkPreviewSettings() signal dismissLinkPreview(int index) - signal removePaymentRequestPreviewRequested(int index) + signal removePaymentRequestPreview(int index) property var usersModel property SharedStores.RootStore sharedStore @@ -69,6 +69,8 @@ Rectangle { property var linkPreviewModel: null + property var formatBalance: null + property var urlsList: [] property bool askToEnableLinkPreview: false @@ -1226,6 +1228,7 @@ Rectangle { imagePreviewArray: control.fileUrlsAndSources linkPreviewModel: control.linkPreviewModel paymentRequestModel: control.paymentRequestModel + formatBalance: control.formatBalance showLinkPreviewSettings: control.askToEnableLinkPreview onImageRemoved: (index) => { //Just do a copy and replace the whole thing because it's a plain JS array and thre's no signal when a single item is removed @@ -1244,7 +1247,7 @@ Rectangle { onDisableLinkPreview: () => control.disableLinkPreview() onDismissLinkPreviewSettings: () => control.dismissLinkPreviewSettings() onDismissLinkPreview: (index) => control.dismissLinkPreview(index) - onRemovePaymentRequestPreviewRequested: (index) => control.removePaymentRequestPreviewRequested(index) + onRemovePaymentRequestPreview: (index) => control.removePaymentRequestPreview(index) } RowLayout { diff --git a/ui/imports/shared/views/chat/LinksMessageView.qml b/ui/imports/shared/views/chat/LinksMessageView.qml index b01c3544f9..e623ad9ce5 100644 --- a/ui/imports/shared/views/chat/LinksMessageView.qml +++ b/ui/imports/shared/views/chat/LinksMessageView.qml @@ -6,6 +6,7 @@ import StatusQ.Core 0.1 import StatusQ.Core.Theme 0.1 import StatusQ.Controls 0.1 import StatusQ.Components 0.1 +import StatusQ.Core.Utils 0.1 as SQUtils import shared.controls 1.0 import shared.panels 1.0 @@ -30,6 +31,10 @@ Flow { required property bool gifUnfurlingEnabled required property bool canAskToUnfurlGifs + required property bool areTestNetworksEnabled + + property var formatBalance: null + property string senderName property string senderThumbnailImage property int senderColorId @@ -69,7 +74,12 @@ Flow { delegate: PaymentRequestCardDelegate { required property var model objectName: "PaymentRequestDelegate_" + model.index - amount: model.amount + areTestNetworksEnabled: root.areTestNetworksEnabled + amount: { + if (!root.formatBalance) + return model.amount + return root.formatBalance(model.amount, model.symbol) + } symbol: model.symbol address: model.receiver senderName: root.senderName @@ -81,7 +91,7 @@ Flow { Repeater { id: tempRepeater - visible: root.canAskToUnfurlGifs + visible: root.cankToUnfurlGifs model: root.gifUnfurlingEnabled ? gifLinks : [] delegate: LinkPreviewGifDelegate { diff --git a/ui/imports/shared/views/chat/MessageView.qml b/ui/imports/shared/views/chat/MessageView.qml index 2a3d9b469b..be295f677d 100644 --- a/ui/imports/shared/views/chat/MessageView.qml +++ b/ui/imports/shared/views/chat/MessageView.qml @@ -74,6 +74,7 @@ Loader { property string messageAttachments: "" property var transactionParams property var emojiReactionsModel + property var formatBalance // These 2 properties can be dropped when the new unfurling flow supports GIFs property var links @@ -138,6 +139,8 @@ Loader { property bool sendViaPersonalChatEnabled + property bool areTestNetworksEnabled + property bool stickersLoaded: false property string sticker property int stickerPack: -1 @@ -982,6 +985,8 @@ Loader { playAnimations: root.Window.active && root.messageStore.isChatActive isOnline: root.rootStore.mainModuleInst.isOnline highlightLink: delegate.hoveredLink + areTestNetworksEnabled: root.areTestNetworksEnabled + formatBalance: root.formatBalance onImageClicked: (image, mouse, imageSource, url) => { d.onImageClicked(image, mouse, imageSource, url) } @@ -993,11 +998,8 @@ Loader { canAskToUnfurlGifs: !root.sharedRootStore.neverAskAboutUnfurlingAgain onSetNeverAskAboutUnfurlingAgain: root.sharedRootStore.setNeverAskAboutUnfurlingAgain(neverAskAgain) onPaymentRequestClicked: (index) => { - const receiver = StatusQUtils.ModelUtils.get(paymentRequestModel, index, "receiver") - const amount = StatusQUtils.ModelUtils.get(paymentRequestModel, index, "amount") - const symbol = StatusQUtils.ModelUtils.get(paymentRequestModel, index, "symbol") - const chainId = StatusQUtils.ModelUtils.get(paymentRequestModel, index, "chainId") - Global.paymentRequestClicked(receiver, symbol, amount, chainId) + const request = StatusQUtils.ModelUtils.get(paymentRequestModel, index) + Global.paymentRequestClicked(request.receiver, request.symbol, request.amount, request.chainId) } Component.onCompleted: {