feat: add chat command bubbles for received txs
This commit is contained in:
parent
4e801c5336
commit
60492b4db1
|
@ -24,6 +24,10 @@ proc handleChatEvents(self: ChatController) =
|
|||
var evArgs = ChatUpdateArgs(e)
|
||||
self.view.updateChats(evArgs.chats, false)
|
||||
|
||||
self.status.events.on("messageDeleted") do(e: Args):
|
||||
var evArgs = MessageArgs(e)
|
||||
self.view.deleteMessage(evArgs.channel, evArgs.id)
|
||||
|
||||
self.status.events.on("chatHistoryCleared") do(e: Args):
|
||||
var args = ChannelArgs(e)
|
||||
self.view.clearMessages(args.chat.id)
|
||||
|
|
|
@ -488,6 +488,9 @@ QtObject:
|
|||
self.currentSuggestions.setNewData(self.status.contacts.getContacts())
|
||||
self.calculateUnreadMessages()
|
||||
|
||||
proc deleteMessage*(self: ChatsView, channelId: string, messageId: string) =
|
||||
self.messageList[channelId].deleteMessage(messageId)
|
||||
|
||||
proc renameGroup*(self: ChatsView, newName: string) {.slot.} =
|
||||
self.status.chat.renameGroup(self.activeChannel.id, newName)
|
||||
|
||||
|
@ -570,5 +573,15 @@ QtObject:
|
|||
if (self.chats.chats.len == 0): return false
|
||||
let selectedChannel = self.chats.getChannel(channelIndex)
|
||||
if (selectedChannel == nil): return false
|
||||
result = selectedChannel.muted
|
||||
result = selectedChannel.muted
|
||||
|
||||
### Chat commands functions ###
|
||||
proc acceptRequestAddressForTransaction*(self: ChatsView, messageId: string , address: string) {.slot.} =
|
||||
self.status.chat.acceptRequestAddressForTransaction(messageId, address)
|
||||
|
||||
proc declineRequestAddressForTransaction*(self: ChatsView, messageId: string) {.slot.} =
|
||||
self.status.chat.declineRequestAddressForTransaction(messageId)
|
||||
|
||||
proc declineRequestTransaction*(self: ChatsView, messageId: string) {.slot.} =
|
||||
self.status.chat.declineRequestTransaction(messageId)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import NimQml, Tables, sets
|
||||
import NimQml, Tables, sets, json
|
||||
import ../../../status/status
|
||||
import ../../../status/accounts
|
||||
import ../../../status/chat
|
||||
|
@ -31,6 +31,7 @@ type
|
|||
Audio = UserRole + 20
|
||||
AudioDurationMs = UserRole + 21
|
||||
EmojiReactions = UserRole + 22
|
||||
CommandParameters = UserRole + 23
|
||||
|
||||
QtObject:
|
||||
type
|
||||
|
@ -69,6 +70,14 @@ QtObject:
|
|||
result.status = status
|
||||
result.setup
|
||||
|
||||
proc deleteMessage*(self: ChatMessageList, messageId: string) =
|
||||
let messageIndex = self.messageIndex[messageId]
|
||||
self.beginRemoveRows(newQModelIndex(), messageIndex, messageIndex)
|
||||
self.messages.delete(messageIndex)
|
||||
self.messageIndex.del(messageId)
|
||||
self.messageReactions.del(messageId)
|
||||
self.endRemoveRows()
|
||||
|
||||
proc resetTimeOut*(self: ChatMessageList, messageId: string) =
|
||||
if not self.messageIndex.hasKey(messageId): return
|
||||
let msgIdx = self.messageIndex[messageId]
|
||||
|
@ -126,6 +135,17 @@ QtObject:
|
|||
of ChatMessageRoles.Audio: result = newQVariant(message.audio)
|
||||
of ChatMessageRoles.AudioDurationMs: result = newQVariant(message.audioDurationMs)
|
||||
of ChatMessageRoles.EmojiReactions: result = newQVariant(self.getReactions(message.id))
|
||||
# Pass the command parameters as a JSON string
|
||||
of ChatMessageRoles.CommandParameters: result = newQVariant($(%*{
|
||||
"id": message.commandParameters.id,
|
||||
"fromAddress": message.commandParameters.fromAddress,
|
||||
"address": message.commandParameters.address,
|
||||
"contract": message.commandParameters.contract,
|
||||
"value": message.commandParameters.value,
|
||||
"transactionHash": message.commandParameters.transactionHash,
|
||||
"commandState": message.commandParameters.commandState,
|
||||
"signature": message.commandParameters.signature
|
||||
}))
|
||||
|
||||
method roleNames(self: ChatMessageList): Table[int, string] =
|
||||
{
|
||||
|
@ -150,7 +170,8 @@ QtObject:
|
|||
ChatMessageRoles.Image.int: "image",
|
||||
ChatMessageRoles.Audio.int: "audio",
|
||||
ChatMessageRoles.AudioDurationMs.int: "audioDurationMs",
|
||||
ChatMessageRoles.EmojiReactions.int: "emojiReactions"
|
||||
ChatMessageRoles.EmojiReactions.int: "emojiReactions",
|
||||
ChatMessageRoles.CommandParameters.int: "commandParameters"
|
||||
}.toTable
|
||||
|
||||
proc getMessageIndex(self: ChatMessageList, messageId: string): int {.slot.} =
|
||||
|
|
|
@ -2,6 +2,7 @@ import eventemitter, json, strutils, sequtils, tables, chronicles, sugar, times
|
|||
import libstatus/contracts as status_contracts
|
||||
import libstatus/chat as status_chat
|
||||
import libstatus/mailservers as status_mailservers
|
||||
import libstatus/chatCommands as status_chat_commands
|
||||
import libstatus/stickers as status_stickers
|
||||
import libstatus/types
|
||||
import mailservers
|
||||
|
@ -265,19 +266,20 @@ proc clearHistory*(self: ChatModel, chatId: string) =
|
|||
proc setActiveChannel*(self: ChatModel, chatId: string) =
|
||||
self.events.emit("activeChannelChanged", ChatIdArg(chatId: chatId))
|
||||
|
||||
proc sendMessage*(self: ChatModel, chatId: string, msg: string, replyTo: string = "", contentType: int = ContentType.Message.int) =
|
||||
var response = status_chat.sendChatMessage(chatId, msg, replyTo, contentType)
|
||||
var (chats, messages) = self.processChatUpdate(parseJson(response))
|
||||
proc processMessageUpdateAfterSend(self: ChatModel, response: string): (seq[Chat], seq[Message]) =
|
||||
result = self.processChatUpdate(parseJson(response))
|
||||
var (chats, messages) = result
|
||||
self.events.emit("chatUpdate", ChatUpdateArgs(messages: messages, chats: chats, contacts: @[]))
|
||||
for msg in messages:
|
||||
self.events.emit("sendingMessage", MessageArgs(id: msg.id, channel: msg.chatId))
|
||||
|
||||
proc sendMessage*(self: ChatModel, chatId: string, msg: string, replyTo: string = "", contentType: int = ContentType.Message.int) =
|
||||
var response = status_chat.sendChatMessage(chatId, msg, replyTo, contentType)
|
||||
discard self.processMessageUpdateAfterSend(response)
|
||||
|
||||
proc sendImage*(self: ChatModel, chatId: string, image: string) =
|
||||
var response = status_chat.sendImageMessage(chatId, image)
|
||||
var (chats, messages) = self.processChatUpdate(parseJson(response))
|
||||
self.events.emit("chatUpdate", ChatUpdateArgs(messages: messages, chats: chats, contacts: @[]))
|
||||
for msg in messages:
|
||||
self.events.emit("sendingMessage", MessageArgs(id: msg.id, channel: msg.chatId))
|
||||
discard self.processMessageUpdateAfterSend(response)
|
||||
|
||||
proc addStickerToRecent*(self: ChatModel, sticker: Sticker, save: bool = false) =
|
||||
self.recentStickers.insert(sticker, 0)
|
||||
|
@ -396,3 +398,20 @@ proc muteChat*(self: ChatModel, chatId: string) =
|
|||
|
||||
proc unmuteChat*(self: ChatModel, chatId: string) =
|
||||
discard status_chat.unmuteChat(chatId)
|
||||
|
||||
proc processUpdateForTransaction*(self: ChatModel, messageId: string, response: string) =
|
||||
var (chats, messages) = self.processMessageUpdateAfterSend(response)
|
||||
self.events.emit("messageDeleted", MessageArgs(id: messageId, channel: chats[0].id))
|
||||
|
||||
proc acceptRequestAddressForTransaction*(self: ChatModel, messageId: string, address: string) =
|
||||
let response = status_chat_commands.acceptRequestAddressForTransaction(messageId, address)
|
||||
self.processUpdateForTransaction(messageId, response)
|
||||
|
||||
proc declineRequestAddressForTransaction*(self: ChatModel, messageId: string) =
|
||||
let response = status_chat_commands.declineRequestAddressForTransaction(messageId)
|
||||
self.processUpdateForTransaction(messageId, response)
|
||||
|
||||
|
||||
proc declineRequestTransaction*(self: ChatModel, messageId: string) =
|
||||
let response = status_chat_commands.declineRequestTransaction(messageId)
|
||||
self.processUpdateForTransaction(messageId, response)
|
||||
|
|
|
@ -19,11 +19,21 @@ type TextItem* = object
|
|||
literal*: string
|
||||
destination*: string
|
||||
|
||||
type CommandParameters* = object
|
||||
id*: string
|
||||
fromAddress*: string
|
||||
address*: string
|
||||
contract*: string
|
||||
value*: string
|
||||
transactionHash*: string
|
||||
commandState*: int
|
||||
signature*: string
|
||||
|
||||
type Message* = object
|
||||
alias*: string
|
||||
chatId*: string
|
||||
clock*: int
|
||||
# commandParameters*: # ???
|
||||
commandParameters*: CommandParameters
|
||||
contentType*: ContentType
|
||||
ensName*: string
|
||||
fromAuthor*: string
|
||||
|
@ -32,7 +42,7 @@ type Message* = object
|
|||
lineCount*: int
|
||||
localChatId*: string
|
||||
messageType*: string # ???
|
||||
parsedText*: seq[TextItem]
|
||||
parsedText*: seq[TextItem]
|
||||
# quotedMessage: # ???
|
||||
replace*: string # ???
|
||||
responseTo*: string
|
||||
|
|
|
@ -58,7 +58,6 @@ proc chatMessages*(chatId: string, cursor: string = ""): (string, seq[Message])
|
|||
cursorVal = newJString(cursor)
|
||||
|
||||
let rpcResult = parseJson(callPrivateRPC("chatMessages".prefix, %* [chatId, cursorVal, 20]))["result"]
|
||||
|
||||
if rpcResult["messages"].kind != JNull:
|
||||
for jsonMsg in rpcResult["messages"]:
|
||||
messages.add(jsonMsg.toMessage)
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import json, chronicles
|
||||
import core, utils
|
||||
|
||||
proc acceptRequestAddressForTransaction*(messageId: string, address: string): string =
|
||||
result = callPrivateRPC("acceptRequestAddressForTransaction".prefix, %* [messageId, address])
|
||||
|
||||
proc declineRequestAddressForTransaction*(messageId: string): string =
|
||||
result = callPrivateRPC("declineRequestAddressForTransaction".prefix, %* [messageId])
|
||||
|
||||
proc declineRequestTransaction*(messageId: string): string =
|
||||
result = callPrivateRPC("declineRequestTransaction".prefix, %* [messageId])
|
|
@ -198,6 +198,19 @@ proc toMessage*(jsonMsg: JsonNode): Message =
|
|||
|
||||
if message.contentType == ContentType.Sticker:
|
||||
message.stickerHash = jsonMsg["sticker"]["hash"].getStr
|
||||
.join(" ")
|
||||
|
||||
if message.contentType == ContentType.Transaction:
|
||||
message.commandParameters = CommandParameters(
|
||||
id: jsonMsg["commandParameters"]["id"].getStr,
|
||||
fromAddress: jsonMsg["commandParameters"]["from"].getStr,
|
||||
address: jsonMsg["commandParameters"]["address"].getStr,
|
||||
contract: jsonMsg["commandParameters"]["contract"].getStr,
|
||||
value: jsonMsg["commandParameters"]["value"].getStr,
|
||||
transactionHash: jsonMsg["commandParameters"]["transactionHash"].getStr,
|
||||
commandState: jsonMsg["commandParameters"]["commandState"].getInt,
|
||||
signature: jsonMsg["commandParameters"]["signature"].getStr
|
||||
)
|
||||
|
||||
result = message
|
||||
|
||||
|
|
|
@ -136,7 +136,6 @@ proc updateAccount*(self: WalletModel, address: string) =
|
|||
self.events.emit("accountsUpdated", Args())
|
||||
|
||||
proc getTotalFiatBalance*(self: WalletModel): string =
|
||||
var newBalance = 0.0
|
||||
fmt"{self.totalBalance:.2f} {self.defaultCurrency}"
|
||||
|
||||
proc convertValue*(self: WalletModel, balance: string, fromCurrency: string, toCurrency: string): float =
|
||||
|
|
|
@ -61,6 +61,8 @@ Rectangle {
|
|||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.onClicked
|
||||
onClicked: {
|
||||
root.onClicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,51 +3,76 @@ import QtQuick.Controls 2.13
|
|||
import QtGraphicalEffects 1.13
|
||||
import "../../../../../imports"
|
||||
import "../../../../../shared"
|
||||
import "../../../Wallet"
|
||||
|
||||
Popup {
|
||||
id: root
|
||||
width: buttonRow.width
|
||||
height: buttonRow.height
|
||||
padding: 0
|
||||
margins: 0
|
||||
id: root
|
||||
width: buttonRow.width
|
||||
height: buttonRow.height
|
||||
padding: 0
|
||||
margins: 0
|
||||
|
||||
background: Rectangle {
|
||||
color: Style.current.background
|
||||
radius: Style.current.radius
|
||||
border.width: 0
|
||||
layer.enabled: true
|
||||
layer.effect: DropShadow{
|
||||
verticalOffset: 3
|
||||
radius: 8
|
||||
samples: 15
|
||||
fast: true
|
||||
cached: true
|
||||
color: "#22000000"
|
||||
}
|
||||
}
|
||||
background: Rectangle {
|
||||
color: Style.current.background
|
||||
radius: Style.current.radius
|
||||
border.width: 0
|
||||
layer.enabled: true
|
||||
layer.effect: DropShadow {
|
||||
verticalOffset: 3
|
||||
radius: 8
|
||||
samples: 15
|
||||
fast: true
|
||||
cached: true
|
||||
color: "#22000000"
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttonRow
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 0
|
||||
padding: Style.current.halfPadding
|
||||
spacing: Style.current.halfPadding
|
||||
Row {
|
||||
id: buttonRow
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 0
|
||||
padding: Style.current.halfPadding
|
||||
spacing: Style.current.halfPadding
|
||||
|
||||
ChatCommandButton {
|
||||
iconColor: Style.current.purple
|
||||
iconSource: "../../../../img/send.svg"
|
||||
//% "Send transaction"
|
||||
text: qsTrId("send-transaction")
|
||||
}
|
||||
ChatCommandButton {
|
||||
iconColor: Style.current.purple
|
||||
iconSource: "../../../../img/send.svg"
|
||||
//% "Send transaction"
|
||||
text: qsTrId("send-transaction")
|
||||
onClicked: function () {
|
||||
sendModal.selectedRecipient = {
|
||||
address: "0x9ce0056c5fc6bb9459a4dcfa35eaad8c1fee5ce9",
|
||||
identicon: chatsModel.activeChannel.identicon,
|
||||
name: chatsModel.activeChannel.name,
|
||||
type: RecipientSelector.Type.Contact
|
||||
}
|
||||
sendModal.open()
|
||||
}
|
||||
}
|
||||
|
||||
ChatCommandButton {
|
||||
iconColor: Style.current.orange
|
||||
iconSource: "../../../../img/send.svg"
|
||||
rotatedImage: true
|
||||
//% "Request transaction"
|
||||
text: qsTrId("request-transaction")
|
||||
}
|
||||
}
|
||||
ChatCommandButton {
|
||||
iconColor: Style.current.orange
|
||||
iconSource: "../../../../img/send.svg"
|
||||
rotatedImage: true
|
||||
//% "Request transaction"
|
||||
text: qsTrId("request-transaction")
|
||||
}
|
||||
|
||||
SendModal {
|
||||
id: sendModal
|
||||
onOpened: {
|
||||
walletModel.getGasPricePredictions()
|
||||
}
|
||||
selectedRecipient: {
|
||||
return {
|
||||
address: "0x9ce0056c5fc6bb9459a4dcfa35eaad8c1fee5ce9",
|
||||
identicon: chatsModel.activeChannel.identicon,
|
||||
name: chatsModel.activeChannel.name,
|
||||
type: RecipientSelector.Type.Contact
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,6 +79,8 @@ Item {
|
|||
return fetchMoreMessagesButtonComponent
|
||||
case Constants.systemMessagePrivateGroupType:
|
||||
return privateGroupHeaderComponent
|
||||
case Constants.transactionType:
|
||||
return transactionBubble
|
||||
default:
|
||||
return appSettings.compactMode ? compactMessageComponent : messageComponent
|
||||
}
|
||||
|
@ -174,6 +176,12 @@ Item {
|
|||
clickMessage: messageItem.clickMessage
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction bubble
|
||||
Component {
|
||||
id: transactionBubble
|
||||
TransactionBubble {}
|
||||
}
|
||||
}
|
||||
|
||||
/*##^##
|
||||
|
|
|
@ -2,123 +2,214 @@ import QtQuick 2.3
|
|||
import "../../../../../shared"
|
||||
import "../../../../../imports"
|
||||
import "./TransactionComponents"
|
||||
import "../../../Wallet/data"
|
||||
|
||||
Rectangle {
|
||||
property string tokenAmount: "100"
|
||||
property string token: "SNT"
|
||||
property string fiatValue: "10 USD"
|
||||
property bool outgoing: true
|
||||
property string state: "addressReceived"
|
||||
property int timestamp: 1598454756329
|
||||
Item {
|
||||
property var commandParametersObject: {
|
||||
try {
|
||||
var result = JSON.parse(commandParameters)
|
||||
|
||||
return result
|
||||
} catch (e) {
|
||||
console.error('Error parsing command parameters')
|
||||
console.error('JSON:', commandParameters)
|
||||
console.error('Error:', e)
|
||||
return {
|
||||
id: "",
|
||||
from: "",
|
||||
address: "",
|
||||
contract: "",
|
||||
value: "",
|
||||
transactionHash: "",
|
||||
commandState: 1,
|
||||
signature: null
|
||||
}
|
||||
}
|
||||
}
|
||||
property var token: {
|
||||
if (commandParametersObject.contract === "") {
|
||||
return {
|
||||
symbol: "ETH",
|
||||
name: "Ethereum",
|
||||
address: "0x0000000000000000000000000000000000000000",
|
||||
decimals: 18,
|
||||
hasIcon: true
|
||||
}
|
||||
}
|
||||
|
||||
let count = walletModel.defaultTokenList.items.count
|
||||
for (let i = 0; i < count; i++) {
|
||||
let token = walletModel.defaultTokenList.items.get(i)
|
||||
if (commandParametersObject.contract === token.address) {
|
||||
return token
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
property string tokenAmount: {
|
||||
if (!commandParametersObject.value) {
|
||||
return "0"
|
||||
}
|
||||
|
||||
// Divide the Wei value by 10^decimals
|
||||
var divModResult = Utils.newBigNumber(commandParametersObject.value)
|
||||
.divmod(Utils.newBigNumber(10)
|
||||
.pow(token.decimals))
|
||||
// Make a string with the quotient and the remainder
|
||||
var str = divModResult.quotient.toString() + "." + divModResult.remainder.toString()
|
||||
// Remove the useless zeros at the satrt and the end, but keep at least one before the dot
|
||||
return str.replace(/^(0*)([0-9\.]+?)(0*)$/g, function (match, firstZeros, whatWeKeep, secondZeros) {
|
||||
if (whatWeKeep.startsWith('.')) {
|
||||
whatWeKeep = "0" + whatWeKeep
|
||||
}
|
||||
|
||||
return whatWeKeep
|
||||
})
|
||||
}
|
||||
property string tokenSymbol: token.symbol
|
||||
property string fiatValue: {
|
||||
if (!tokenAmount || !token.symbol) {
|
||||
return "0"
|
||||
}
|
||||
var defaultFiatSymbol = walletModel.defaultCurrency
|
||||
return walletModel.getFiatValue(tokenAmount, token.symbol, defaultFiatSymbol) + " " + defaultFiatSymbol.toUpperCase()
|
||||
}
|
||||
property int state: commandParametersObject.commandState
|
||||
property bool outgoing: {
|
||||
switch (root.state) {
|
||||
case Constants.pending:
|
||||
case Constants.confirmed:
|
||||
case Constants.transactionRequested:
|
||||
case Constants.addressRequested: return isCurrentUser
|
||||
case Constants.declined:
|
||||
case Constants.transactionDeclined:
|
||||
case Constants.addressReceived: return !isCurrentUser
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
property int innerMargin: 12
|
||||
|
||||
id: root
|
||||
width: 170
|
||||
height: childrenRect.height
|
||||
radius: 16
|
||||
color: Style.current.background
|
||||
border.color: Style.current.border
|
||||
border.width: 1
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: appSettings.compactMode ? Style.current.padding : 48
|
||||
width: rectangleBubble.width
|
||||
height: rectangleBubble.height
|
||||
|
||||
StyledText {
|
||||
id: title
|
||||
color: Style.current.secondaryText
|
||||
text: outgoing ? qsTr("↑ Outgoing transaction") : qsTr("↓ Incoming transaction")
|
||||
font.weight: Font.Medium
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: Style.current.halfPadding
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
font.pixelSize: 13
|
||||
}
|
||||
|
||||
Item {
|
||||
id: valueContainer
|
||||
height: tokenText.height + fiatText.height
|
||||
anchors.top: title.bottom
|
||||
anchors.topMargin: 4
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 12
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 12
|
||||
|
||||
Image {
|
||||
id: tokenImage
|
||||
source: `../../../../img/tokens/${root.token}.png`
|
||||
width: 24
|
||||
height: 24
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
Rectangle {
|
||||
id: rectangleBubble
|
||||
width: (bubbleLoader.active ? bubbleLoader.width : valueContainer.width)
|
||||
+ timeText.width + 3 * root.innerMargin
|
||||
height: childrenRect.height + root.innerMargin
|
||||
radius: 16
|
||||
color: Style.current.background
|
||||
border.color: Style.current.border
|
||||
border.width: 1
|
||||
|
||||
StyledText {
|
||||
id: tokenText
|
||||
color: Style.current.text
|
||||
text: `${root.tokenAmount} ${root.token}`
|
||||
anchors.left: tokenImage.right
|
||||
anchors.leftMargin: Style.current.halfPadding
|
||||
font.pixelSize: 22
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: fiatText
|
||||
id: title
|
||||
color: Style.current.secondaryText
|
||||
text: root.fiatValue
|
||||
anchors.top: tokenText.bottom
|
||||
anchors.left: tokenText.left
|
||||
text: outgoing ? qsTr("↑ Outgoing transaction") : qsTr("↓ Incoming transaction")
|
||||
font.weight: Font.Medium
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: Style.current.halfPadding
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: root.innerMargin
|
||||
font.pixelSize: 13
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: bubbleLoader
|
||||
active: root.state !== Constants.addressRequested || !outgoing
|
||||
sourceComponent: stateBubbleComponent
|
||||
anchors.top: valueContainer.bottom
|
||||
anchors.topMargin: Style.current.halfPadding
|
||||
width: parent.width
|
||||
height: item.height + 12
|
||||
}
|
||||
Item {
|
||||
id: valueContainer
|
||||
width: childrenRect.width
|
||||
height: tokenText.height + fiatText.height
|
||||
anchors.top: title.bottom
|
||||
anchors.topMargin: 4
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: root.innerMargin
|
||||
|
||||
Component {
|
||||
id: stateBubbleComponent
|
||||
Image {
|
||||
id: tokenImage
|
||||
source: `../../../../img/tokens/${root.tokenSymbol}.png`
|
||||
width: 24
|
||||
height: 24
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StateBubble {
|
||||
state: root.state
|
||||
StyledText {
|
||||
id: tokenText
|
||||
color: Style.current.textColor
|
||||
text: `${root.tokenAmount} ${root.tokenSymbol}`
|
||||
anchors.left: tokenImage.right
|
||||
anchors.leftMargin: Style.current.halfPadding
|
||||
font.pixelSize: 22
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: fiatText
|
||||
color: Style.current.secondaryText
|
||||
text: root.fiatValue
|
||||
anchors.top: tokenText.bottom
|
||||
anchors.left: tokenText.left
|
||||
font.pixelSize: 13
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: bubbleLoader
|
||||
active: isCurrentUser || (!isCurrentUser && !(root.state === Constants.addressRequested || root.state === Constants.transactionRequested))
|
||||
sourceComponent: stateBubbleComponent
|
||||
anchors.top: valueContainer.bottom
|
||||
anchors.topMargin: Style.current.halfPadding
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: root.innerMargin
|
||||
}
|
||||
|
||||
Component {
|
||||
id: stateBubbleComponent
|
||||
|
||||
StateBubble {
|
||||
state: root.state
|
||||
outgoing: root.outgoing
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: buttonsLoader
|
||||
active: (root.state === Constants.addressRequested && !root.outgoing) ||
|
||||
(root.state === Constants.addressReceived && root.outgoing) ||
|
||||
(root.state === Constants.transactionRequested && !root.outgoing)
|
||||
sourceComponent: root.outgoing ? signAndSendComponent : acceptTransactionComponent
|
||||
anchors.top: bubbleLoader.active ? bubbleLoader.bottom : valueContainer.bottom
|
||||
anchors.topMargin: bubbleLoader.active ? root.innerMargin : 20
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
Component {
|
||||
id: acceptTransactionComponent
|
||||
|
||||
AcceptTransaction {
|
||||
state: root.state
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: signAndSendComponent
|
||||
|
||||
SendTransactionButton {}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: timeText
|
||||
color: Style.current.secondaryText
|
||||
text: Utils.formatTime(timestamp)
|
||||
anchors.left: bubbleLoader.active ? bubbleLoader.right : undefined
|
||||
anchors.leftMargin: bubbleLoader.active ? 13 : 0
|
||||
anchors.right: bubbleLoader.active ? undefined : parent.right
|
||||
anchors.rightMargin: bubbleLoader.active ? 0 : root.innerMargin
|
||||
anchors.bottom: bubbleLoader.active ? bubbleLoader.bottom : buttonsLoader.top
|
||||
anchors.bottomMargin: bubbleLoader.active ? -root.innerMargin : 7
|
||||
font.pixelSize: 10
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: buttonsLoader
|
||||
active: (root.state === Constants.addressRequested && !root.outgoing) ||
|
||||
(root.state === Constants.addressReceived && root.outgoing)
|
||||
sourceComponent: root.outgoing ? signAndSendComponent : acceptTransactionComponent
|
||||
anchors.top: bubbleLoader.active ? bubbleLoader.bottom : valueContainer.bottom
|
||||
anchors.topMargin: bubbleLoader.active ? 0 : Style.current.halfPadding
|
||||
width: parent.width
|
||||
height: item.height
|
||||
}
|
||||
|
||||
Component {
|
||||
id: acceptTransactionComponent
|
||||
|
||||
AcceptTransaction {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: signAndSendComponent
|
||||
|
||||
SendTransactionButton {}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: timeText
|
||||
color: Style.current.secondaryText
|
||||
text: Utils.formatTime(root.timestamp)
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 9
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 12
|
||||
font.pixelSize: 10
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*##^##
|
||||
|
|
|
@ -3,6 +3,8 @@ import "../../../../../../shared"
|
|||
import "../../../../../../imports"
|
||||
|
||||
Item {
|
||||
property int state: Constants.addressRequested
|
||||
|
||||
width: parent.width
|
||||
height: childrenRect.height
|
||||
|
||||
|
@ -13,14 +15,13 @@ Item {
|
|||
StyledText {
|
||||
id: acceptText
|
||||
color: Style.current.blue
|
||||
text: qsTr("Accept and share address")
|
||||
text: root.state === Constants.addressRequested ? qsTr("Accept and share address") : qsTr("Accept and send")
|
||||
padding: Style.current.halfPadding
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.WordWrap
|
||||
font.weight: Font.Medium
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
bottomPadding: Style.current.halfPadding
|
||||
topPadding: Style.current.halfPadding
|
||||
anchors.top: separator1.bottom
|
||||
font.pixelSize: 15
|
||||
|
||||
|
@ -28,7 +29,12 @@ Item {
|
|||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
console.log('Accept')
|
||||
if (root.state === Constants.addressRequested) {
|
||||
// TODO get address from a modal instead
|
||||
chatsModel.acceptRequestAddressForTransaction(messageId, walletModel.getDefaultAccount())
|
||||
} else if (root.state === Constants.transactionRequested) {
|
||||
console.log('Accept and send')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,8 +54,7 @@ Item {
|
|||
font.weight: Font.Medium
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
bottomPadding: Style.current.padding
|
||||
topPadding: Style.current.padding
|
||||
padding: Style.current.halfPadding
|
||||
anchors.top: separator2.bottom
|
||||
font.pixelSize: 15
|
||||
|
||||
|
@ -57,7 +62,12 @@ Item {
|
|||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
console.log('Decline')
|
||||
if (root.state === Constants.addressRequested) {
|
||||
chatsModel.declineRequestAddressForTransaction(messageId)
|
||||
} else if (root.state === Constants.transactionRequested) {
|
||||
chatsModel.declineRequestTransaction(messageId)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import "../../../../../../imports"
|
|||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: childrenRect.height
|
||||
height: childrenRect.height + Style.current.halfPadding
|
||||
|
||||
Separator {
|
||||
id: separator
|
||||
|
@ -19,9 +19,8 @@ Item {
|
|||
font.weight: Font.Medium
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
bottomPadding: Style.current.halfPadding
|
||||
topPadding: Style.current.halfPadding
|
||||
anchors.top: separator1.bottom
|
||||
anchors.top: separator.bottom
|
||||
font.pixelSize: 15
|
||||
|
||||
MouseArea {
|
||||
|
|
|
@ -4,11 +4,12 @@ import "../../../../../../shared"
|
|||
import "../../../../../../imports"
|
||||
|
||||
Rectangle {
|
||||
property string state: Constants.pending
|
||||
property int state: Constants.pending
|
||||
property bool outgoing: true
|
||||
|
||||
id: root
|
||||
width: childrenRect.width + 12
|
||||
height: childrenRect.height
|
||||
width: childrenRect.width + 24
|
||||
height: 28
|
||||
border.width: 1
|
||||
border.color: Style.current.border
|
||||
radius: 24
|
||||
|
@ -19,11 +20,10 @@ Rectangle {
|
|||
switch (root.state) {
|
||||
case Constants.pending:
|
||||
case Constants.addressReceived:
|
||||
case Constants.shared:
|
||||
case Constants.transactionRequested:
|
||||
case Constants.addressRequested: return "../../../../../img/dotsLoadings.svg"
|
||||
case Constants.confirmed: return "../../../../../img/check.svg"
|
||||
case Constants.unknown:
|
||||
case Constants.failure:
|
||||
case Constants.transactionDeclined:
|
||||
case Constants.declined: return "../../../../../img/exclamation.svg"
|
||||
default: return ""
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ Rectangle {
|
|||
ColorOverlay {
|
||||
anchors.fill: stateImage
|
||||
source: stateImage
|
||||
color: state == Constants.confirmed ? Style.current.transparent : Style.current.text
|
||||
color: state === Constants.confirmed ? Style.current.transparent : Style.current.textColor
|
||||
}
|
||||
|
||||
StyledText {
|
||||
|
@ -48,7 +48,7 @@ Rectangle {
|
|||
return Style.current.danger
|
||||
}
|
||||
if (root.state === Constants.confirmed || root.state === Constants.declined) {
|
||||
return Style.current.text
|
||||
return Style.current.textColor
|
||||
}
|
||||
|
||||
return Style.current.secondaryText
|
||||
|
@ -59,9 +59,10 @@ Rectangle {
|
|||
case Constants.confirmed: return qsTr("Confirmed")
|
||||
case Constants.unknown: return qsTr("Unknown token")
|
||||
case Constants.addressRequested: return qsTr("Address requested")
|
||||
case Constants.addressReceived: return qsTr("Address received")
|
||||
case Constants.transactionRequested: return qsTr("Waiting to accept")
|
||||
case Constants.addressReceived: return (!root.outgoing ? qsTr("Address shared") : qsTr("Address received"))
|
||||
case Constants.transactionDeclined:
|
||||
case Constants.declined: return qsTr("Transaction declined")
|
||||
case Constants.shared: return qsTr("Shared ‘Other Account’")
|
||||
case Constants.failure: return qsTr("Failure")
|
||||
default: return qsTr("Unknown state")
|
||||
}
|
||||
|
@ -69,8 +70,7 @@ Rectangle {
|
|||
font.weight: Font.Medium
|
||||
anchors.left: stateImage.right
|
||||
anchors.leftMargin: 4
|
||||
bottomPadding: Style.current.halfPadding
|
||||
topPadding: Style.current.halfPadding
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.pixelSize: 13
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,12 @@ ModalPopup {
|
|||
title: qsTrId("command-button-send")
|
||||
height: 504
|
||||
|
||||
property var selectedRecipient
|
||||
onSelectedRecipientChanged: {
|
||||
selectRecipient.selectedRecipient = this.selectedRecipient
|
||||
selectRecipient.readOnly = !!this.selectedRecipient && !!this.selectedRecipient.address
|
||||
}
|
||||
|
||||
property MessageDialog sendingError: MessageDialog {
|
||||
id: sendingError
|
||||
title: qsTr("Error sending the transaction")
|
||||
|
@ -94,6 +100,8 @@ ModalPopup {
|
|||
accounts: walletModel.accounts
|
||||
contacts: profileModel.addedContacts
|
||||
label: qsTr("Recipient")
|
||||
readOnly: !!root.selectedRecipient && !!root.selectedRecipient.address
|
||||
selectedRecipient: root.selectedRecipient
|
||||
anchors.top: separator.bottom
|
||||
anchors.topMargin: 10
|
||||
width: stack.width
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org>
|
File diff suppressed because it is too large
Load Diff
|
@ -25,14 +25,13 @@ QtObject {
|
|||
readonly property string generatedWalletType: "generated"
|
||||
|
||||
// Transaction states
|
||||
readonly property string pending: "pending"
|
||||
readonly property string confirmed: "confirmed"
|
||||
readonly property string unknown: "unknown"
|
||||
readonly property string addressRequested: "addressRequested"
|
||||
readonly property string addressReceived: "addressReceived"
|
||||
readonly property string declined: "declined"
|
||||
readonly property string shared: "shared"
|
||||
readonly property string failure: "failure"
|
||||
readonly property int addressRequested: 1
|
||||
readonly property int declined: 2
|
||||
readonly property int addressReceived: 3
|
||||
readonly property int transactionRequested: 4
|
||||
readonly property int transactionDeclined: 5
|
||||
readonly property int pending: 6
|
||||
readonly property int confirmed: 7
|
||||
|
||||
readonly property var accountColors: [
|
||||
"#9B832F",
|
||||
|
|
|
@ -2,8 +2,14 @@ pragma Singleton
|
|||
|
||||
import QtQuick 2.13
|
||||
import "../shared/xss.js" as XSS
|
||||
import "./BigNumber/bignumber.js" as BigNumber
|
||||
|
||||
QtObject {
|
||||
function newBigNumber(number) {
|
||||
// See here for docs: https://github.com/peterolson/BigInteger.js
|
||||
return BigNumber.bigInt(number)
|
||||
}
|
||||
|
||||
function isHex(value) {
|
||||
return /^(-0x|0x)?[0-9a-fA-F]*$/i.test(value)
|
||||
}
|
||||
|
|
|
@ -167,6 +167,7 @@ DISTFILES += \
|
|||
app/AppLayouts/Wallet/components/collectiblesComponents/CollectiblesModal.qml \
|
||||
app/AppLayouts/Wallet/components/collectiblesComponents/CollectiblesModalContent.qml \
|
||||
app/AppLayouts/Wallet/components/collectiblesComponents/collectiblesData.js \
|
||||
app/AppLayouts/Wallet/data/Tokens.qml \
|
||||
fonts/InterStatus/InterStatus-Black.otf \
|
||||
fonts/InterStatus/InterStatus-BlackItalic.otf \
|
||||
fonts/InterStatus/InterStatus-Bold.otf \
|
||||
|
|
|
@ -18,6 +18,7 @@ Item {
|
|||
property int iconHeight: 24
|
||||
property int iconWidth: 24
|
||||
property bool copyToClipboard: false
|
||||
property bool readOnly: false
|
||||
|
||||
readonly property bool hasIcon: icon.toString() !== ""
|
||||
readonly property var forceActiveFocus: function () {
|
||||
|
@ -65,7 +66,7 @@ Item {
|
|||
if (!!validationError) {
|
||||
return Style.current.danger
|
||||
}
|
||||
if (inputValue.focus) {
|
||||
if (!inputBox.readOnly && inputValue.focus) {
|
||||
return Style.current.inputBorderFocus
|
||||
}
|
||||
return Style.current.transparent
|
||||
|
@ -87,6 +88,7 @@ Item {
|
|||
leftPadding: inputBox.hasIcon ? iconWidth + 20 : Style.current.padding
|
||||
selectByMouse: true
|
||||
font.pixelSize: fontPixelSize
|
||||
readOnly: inputBox.readOnly
|
||||
background: Rectangle {
|
||||
color: Style.current.transparent
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ Item {
|
|||
property alias label: txtLabel.text
|
||||
// If supplied, additional info will be displayed top-right in danger colour (red)
|
||||
property alias additionalInfo: txtAddlInfo.text
|
||||
property var selectedRecipient: { }
|
||||
property var selectedRecipient
|
||||
property bool readOnly: false
|
||||
height: (readOnly ? inpReadOnly.height : inpAddress.height) + txtLabel.height
|
||||
//% "Invalid ethereum address"
|
||||
|
@ -106,7 +106,7 @@ Item {
|
|||
textField.verticalAlignment: TextField.AlignVCenter
|
||||
textField.font.pixelSize: 15
|
||||
textField.color: Style.current.secondaryText
|
||||
textField.readOnly: true
|
||||
readOnly: true
|
||||
validationErrorAlignment: TextEdit.AlignRight
|
||||
validationErrorTopMargin: 8
|
||||
customHeight: 56
|
||||
|
|
Loading…
Reference in New Issue