feat: add sticker popup
Add sticker popup Add send sticker message Add ability to select sticker pack and show stickers for pack with scroll 1. Sticker history 2. Install sticker packs 3. Sticker market 1. Sticker packs are installed on app start up until installation of sticker pack functionality is added 2. Optimisations such as preloading images to be done so that sticker images are not downloaded each time.
This commit is contained in:
parent
6a49070431
commit
847eb2623f
|
@ -3,9 +3,12 @@ import ../../status/chat as chat_model
|
|||
import ../../status/mailservers as mailserver_model
|
||||
import ../../signals/types
|
||||
import ../../status/libstatus/types as status_types
|
||||
import ../../status/libstatus/wallet as status_wallet
|
||||
import ../../status/[chat, contacts, status]
|
||||
import view, views/channels_list
|
||||
|
||||
from eth/common/utils import parseAddress
|
||||
|
||||
logScope:
|
||||
topics = "chat-controller"
|
||||
|
||||
|
@ -70,6 +73,12 @@ proc init*(self: ChatController) =
|
|||
self.status.mailservers.init()
|
||||
self.status.chat.init()
|
||||
|
||||
let currAcct = status_wallet.getWalletAccounts()[0] # TODO: make generic
|
||||
let currAddr = parseAddress(currAcct.address)
|
||||
let installedStickers = self.status.chat.getInstalledStickers(currAddr)
|
||||
for stickerPack in installedStickers:
|
||||
self.view.addStickerPackToList(stickerPack)
|
||||
|
||||
proc handleMessage(self: ChatController, data: MessageSignal) =
|
||||
self.status.chat.update(data.chats, data.messages)
|
||||
|
||||
|
|
|
@ -4,9 +4,10 @@ import ../../status/status
|
|||
import ../../status/chat as status_chat
|
||||
import ../../status/contacts as status_contacts
|
||||
import ../../status/chat/[chat, message]
|
||||
import ../../status/libstatus/types
|
||||
import ../../status/profile/profile
|
||||
|
||||
import views/channels_list, views/message_list, views/chat_item
|
||||
import views/channels_list, views/message_list, views/chat_item, views/sticker_pack_list, views/sticker_list
|
||||
|
||||
logScope:
|
||||
topics = "chats-view"
|
||||
|
@ -19,6 +20,10 @@ QtObject:
|
|||
callResult: string
|
||||
messageList: Table[string, ChatMessageList]
|
||||
activeChannel*: ChatItemView
|
||||
activeStickerPackId*: int
|
||||
stickerPacks*: StickerPackList
|
||||
stickers*: Table[int, StickerList]
|
||||
emptyStickerList: StickerList
|
||||
|
||||
proc setup(self: ChatsView) = self.QAbstractListModel.setup
|
||||
|
||||
|
@ -28,6 +33,7 @@ QtObject:
|
|||
for msg in self.messageList.values:
|
||||
msg.delete
|
||||
self.messageList = initTable[string, ChatMessageList]()
|
||||
self.stickers = initTable[int, StickerList]()
|
||||
self.QAbstractListModel.delete
|
||||
|
||||
proc newChatsView*(status: Status): ChatsView =
|
||||
|
@ -35,9 +41,23 @@ QtObject:
|
|||
result.status = status
|
||||
result.chats = newChannelsList()
|
||||
result.activeChannel = newChatItemView(status)
|
||||
result.activeStickerPackId = -1
|
||||
result.messageList = initTable[string, ChatMessageList]()
|
||||
result.stickerPacks = newStickerPackList()
|
||||
result.stickers = initTable[int, StickerList]()
|
||||
result.emptyStickerList = newStickerList()
|
||||
result.setup()
|
||||
|
||||
proc addStickerPackToList*(self: ChatsView, stickerPack: StickerPack) =
|
||||
discard self.stickerPacks.addStickerPackToList(stickerPack)
|
||||
self.stickers[stickerPack.id] = newStickerList(stickerPack.stickers)
|
||||
|
||||
proc getStickerPackList(self: ChatsView): QVariant {.slot.} =
|
||||
newQVariant(self.stickerPacks)
|
||||
|
||||
QtProperty[QVariant] stickerPacks:
|
||||
read = getStickerPackList
|
||||
|
||||
proc getChatsList(self: ChatsView): QVariant {.slot.} =
|
||||
newQVariant(self.chats)
|
||||
|
||||
|
@ -67,6 +87,24 @@ QtObject:
|
|||
read = getActiveChannelIdx
|
||||
write = setActiveChannelByIndex
|
||||
notify = activeChannelChanged
|
||||
|
||||
proc activeStickerPackChanged*(self: ChatsView) {.signal.}
|
||||
|
||||
proc setActiveStickerPackById*(self: ChatsView, id: int) {.slot.} =
|
||||
if self.activeStickerPackId == id:
|
||||
return
|
||||
|
||||
self.activeStickerPackId = id
|
||||
self.activeStickerPackChanged()
|
||||
|
||||
proc getStickerList*(self: ChatsView): QVariant {.slot.} =
|
||||
if self.activeStickerPackId <= 0:
|
||||
return newQVariant(self.emptyStickerList)
|
||||
result = newQVariant(self.stickers[self.activeStickerPackId])
|
||||
|
||||
QtProperty[QVariant] stickers:
|
||||
read = getStickerList
|
||||
notify = activeStickerPackChanged
|
||||
|
||||
proc setActiveChannel*(self: ChatsView, channel: string) =
|
||||
if(channel == ""): return
|
||||
|
@ -120,6 +158,9 @@ QtObject:
|
|||
|
||||
proc sendMessage*(self: ChatsView, message: string) {.slot.} =
|
||||
discard self.status.chat.sendMessage(self.activeChannel.id, message)
|
||||
|
||||
proc sendSticker*(self: ChatsView, hash: string, pack: int) {.slot.} =
|
||||
self.status.chat.sendSticker(self.activeChannel.id, hash, pack)
|
||||
|
||||
proc joinChat*(self: ChatsView, channel: string, chatTypeInt: int): int {.slot.} =
|
||||
self.status.chat.join(channel, ChatType(chatTypeInt))
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
import NimQml, Tables
|
||||
import ../../../status/chat/stickers
|
||||
|
||||
import ../../../status/libstatus/types
|
||||
|
||||
type
|
||||
StickerRoles {.pure.} = enum
|
||||
Url = UserRole + 1
|
||||
Hash = UserRole + 2
|
||||
|
||||
QtObject:
|
||||
type
|
||||
StickerList* = ref object of QAbstractListModel
|
||||
stickers*: seq[Sticker]
|
||||
|
||||
proc setup(self: StickerList) = self.QAbstractListModel.setup
|
||||
|
||||
proc delete(self: StickerList) = self.QAbstractListModel.delete
|
||||
|
||||
proc newStickerList*(stickers: seq[Sticker] = @[]): StickerList =
|
||||
new(result, delete)
|
||||
result.stickers = stickers
|
||||
result.setup()
|
||||
|
||||
method rowCount(self: StickerList, index: QModelIndex = nil): int = self.stickers.len
|
||||
|
||||
method data(self: StickerList, index: QModelIndex, role: int): QVariant =
|
||||
if not index.isValid:
|
||||
return
|
||||
if index.row < 0 or index.row >= self.stickers.len:
|
||||
return
|
||||
|
||||
let sticker = self.stickers[index.row]
|
||||
let stickerRole = role.StickerRoles
|
||||
case stickerRole:
|
||||
of StickerRoles.Url: result = newQVariant(decodeContentHash(sticker.hash))
|
||||
of StickerRoles.Hash: result = newQVariant(sticker.hash)
|
||||
|
||||
method roleNames(self: StickerList): Table[int, string] =
|
||||
{
|
||||
StickerRoles.Url.int:"url",
|
||||
StickerRoles.Hash.int:"hash"
|
||||
}.toTable
|
|
@ -0,0 +1,60 @@
|
|||
import NimQml, Tables
|
||||
import ../../../status/chat/stickers
|
||||
import ../../../status/libstatus/types
|
||||
|
||||
type
|
||||
StickerPackRoles {.pure.} = enum
|
||||
Author = UserRole + 1,
|
||||
Id = UserRole + 2
|
||||
Name = UserRole + 3
|
||||
Price = UserRole + 4
|
||||
Preview = UserRole + 5
|
||||
Thumbnail = UserRole + 6
|
||||
|
||||
QtObject:
|
||||
type
|
||||
StickerPackList* = ref object of QAbstractListModel
|
||||
packs*: seq[StickerPack]
|
||||
|
||||
proc setup(self: StickerPackList) = self.QAbstractListModel.setup
|
||||
|
||||
proc delete(self: StickerPackList) = self.QAbstractListModel.delete
|
||||
|
||||
proc newStickerPackList*(): StickerPackList =
|
||||
new(result, delete)
|
||||
result.packs = @[]
|
||||
result.setup()
|
||||
|
||||
method rowCount(self: StickerPackList, index: QModelIndex = nil): int = self.packs.len
|
||||
|
||||
method data(self: StickerPackList, index: QModelIndex, role: int): QVariant =
|
||||
if not index.isValid:
|
||||
return
|
||||
if index.row < 0 or index.row >= self.packs.len:
|
||||
return
|
||||
|
||||
let stickerPack = self.packs[index.row]
|
||||
let stickerPackRole = role.StickerPackRoles
|
||||
case stickerPackRole:
|
||||
of StickerPackRoles.Author: result = newQVariant(stickerPack.author)
|
||||
of StickerPackRoles.Id: result = newQVariant($stickerPack.id)
|
||||
of StickerPackRoles.Name: result = newQVariant(stickerPack.name)
|
||||
of StickerPackRoles.Price: result = newQVariant(stickerPack.price)
|
||||
of StickerPackRoles.Preview: result = newQVariant(decodeContentHash(stickerPack.preview))
|
||||
of StickerPackRoles.Thumbnail: result = newQVariant(decodeContentHash(stickerPack.thumbnail))
|
||||
|
||||
method roleNames(self: StickerPackList): Table[int, string] =
|
||||
{
|
||||
StickerPackRoles.Author.int:"author",
|
||||
StickerPackRoles.Id.int:"id",
|
||||
StickerPackRoles.Name.int: "name",
|
||||
StickerPackRoles.Price.int: "price",
|
||||
StickerPackRoles.Preview.int: "preview",
|
||||
StickerPackRoles.Thumbnail.int: "thumbnail"
|
||||
}.toTable
|
||||
|
||||
proc addStickerPackToList*(self: StickerPackList, pack: StickerPack): int =
|
||||
self.beginInsertRows(newQModelIndex(), 0, 0)
|
||||
self.packs.insert(pack, 0)
|
||||
self.endInsertRows()
|
||||
result = 0
|
|
@ -31,8 +31,8 @@ proc init*(self: ProfileController, account: Account) =
|
|||
# Ideally, this module should call getSettings once, and fill the
|
||||
# profile with all the information comming from the settings.
|
||||
let response = status_settings.getSettings()
|
||||
let pubKey = parseJSON($response)["result"]["public-key"].getStr
|
||||
let mnemonic = parseJSON($response)["result"]["mnemonic"].getStr
|
||||
let pubKey = response["public-key"].getStr
|
||||
let mnemonic = response["mnemonic"].getStr
|
||||
profile.id = pubKey
|
||||
|
||||
self.view.setNewProfile(profile)
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import eventemitter, json, strutils, sequtils, tables, chronicles
|
||||
import libstatus/chat as status_chat
|
||||
import libstatus/stickers as status_stickers
|
||||
import libstatus/types
|
||||
import profile/profile
|
||||
import chat/[chat, message]
|
||||
import chat/[chat, message], wallet
|
||||
import ../signals/messages
|
||||
import ens
|
||||
import eth/common/eth_types
|
||||
|
||||
type
|
||||
ChatUpdateArgs* = ref object of Args
|
||||
|
@ -78,9 +81,21 @@ proc join*(self: ChatModel, chatId: string, chatType: ChatType) =
|
|||
|
||||
self.events.emit("channelJoined", ChannelArgs(chat: chat))
|
||||
|
||||
proc getInstalledStickers*(self: ChatModel, address: EthAddress): seq[StickerPack] =
|
||||
# TODO: needs more fleshing out to determine which sticker packs
|
||||
# we own -- owned sticker packs will simply allowed them to be installed
|
||||
discard status_stickers.getBalance(address)
|
||||
|
||||
result = status_stickers.getInstalledStickers()
|
||||
|
||||
proc init*(self: ChatModel) =
|
||||
let chatList = status_chat.loadChats()
|
||||
|
||||
# TODO: Temporarily install sticker packs as a first step. Later, once installation
|
||||
# of sticker packs is supported, this should be removed, and a default "No
|
||||
# stickers installed" view should show if no sticker packs are installed.
|
||||
status_stickers.installStickers()
|
||||
|
||||
var filters:seq[JsonNode] = @[]
|
||||
for chat in chatList:
|
||||
if self.hasChannel(chat.id): continue
|
||||
|
@ -133,6 +148,10 @@ proc sendMessage*(self: ChatModel, chatId: string, msg: string): string =
|
|||
self.emitUpdate(sentMessage)
|
||||
sentMessage
|
||||
|
||||
proc sendSticker*(self: ChatModel, chatId: string, hash: string, pack: int) =
|
||||
var response = status_chat.sendStickerMessage(chatId, hash, pack)
|
||||
self.emitUpdate(response)
|
||||
|
||||
proc chatMessages*(self: ChatModel, chatId: string, initialLoad:bool = true) =
|
||||
if not self.msgCursor.hasKey(chatId):
|
||||
self.msgCursor[chatId] = "";
|
||||
|
|
|
@ -78,7 +78,22 @@ proc sendChatMessage*(chatId: string, msg: string): string =
|
|||
"responseTo": nil,
|
||||
"ensName": nil,
|
||||
"sticker": nil,
|
||||
"contentType": 1
|
||||
"contentType": ContentType.Message.int
|
||||
}
|
||||
])
|
||||
|
||||
proc sendStickerMessage*(chatId: string, hash: string, pack: int): string =
|
||||
callPrivateRPC("sendChatMessage".prefix, %* [
|
||||
{
|
||||
"chatId": chatId,
|
||||
"text": "Update to latest version to see a nice sticker here!",
|
||||
"responseTo": nil,
|
||||
"ensName": nil,
|
||||
"sticker": {
|
||||
"hash": hash,
|
||||
"pack": pack
|
||||
},
|
||||
"contentType": ContentType.Sticker.int
|
||||
}
|
||||
])
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import sequtils, strformat, sugar, macros, tables, eth/common/eth_types, stew/byteutils, nimcrypto
|
||||
import sequtils, strformat, sugar, macros, tables
|
||||
import eth/common/eth_types, stew/byteutils, nimcrypto
|
||||
from eth/common/utils import parseAddress
|
||||
|
||||
type
|
||||
|
@ -18,14 +19,26 @@ type Contract* = ref object
|
|||
methods*: Table[string, Method]
|
||||
|
||||
let CONTRACTS: seq[Contract] = @[
|
||||
Contract(name: "snt", network: Network.Mainnet, address: parseAddress("0x744d70fdbe2ba4cf95131626614a1763df805b9e")),
|
||||
Contract(name: "snt", network: Network.Mainnet, address: parseAddress("0x744d70fdbe2ba4cf95131626614a1763df805b9e"),
|
||||
methods: [
|
||||
("approveAndCall", Method(signature: "approveAndCall(address,uint256,bytes)"))
|
||||
].toTable
|
||||
),
|
||||
Contract(name: "snt", network: Network.Testnet, address: parseAddress("0xc55cf4b03948d7ebc8b9e8bad92643703811d162")),
|
||||
Contract(name: "tribute-to-talk", network: Network.Testnet, address: parseAddress("0xC61aa0287247a0398589a66fCD6146EC0F295432")),
|
||||
Contract(name: "stickers", network: Network.Mainnet, address: parseAddress("0x0577215622f43a39f4bc9640806dfea9b10d2a36")),
|
||||
Contract(name: "stickers", network: Network.Testnet, address: parseAddress("0x8cc272396be7583c65bee82cd7b743c69a87287d")),
|
||||
Contract(name: "sticker-market", network: Network.Mainnet, address: parseAddress("0x12824271339304d3a9f7e096e62a2a7e73b4a7e7")),
|
||||
Contract(name: "sticker-market", network: Network.Mainnet, address: parseAddress("0x12824271339304d3a9f7e096e62a2a7e73b4a7e7"),
|
||||
methods: [
|
||||
("buyToken", Method(signature: "buyToken(uint256,address,uint256)"))
|
||||
].toTable
|
||||
),
|
||||
Contract(name: "sticker-market", network: Network.Testnet, address: parseAddress("0x6CC7274aF9cE9572d22DFD8545Fb8c9C9Bcb48AD")),
|
||||
Contract(name: "sticker-pack", network: Network.Mainnet, address: parseAddress("0x110101156e8F0743948B2A61aFcf3994A8Fb172e")),
|
||||
Contract(name: "sticker-pack", network: Network.Mainnet, address: parseAddress("0x110101156e8F0743948B2A61aFcf3994A8Fb172e"),
|
||||
methods: [
|
||||
("balanceOf", Method(signature: "balanceOf(address)"))
|
||||
].toTable
|
||||
),
|
||||
Contract(name: "sticker-pack", network: Network.Testnet, address: parseAddress("0xf852198d0385c4b871e0b91804ecd47c6ba97351")),
|
||||
# Strikers seems dead. Their website doesn't work anymore
|
||||
Contract(name: "strikers", network: Network.Mainnet, address: parseAddress("0xdcaad9fd9a74144d226dbf94ce6162ca9f09ed7e"),
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
import json
|
||||
import core
|
||||
import json
|
||||
|
||||
proc saveSettings*(key: string, value: string): string =
|
||||
callPrivateRPC("settings_saveSetting", %* [
|
||||
key, $value
|
||||
])
|
||||
|
||||
proc getSettings*(): string =
|
||||
callPrivateRPC("settings_getSettings")
|
||||
# TODO: return an Table/Object instead of string
|
||||
|
||||
proc getWeb3ClientVersion*(): string =
|
||||
parseJson(callPrivateRPC("web3_clientVersion"))["result"].getStr
|
||||
|
||||
proc getSettings*(): JsonNode =
|
||||
callPrivateRPC("settings_getSettings").parseJSON()["result"]
|
||||
# TODO: return an Table/Object instead
|
||||
|
||||
proc getSetting*(name: string): string =
|
||||
let settings: JsonNode = getSettings()
|
||||
result = settings{name}.getStr
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -63,6 +63,13 @@ type
|
|||
keyUid*: string
|
||||
photoPath*: string
|
||||
|
||||
type
|
||||
RpcResponse* = ref object
|
||||
jsonrpc*: string
|
||||
result*: string
|
||||
id*: int
|
||||
error*: string
|
||||
|
||||
proc toAccount*(account: GeneratedAccount): Account =
|
||||
result = Account(name: account.name, photoPath: account.photoPath, keyUid: account.address)
|
||||
|
||||
|
@ -90,3 +97,18 @@ type
|
|||
value*: string
|
||||
fromAddress*: string
|
||||
to*: string
|
||||
|
||||
type
|
||||
RpcException* = object of Exception
|
||||
|
||||
type Sticker* = ref object
|
||||
hash*: string
|
||||
|
||||
type StickerPack* = ref object
|
||||
author*: string
|
||||
id*: int
|
||||
name*: string
|
||||
price*: int
|
||||
preview*: string
|
||||
stickers*: seq[Sticker]
|
||||
thumbnail*: string
|
||||
|
|
|
@ -50,7 +50,7 @@ proc sendTransaction*(self: WalletModel, from_value: string, to: string, value:
|
|||
proc getDefaultCurrency*(self: WalletModel): string =
|
||||
# TODO: this should come from a model? It is going to be used too in the
|
||||
# profile section and ideally we should not call the settings more than once
|
||||
status_settings.getSettings().parseJSON()["result"]["currency"].getStr
|
||||
status_settings.getSetting("currency")
|
||||
|
||||
proc setDefaultCurrency*(self: WalletModel, currency: string) =
|
||||
discard status_settings.saveSettings("currency", currency)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import strformat, httpclient, json, chronicles, sequtils, strutils, tables
|
||||
import ../libstatus/[core, contracts]
|
||||
import ../libstatus/core as status
|
||||
import ../libstatus/contracts as contracts
|
||||
import eth/common/eth_types
|
||||
import account
|
||||
|
||||
|
|
|
@ -36,15 +36,24 @@ StackLayout {
|
|||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: chatInputContainer
|
||||
height: 70
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 0
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignBottom
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: height
|
||||
transformOrigin: Item.Bottom
|
||||
clip: true
|
||||
|
||||
ChatInput {}
|
||||
ChatInput {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: -border.width
|
||||
border.width: 1
|
||||
border.color: Theme.grey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.13
|
||||
import "../../../../imports"
|
||||
import "../components"
|
||||
|
||||
Rectangle {
|
||||
border.width: 0
|
||||
|
||||
Button {
|
||||
id: chatSendBtn
|
||||
visible: txtData.length > 0
|
||||
width: 30
|
||||
height: 30
|
||||
text: ""
|
||||
anchors.rightMargin: Theme.padding
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
onClicked: {
|
||||
chatsModel.sendMessage(txtData.text)
|
||||
txtData.text = ""
|
||||
}
|
||||
background: Rectangle {
|
||||
color: parent.enabled ? Theme.blue : Theme.grey
|
||||
radius: 50
|
||||
}
|
||||
Image {
|
||||
source: "../../../img/arrowUp.svg"
|
||||
width: 12
|
||||
fillMode: Image.PreserveAspectFit
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: stickersIcon
|
||||
visible: txtData.length == 0
|
||||
width: 20
|
||||
height: 20
|
||||
anchors.rightMargin: Theme.padding
|
||||
anchors.right: parent.right
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "../../../img/stickers_icon" + (stickersPopup.opened ? "_open.svg" : ".svg")
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
MouseArea {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
if (stickersPopup.opened) {
|
||||
stickersPopup.close()
|
||||
} else {
|
||||
stickersPopup.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StickersPopup {
|
||||
id: stickersPopup
|
||||
width: 360
|
||||
height: 440
|
||||
x: parent.width - width - 8
|
||||
y: parent.height - sendBtns.height - height - 8
|
||||
stickerList: chatsModel.stickers
|
||||
stickerPackList: chatsModel.stickerPacks
|
||||
}
|
||||
}
|
||||
/*##^##
|
||||
Designer {
|
||||
D{i:0;autoSize:true;height:480;width:640}
|
||||
}
|
||||
##^##*/
|
|
@ -1,67 +1,31 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Layouts 1.13
|
||||
import "../components"
|
||||
import "../../../../shared"
|
||||
import "../../../../imports"
|
||||
|
||||
Rectangle {
|
||||
id: element2
|
||||
width: 200
|
||||
height: 70
|
||||
Layout.fillWidth: true
|
||||
color: "white"
|
||||
border.width: 0
|
||||
|
||||
visible: chatsModel.activeChannel.chatType != Constants.chatTypePrivateGroupChat || chatsModel.activeChannel.isMember(profileModel.profile.pubKey)
|
||||
|
||||
Rectangle {
|
||||
id: rectangle
|
||||
color: "#00000000"
|
||||
border.color: Theme.grey
|
||||
RowLayout {
|
||||
spacing: 0
|
||||
anchors.fill: parent
|
||||
|
||||
Button {
|
||||
id: chatSendBtn
|
||||
visible: txtData.length > 0
|
||||
x: 100
|
||||
width: 30
|
||||
height: 30
|
||||
text: ""
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 20
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 16
|
||||
onClicked: {
|
||||
chatsModel.sendMessage(txtData.text)
|
||||
txtData.text = ""
|
||||
}
|
||||
background: Rectangle {
|
||||
color: parent.enabled ? Theme.blue : Theme.grey
|
||||
radius: 50
|
||||
}
|
||||
Image {
|
||||
source: "../../../img/arrowUp.svg"
|
||||
width: 12
|
||||
fillMode: Image.PreserveAspectFit
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
StyledTextField {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: parent.width - sendBtns.width
|
||||
|
||||
id: txtData
|
||||
text: ""
|
||||
padding: 0
|
||||
leftPadding: 12
|
||||
rightPadding: Theme.padding
|
||||
font.pixelSize: 14
|
||||
placeholderText: qsTr("Type a message...")
|
||||
anchors.right: chatSendBtn.left
|
||||
anchors.rightMargin: 16
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 0
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
anchors.left: parent.left
|
||||
leftPadding: 24
|
||||
|
||||
selectByMouse: true
|
||||
Keys.onEnterPressed: {
|
||||
chatsModel.sendMessage(txtData.text)
|
||||
|
@ -75,10 +39,28 @@ Rectangle {
|
|||
color: "#00000000"
|
||||
}
|
||||
}
|
||||
|
||||
ChatButtons {
|
||||
id: sendBtns
|
||||
Layout.topMargin: 1
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: 30 + Theme.padding
|
||||
Layout.minimumWidth: 30 + Theme.padding
|
||||
Layout.maximumWidth: 200
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea1
|
||||
anchors.rightMargin: 50
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
txtData.forceActiveFocus(Qt.MouseFocusReason)
|
||||
}
|
||||
}
|
||||
}
|
||||
/*##^##
|
||||
Designer {
|
||||
D{i:0;width:600}
|
||||
D{i:0;autoSize:true;formeditorColor:"#ffffff";height:100;width:600}
|
||||
}
|
||||
##^##*/
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
TopBar 1.0 TopBar.qml
|
||||
ChatMessages 1.0 ChatMessages.qml
|
||||
ChatInput 1.0 ChatInput.qml
|
||||
EmptyChat 1.0 EmptyChat.qml
|
||||
EmptyChat 1.0 EmptyChat.qml
|
||||
ChatButtons 1.0 ChatButtons.qml
|
|
@ -0,0 +1,66 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Controls 2.12 as QQC2
|
||||
import QtQuick.Layouts 1.3
|
||||
import Qt.labs.platform 1.1
|
||||
|
||||
ListModel {
|
||||
ListElement {
|
||||
hash: "e30101701220fff8527a1b37070d46c9077877b7f7cc74da5c31adafe77ba65e5efefebf5d91"
|
||||
url: "QmfZrHmLR5VvkXSDbArDR3TX6j4FgpDcrvNz2fHSJk1VvG"
|
||||
}
|
||||
ListElement {
|
||||
hash: "e301017012208023d8c6bd327b0ac2be66423d59776a753d5f5492975fe0bd5b5601d7c1d9d3"
|
||||
url: "QmWxrbdgU5q3VxStTQr4VTBdJNqwatMAUf8KZBLEfqZyii"
|
||||
}
|
||||
ListElement {
|
||||
hash: "e3010170122064f4e8fa00a5b8164689e038a4d74e0b12f4490dcd4112e80057c254f6fbc135"
|
||||
url: "QmV8k5Y4mE8hhiydohBw8hqRQgFzAQMiveCYKZ6PkKNVgg"
|
||||
}
|
||||
ListElement {
|
||||
hash: "e301017012200d50bd618b0aed0562ed153de0bf77da766646e81a848982a2f8aaf7d7e94dcc"
|
||||
url: "QmPEdR6ayeLouro7FfkQSt5aq3nfzYK4FT4nxnoxn5FuhV"
|
||||
}
|
||||
ListElement {
|
||||
hash: "e3010170122055f08854a40acaac60355d9bb3eaa730b994e2e13484e67d2675103e0cda0c88"
|
||||
url: "QmU886Hu3XAwYp8hfkMVhKoMNsPeeAJr7wgjYqAiAd4enB"
|
||||
}
|
||||
ListElement {
|
||||
hash: "e301017012203fc2acfed328918bf000ee637ab4c25fa38f2c69b378b69b9212d61747d30c02"
|
||||
url: "QmSdYZpjEAUG3fUpkPpC9ATnoaaiTLLj3W587uwx943AC1"
|
||||
}
|
||||
ListElement {
|
||||
hash: "e3010170122096930b99e08c6c28c88c0b74bae7a0159f5c6438ab7d50294987533dabfee863"
|
||||
url: "QmYURuqdkoycSLLz2qfMgjeK18Y4kT8PQfExRfbziVLSZ8"
|
||||
}
|
||||
ListElement {
|
||||
hash: "e3010170122051ddbe29bee4bbc5fcf50d81faad0872f32b88cea4e4e4fcdbf2daf5d09eda76"
|
||||
url: "QmTrDqsuN4DgKfjnDrWgo92EFCD1vFffYcZ1jMEr3AgCnH"
|
||||
}
|
||||
ListElement {
|
||||
hash: "e301017012200647e07651c163515ce34d18b3c8636eeb4798dbaa1766b2a60facc59999b261"
|
||||
url: "QmNmAiwa9PDcZs7b2oQ2D1wHfQfi1MFjp6QcfzHzGhhNJt"
|
||||
}
|
||||
ListElement {
|
||||
hash: "e30101701220c539bfa744e39cf2ece1ab379a15c95338d513a9ce5178d4ad28be486b801bc2"
|
||||
url: "QmbcY6hwDt3EKK6pJGJ6yFn3A872y2ajeBRrrKRj7KC3BX"
|
||||
}
|
||||
ListElement {
|
||||
hash: "e301017012205ea333b9eb89918ed592f43372bd58dc3a91a7a71aa68b37369c2f66f931fd87"
|
||||
url: "QmUi5NQSMg2kmhkLUtQ9Sjxnkwgn68x88wL2n357VAZdyx"
|
||||
}
|
||||
ListElement {
|
||||
hash: "e3010170122007f05ba31bd77003bff562ed932a8b440de1ad05481dc622b1c0c571d6b39ffc"
|
||||
url: "QmNse8urb4GJGEHYgUpRJBRwgiWaTGZtkoibVVUpveqfBq"
|
||||
}
|
||||
ListElement {
|
||||
hash: "e30101701220906b7a664a87707db72921cf5c7416c61a717dfcb5fcff9bc04b28c612ae554d"
|
||||
url: "QmY4QULmzFQ2AAbEuMvnd3Nd7qD8eWtyxiLD9CAf3kFZWU"
|
||||
}
|
||||
}
|
||||
|
||||
/*##^##
|
||||
Designer {
|
||||
D{i:0;autoSize:true;height:480;width:640}
|
||||
}
|
||||
##^##*/
|
|
@ -0,0 +1,32 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.13
|
||||
|
||||
ListModel {
|
||||
ListElement {
|
||||
author: "cryptoworld1373"
|
||||
name: "Status Cat"
|
||||
price: 0
|
||||
preview: "e3010170122050efc0a3e661339f31e1e44b3d15a1bf4e501c965a0523f57b701667fa90ccca"
|
||||
thumbnail: "QmfZrHmLR5VvkXSDbArDR3TX6j4FgpDcrvNz2fHSJk1VvG"
|
||||
}
|
||||
ListElement {
|
||||
author: "ETHDenver"
|
||||
name: "ETHDenver Bufficorn"
|
||||
price: 0
|
||||
preview: "e30101701220a62487ef23b1bbdc2bf39583bb4259bda032450ac90d199eec8b0b74fe8de580"
|
||||
thumbnail: "e30101701220d06f13f3de8da081ef2a1bc36ffa283c1bfe093bf45bc0332a6d748196e8ce16"
|
||||
}
|
||||
ListElement {
|
||||
author: "Brooklyn Design Factory"
|
||||
name: "Ghostatus"
|
||||
price: 0
|
||||
preview: "e3010170122027c67c9acbe98786f6db4aabca3fd3ec04993eaa3e08811aefe27d9786c3bf00"
|
||||
thumbnail: "e30101701220a7beb4be086ad31ae19c64e5a832853571e239d9799a923a03779c4435c6fdad"
|
||||
}
|
||||
}
|
||||
|
||||
/*##^##
|
||||
Designer {
|
||||
D{i:0;autoSize:true;height:480;width:640}
|
||||
}
|
||||
##^##*/
|
|
@ -1 +1,3 @@
|
|||
MessagesData 1.0 MessagesData.qml
|
||||
StickerData 1.0 StickerData.qml
|
||||
StickerPackData 1.0 StickerPackData.qml
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Layouts 1.13
|
||||
|
||||
import "../../../imports"
|
||||
import "../../../shared"
|
||||
import "./components"
|
||||
|
@ -50,6 +51,10 @@ Item {
|
|||
|
||||
AddChat {
|
||||
id: addChat
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.padding
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 59
|
||||
}
|
||||
|
||||
StackLayout {
|
||||
|
|
|
@ -2,108 +2,36 @@ import QtQuick 2.13
|
|||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Layouts 1.13
|
||||
import "../../../../shared"
|
||||
import "../../../../imports"
|
||||
import "../components"
|
||||
|
||||
Rectangle {
|
||||
id: addChat
|
||||
AddButton {
|
||||
id: btnAdd
|
||||
width: 36
|
||||
height: 36
|
||||
color: Theme.blue
|
||||
radius: 50
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 16
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 59
|
||||
|
||||
Image {
|
||||
id: addChatLbl
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "../../../img/plusSign.svg"
|
||||
width: 14
|
||||
height: 14
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
state: "default"
|
||||
rotation: 0
|
||||
states: [
|
||||
State {
|
||||
name: "default"
|
||||
PropertyChanges {
|
||||
target: addChatLbl
|
||||
rotation: 0
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "rotated"
|
||||
PropertyChanges {
|
||||
target: addChatLbl
|
||||
rotation: 45
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
from: "default"
|
||||
to: "rotated"
|
||||
RotationAnimation {
|
||||
duration: 150
|
||||
direction: RotationAnimation.Clockwise
|
||||
easing.type: Easing.InCubic
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: "rotated"
|
||||
to: "default"
|
||||
RotationAnimation {
|
||||
duration: 150
|
||||
direction: RotationAnimation.Counterclockwise
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
]
|
||||
onClicked: {
|
||||
let x = btnAdd.icon.x + btnAdd.icon.width / 2 - newChatMenu.width / 2
|
||||
newChatMenu.popup(x, btnAdd.icon.height + 10)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
addChatLbl.state = "rotated"
|
||||
let x = addChatLbl.x + addChatLbl.width / 2 - newChatMenu.width / 2
|
||||
newChatMenu.popup(x, addChatLbl.height + 10)
|
||||
|
||||
PopupMenu {
|
||||
id: newChatMenu
|
||||
Action {
|
||||
text: qsTr("Start new chat")
|
||||
icon.source: "../../../img/new_chat.svg"
|
||||
onTriggered: privateChatPopup.open()
|
||||
}
|
||||
|
||||
PopupMenu {
|
||||
id: newChatMenu
|
||||
Action {
|
||||
text: qsTr("Start new chat")
|
||||
icon.source: "../../../img/new_chat.svg"
|
||||
onTriggered: privateChatPopup.open()
|
||||
}
|
||||
Action {
|
||||
text: qsTr("Start group chat")
|
||||
icon.source: "../../../img/group_chat.svg"
|
||||
onTriggered: {
|
||||
onTriggered: groupChatPopup.open()
|
||||
}
|
||||
}
|
||||
Action {
|
||||
text: qsTr("Join public chat")
|
||||
icon.source: "../../../img/public_chat.svg"
|
||||
onTriggered: publicChatPopup.open()
|
||||
}
|
||||
onAboutToHide: {
|
||||
addChatLbl.state = "default"
|
||||
}
|
||||
Action {
|
||||
text: qsTr("Start group chat")
|
||||
icon.source: "../../../img/group_chat.svg"
|
||||
onTriggered: groupChatPopup.open()
|
||||
}
|
||||
Action {
|
||||
text: qsTr("Join public chat")
|
||||
icon.source: "../../../img/public_chat.svg"
|
||||
onTriggered: publicChatPopup.open()
|
||||
}
|
||||
onAboutToHide: {
|
||||
btnAdd.icon.state = "default"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*##^##
|
||||
Designer {
|
||||
D{i:0;formeditorZoom:3}
|
||||
}
|
||||
##^##*/
|
||||
|
|
|
@ -27,7 +27,7 @@ Rectangle {
|
|||
border.width: 0
|
||||
radius: Theme.radius
|
||||
|
||||
RoundImage {
|
||||
Identicon {
|
||||
id: accountImage
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtGraphicalEffects 1.0
|
||||
import "../../../../imports"
|
||||
import "../../../../shared"
|
||||
import "../ChatColumn/samples"
|
||||
|
||||
Popup {
|
||||
id: popup
|
||||
property var stickerList: StickerData {}
|
||||
property var stickerPackList: StickerPackData {}
|
||||
modal: false
|
||||
property int selectedPackId
|
||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
|
||||
background: Rectangle {
|
||||
radius: 8
|
||||
border.color: Theme.grey
|
||||
layer.enabled: true
|
||||
layer.effect: DropShadow{
|
||||
verticalOffset: 3
|
||||
radius: 8
|
||||
samples: 15
|
||||
fast: true
|
||||
cached: true
|
||||
color: "#22000000"
|
||||
}
|
||||
}
|
||||
contentItem: ColumnLayout {
|
||||
parent: popup
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 4
|
||||
Layout.rightMargin: 4
|
||||
Layout.topMargin: 4
|
||||
Layout.bottomMargin: 0
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
|
||||
Layout.preferredHeight: 400 - 4
|
||||
|
||||
Item {
|
||||
id: stickerHistory
|
||||
anchors.fill: parent
|
||||
visible: true
|
||||
|
||||
Image {
|
||||
id: imgNoStickers
|
||||
width: 56
|
||||
height: 56
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 134
|
||||
source: "../../../img/stickers_sad_icon.svg"
|
||||
}
|
||||
|
||||
Text {
|
||||
id: lblNoStickers
|
||||
width: parent.width
|
||||
font.pixelSize: 15
|
||||
text: qsTr("You don't have any stickers yet")
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
anchors.top: imgNoStickers.bottom
|
||||
anchors.topMargin: 8
|
||||
}
|
||||
|
||||
StyledButton {
|
||||
label: qsTr("Get Stickers")
|
||||
anchors.top: lblNoStickers.bottom
|
||||
anchors.topMargin: Theme.padding
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
|
||||
GridView {
|
||||
id: stickerGrid
|
||||
visible: false
|
||||
anchors.fill: parent
|
||||
cellWidth: 88
|
||||
cellHeight: 88
|
||||
model: stickerList
|
||||
focus: true
|
||||
clip: true
|
||||
delegate: Item {
|
||||
width: stickerGrid.cellWidth
|
||||
height: stickerGrid.cellHeight
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 4
|
||||
anchors.leftMargin: 4
|
||||
Image {
|
||||
width: 80
|
||||
height: 80
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "https://ipfs.infura.io/ipfs/" + url
|
||||
MouseArea {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
chatsModel.sendSticker(hash, popup.selectedPackId)
|
||||
popup.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: footerContent
|
||||
Layout.leftMargin: 8
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 40 - 8 * 2
|
||||
Layout.topMargin: 8
|
||||
Layout.rightMargin: 8
|
||||
Layout.bottomMargin: 8
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
|
||||
|
||||
AddButton {
|
||||
id: btnAddStickerPack
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
width: 24
|
||||
height: 24
|
||||
}
|
||||
|
||||
RoundedIcon {
|
||||
id: btnHistory
|
||||
size: 24
|
||||
color: Theme.darkGrey
|
||||
imgPath: "../../../img/history_icon.svg"
|
||||
anchors.left: btnAddStickerPack.right
|
||||
anchors.leftMargin: Theme.padding
|
||||
onClicked: {
|
||||
packIndicator.updatePosition(-1)
|
||||
stickerGrid.visible = false;
|
||||
stickerHistory.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Theme.padding
|
||||
anchors.top: parent.top
|
||||
anchors.left: btnHistory.right
|
||||
anchors.leftMargin: Theme.padding
|
||||
|
||||
Repeater {
|
||||
id: stickerPackListView
|
||||
model: stickerPackList
|
||||
|
||||
delegate: RoundedImage {
|
||||
Layout.preferredHeight: height
|
||||
Layout.preferredWidth: width
|
||||
width: 24
|
||||
height: 24
|
||||
source: "https://ipfs.infura.io/ipfs/" + thumbnail
|
||||
onClicked: {
|
||||
chatsModel.setActiveStickerPackById(id)
|
||||
popup.selectedPackId = id
|
||||
packIndicator.updatePosition(index)
|
||||
stickerGrid.visible = true;
|
||||
stickerHistory.visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
id: packIndicator
|
||||
border.color: Theme.blue
|
||||
border.width: 1
|
||||
height: 2
|
||||
width: 16
|
||||
x: 44
|
||||
y: footerContent.height + 8 - height
|
||||
|
||||
function updatePosition(index) {
|
||||
const startX = 44
|
||||
const skipX = 40
|
||||
const idx = index + 1
|
||||
packIndicator.x = startX + skipX * idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*##^##
|
||||
Designer {
|
||||
D{i:0;formeditorColor:"#ffffff";height:440;width:360}
|
||||
}
|
||||
##^##*/
|
|
@ -5,4 +5,5 @@ GroupInfoPopup 1.0 GroupInfoPopup.qml
|
|||
ProfilePropup 1.0 ProfilePopup.qml
|
||||
ChannelIcon 1.0 ChannelIcon.qml
|
||||
RenameGroupPopup 1.0 RenameGroupPopup.qml
|
||||
GroupChatPopup 1.0 GroupChatPopup.qml
|
||||
GroupChatPopup 1.0 GroupChatPopup.qml
|
||||
StickersPopup 1.0 StickersPopup.qml
|
||||
|
|
|
@ -19,7 +19,7 @@ Rectangle {
|
|||
border.width: 0
|
||||
radius: Theme.radius
|
||||
|
||||
RoundImage {
|
||||
Identicon {
|
||||
id: accountImage
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.padding
|
||||
|
|
|
@ -3,124 +3,59 @@ import QtQuick.Controls 2.13
|
|||
import "../../../../shared"
|
||||
import "../../../../imports"
|
||||
|
||||
Rectangle {
|
||||
id: addAccount
|
||||
width: 36
|
||||
height: 36
|
||||
color: Theme.blue
|
||||
radius: 50
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 16
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 59
|
||||
|
||||
Image {
|
||||
id: addAccountLbl
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "../../../img/plusSign.svg"
|
||||
width: 14
|
||||
height: 14
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
state: "default"
|
||||
rotation: 0
|
||||
states: [
|
||||
State {
|
||||
name: "default"
|
||||
PropertyChanges {
|
||||
target: addAccountLbl
|
||||
rotation: 0
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "rotated"
|
||||
PropertyChanges {
|
||||
target: addAccountLbl
|
||||
rotation: 45
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
from: "default"
|
||||
to: "rotated"
|
||||
RotationAnimation {
|
||||
duration: 150
|
||||
direction: RotationAnimation.Clockwise
|
||||
easing.type: Easing.InCubic
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: "rotated"
|
||||
to: "default"
|
||||
RotationAnimation {
|
||||
duration: 150
|
||||
direction: RotationAnimation.Counterclockwise
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
]
|
||||
AddButton {
|
||||
id: btnAdd
|
||||
onClicked: {
|
||||
let x = btnAdd.icon.x + btnAdd.icon.width / 2 - newAccountMenu.width / 2
|
||||
newAccountMenu.popup(x, btnAdd.icon.height + 10)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
addAccountLbl.state = "rotated"
|
||||
let x = addAccountLbl.x + addAccountLbl.width / 2 - newAccountMenu.width / 2
|
||||
newAccountMenu.popup(x, addAccountLbl.height + 10)
|
||||
}
|
||||
GenerateAccountModal {
|
||||
id: generateAccountModal
|
||||
}
|
||||
AddAccountWithSeed {
|
||||
id: addAccountWithSeedModal
|
||||
}
|
||||
AddAccountWithPrivateKey {
|
||||
id: addAccountWithPrivateKeydModal
|
||||
}
|
||||
AddWatchOnlyAccount {
|
||||
id: addWatchOnlyAccountModal
|
||||
}
|
||||
|
||||
GenerateAccountModal {
|
||||
id: generateAccountModal
|
||||
PopupMenu {
|
||||
id: newAccountMenu
|
||||
width: 280
|
||||
Action {
|
||||
text: qsTr("Generate an account")
|
||||
icon.source: "../../../img/generate_account.svg"
|
||||
onTriggered: {
|
||||
generateAccountModal.open()
|
||||
}
|
||||
}
|
||||
AddAccountWithSeed {
|
||||
id: addAccountWithSeedModal
|
||||
Action {
|
||||
text: qsTr("Add a watch-only address")
|
||||
icon.source: "../../../img/add_watch_only.svg"
|
||||
onTriggered: {
|
||||
addWatchOnlyAccountModal.open()
|
||||
}
|
||||
}
|
||||
AddAccountWithPrivateKey {
|
||||
id: addAccountWithPrivateKeydModal
|
||||
Action {
|
||||
text: qsTr("Enter a seed phrase")
|
||||
icon.source: "../../../img/enter_seed_phrase.svg"
|
||||
onTriggered: {
|
||||
addAccountWithSeedModal.open()
|
||||
}
|
||||
}
|
||||
AddWatchOnlyAccount {
|
||||
id: addWatchOnlyAccountModal
|
||||
Action {
|
||||
text: qsTr("Enter a private key")
|
||||
icon.source: "../../../img/enter_private_key.svg"
|
||||
onTriggered: {
|
||||
addAccountWithPrivateKeydModal.open()
|
||||
}
|
||||
}
|
||||
|
||||
PopupMenu {
|
||||
id: newAccountMenu
|
||||
width: 280
|
||||
Action {
|
||||
text: qsTr("Generate an account")
|
||||
icon.source: "../../../img/generate_account.svg"
|
||||
onTriggered: {
|
||||
generateAccountModal.open()
|
||||
}
|
||||
}
|
||||
Action {
|
||||
text: qsTr("Add a watch-only address")
|
||||
icon.source: "../../../img/add_watch_only.svg"
|
||||
onTriggered: {
|
||||
addWatchOnlyAccountModal.open()
|
||||
}
|
||||
}
|
||||
Action {
|
||||
text: qsTr("Enter a seed phrase")
|
||||
icon.source: "../../../img/enter_seed_phrase.svg"
|
||||
onTriggered: {
|
||||
addAccountWithSeedModal.open()
|
||||
}
|
||||
}
|
||||
Action {
|
||||
text: qsTr("Enter a private key")
|
||||
icon.source: "../../../img/enter_private_key.svg"
|
||||
onTriggered: {
|
||||
addAccountWithPrivateKeydModal.open()
|
||||
}
|
||||
}
|
||||
onAboutToHide: {
|
||||
addAccountLbl.state = "default"
|
||||
}
|
||||
onAboutToHide: {
|
||||
btnAdd.icon.state = "default"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="7" height="13" viewBox="0 0 7 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1 1V6.17157C1 6.70201 1.21071 7.21071 1.58579 7.58579L6 12" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 254 B |
|
@ -0,0 +1,4 @@
|
|||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.56858 13.4863C7.22903 13.2491 6.75712 13.2426 6.46422 13.5354C6.17133 13.8283 6.16876 14.3077 6.49708 14.5603C7.46695 15.3063 8.68155 15.7499 9.99976 15.7499C11.318 15.7499 12.5326 15.3063 13.5024 14.5603C13.8308 14.3077 13.8282 13.8283 13.5353 13.5354C13.2424 13.2426 12.7705 13.2491 12.4309 13.4863C11.742 13.9676 10.9039 14.2499 9.99976 14.2499C9.09565 14.2499 8.25747 13.9676 7.56858 13.4863Z" fill="#939BA1"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.8645 11.6499C19.9401 11.1946 19.8959 10.7435 19.7602 10.3174C19.5838 9.76409 19.253 9.25286 18.8292 8.82907L11.1708 1.17069C10.747 0.746897 10.2358 0.416048 9.68247 0.239716C9.62921 0.222742 9.57555 0.2072 9.52155 0.193144C9.14354 0.0947561 8.7484 0.0692148 8.35001 0.135358C8.28899 0.145488 8.22816 0.156171 8.16753 0.1674C3.51984 1.02813 0 5.10295 0 9.99988C0 15.5227 4.47715 19.9999 10 19.9999C14.8969 19.9999 18.9717 16.48 19.8325 11.8324C19.8437 11.7717 19.8544 11.7109 19.8645 11.6499ZM1.5 9.99988C1.5 6.08625 4.14622 2.78816 7.74701 1.8013C7.87574 1.76602 8 1.8664 8 1.99988C8 7.52272 12.4772 11.9999 18 11.9999C18.1335 11.9999 18.2339 12.1241 18.1986 12.2529C17.2117 15.8537 13.9136 18.4999 10 18.4999C5.30558 18.4999 1.5 14.6943 1.5 9.99988ZM18 10.4999C18.1011 10.4999 18.1641 10.3935 18.1094 10.3085C18.0185 10.1673 17.9054 10.0266 17.7685 9.88973L10.1101 2.23135C9.97328 2.09448 9.83259 1.98135 9.69142 1.89052C9.60642 1.83582 9.5 1.89879 9.5 1.99988C9.5 6.6943 13.3056 10.4999 18 10.4999Z" fill="#939BA1"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,4 @@
|
|||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.56858 13.4863C7.22903 13.2491 6.75712 13.2426 6.46422 13.5354C6.17133 13.8283 6.16876 14.3077 6.49708 14.5603C7.46695 15.3063 8.68155 15.7499 9.99976 15.7499C11.318 15.7499 12.5326 15.3063 13.5024 14.5603C13.8308 14.3077 13.8282 13.8283 13.5353 13.5354C13.2424 13.2426 12.7705 13.2491 12.4309 13.4863C11.742 13.9676 10.9039 14.2499 9.99976 14.2499C9.09565 14.2499 8.25747 13.9676 7.56858 13.4863Z" fill="#4360DF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.8645 11.6499C19.9401 11.1946 19.8959 10.7435 19.7602 10.3174C19.5838 9.76409 19.253 9.25286 18.8292 8.82907L11.1708 1.17069C10.747 0.746897 10.2358 0.416048 9.68247 0.239716C9.62921 0.222742 9.57555 0.2072 9.52155 0.193144C9.14354 0.0947561 8.7484 0.0692148 8.35001 0.135358C8.28899 0.145488 8.22816 0.156171 8.16753 0.1674C3.51984 1.02813 0 5.10295 0 9.99988C0 15.5227 4.47715 19.9999 10 19.9999C14.8969 19.9999 18.9717 16.48 19.8325 11.8324C19.8437 11.7717 19.8544 11.7109 19.8645 11.6499ZM1.5 9.99988C1.5 6.08625 4.14622 2.78816 7.74701 1.8013C7.87574 1.76602 8 1.8664 8 1.99988C8 7.52272 12.4772 11.9999 18 11.9999C18.1335 11.9999 18.2339 12.1241 18.1986 12.2529C17.2117 15.8537 13.9136 18.4999 10 18.4999C5.30558 18.4999 1.5 14.6943 1.5 9.99988ZM18 10.4999C18.1011 10.4999 18.1641 10.3935 18.1094 10.3085C18.0185 10.1673 17.9054 10.0266 17.7685 9.88973L10.1101 2.23135C9.97328 2.09448 9.83259 1.98135 9.69142 1.89052C9.60642 1.83582 9.5 1.89879 9.5 1.99988C9.5 6.6943 13.3056 10.4999 18 10.4999Z" fill="#4360DF"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,4 @@
|
|||
<svg width="56" height="56" viewBox="0 0 56 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="56" height="56" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M28 49.875C38.4868 49.875 47.25 42.4958 49.3805 32.6466C49.7619 30.8835 48.0357 29.5236 46.2386 29.6801C45.7068 29.7264 45.1686 29.75 44.625 29.75C34.4768 29.75 26.25 21.5232 26.25 11.375C26.25 10.8314 26.2736 10.2932 26.3199 9.76137C26.4764 7.96426 25.1165 6.23814 23.3534 6.61951C13.5042 8.74997 6.125 17.5132 6.125 28C6.125 40.0812 15.9188 49.875 28 49.875ZM44.625 28C46.0743 28 47.4794 27.8147 48.8183 27.4669C49.2523 27.3541 49.4609 26.873 49.2278 26.49C48.7244 25.663 47.973 24.6784 47.0151 23.5608C45.0993 21.3257 42.5276 18.7525 39.8876 16.1124C37.2475 13.4724 34.6743 10.9007 32.4392 8.98495C31.3216 8.02699 30.337 7.27556 29.51 6.77219C29.127 6.53905 28.6459 6.74772 28.5331 7.1817C28.1853 8.52059 28 9.92566 28 11.375C28 20.5567 35.4433 28 44.625 28ZM28 51.625C41.0477 51.625 51.625 41.0477 51.625 28C51.625 25.375 46.375 20.125 41.125 14.875C35.875 9.625 30.625 4.375 28 4.375C14.9523 4.375 4.375 14.9523 4.375 28C4.375 41.0477 14.9523 51.625 28 51.625ZM19.8578 41.7544C21.9375 39.7461 24.8144 38.5 28 38.5C31.1856 38.5 34.0625 39.7461 36.1422 41.7544C36.4898 42.0901 37.0437 42.0804 37.3794 41.7328C37.7151 41.3852 37.7054 40.8313 37.3578 40.4956C34.9588 38.1789 31.6486 36.75 28 36.75C24.3514 36.75 21.0412 38.1789 18.6422 40.4956C18.2946 40.8313 18.2849 41.3852 18.6206 41.7328C18.9563 42.0804 19.5102 42.0901 19.8578 41.7544Z" fill="#939BA1"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -72,8 +72,11 @@ DISTFILES += \
|
|||
Theme.qml \
|
||||
app/AppLayouts/Browser/BrowserLayout.qml \
|
||||
app/AppLayouts/Chat/ChatColumn.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/MessagesData.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/samples/MessagesData.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/samples/StickerData.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/samples/StickerPackData.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/ChatInput.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/ChatButtons.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/ChatMessages.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/EmptyChat.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/Message.qml \
|
||||
|
@ -81,7 +84,6 @@ DISTFILES += \
|
|||
app/AppLayouts/Chat/ChatColumn/qmldir \
|
||||
app/AppLayouts/Chat/ChatLayout.qml \
|
||||
app/AppLayouts/Chat/ContactsColumn.qml \
|
||||
app/AppLayouts/Chat/ContactsColumn/AddChat.qml \
|
||||
app/AppLayouts/Chat/ContactsColumn/Channel.qml \
|
||||
app/AppLayouts/Chat/ContactsColumn/ChannelList.qml \
|
||||
app/AppLayouts/Chat/ContactsColumn/EmptyView.qml \
|
||||
|
@ -91,6 +93,7 @@ DISTFILES += \
|
|||
app/AppLayouts/Chat/components/PrivateChatPopup.qml \
|
||||
app/AppLayouts/Chat/components/RenameGroupPopup.qml \
|
||||
app/AppLayouts/Chat/components/SuggestedChannel.qml \
|
||||
app/AppLayouts/Chat/components/StickersPopup.qml \
|
||||
app/AppLayouts/Chat/components/qmldir \
|
||||
app/AppLayouts/Chat/qmldir \
|
||||
app/AppLayouts/Node/NodeLayout.qml \
|
||||
|
@ -151,6 +154,7 @@ DISTFILES += \
|
|||
app/img/compassActive.svg \
|
||||
app/img/group_chat.svg \
|
||||
app/img/hash.svg \
|
||||
app/img/history_icon.svg \
|
||||
app/img/message.svg \
|
||||
app/img/messageActive.svg \
|
||||
app/img/new_chat.svg \
|
||||
|
@ -159,6 +163,9 @@ DISTFILES += \
|
|||
app/img/public_chat.svg \
|
||||
app/img/search.svg \
|
||||
app/img/wallet.svg \
|
||||
app/img/stickers_icon.svg \
|
||||
app/img/stickers_icon_open.svg \
|
||||
app/img/stickers_sad_icon.svg \
|
||||
app/img/walletActive.svg \
|
||||
app/qmldir \
|
||||
imports/Utils.qml \
|
||||
|
@ -196,10 +203,12 @@ DISTFILES += \
|
|||
onboarding/img/wallet@2x.jpg \
|
||||
onboarding/img/wallet@3x.jpg \
|
||||
onboarding/qmldir \
|
||||
shared/AddButton.qml \
|
||||
shared/Input.qml \
|
||||
shared/ModalPopup.qml \
|
||||
shared/PopupMenu.qml \
|
||||
shared/RoundImage.qml \
|
||||
shared/Identicon.qml \
|
||||
shared/RoundedImage.qml \
|
||||
shared/SearchBox.qml \
|
||||
shared/Select.qml \
|
||||
shared/Separator.qml \
|
||||
|
|
|
@ -25,7 +25,7 @@ Item {
|
|||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
RoundImage {
|
||||
Identicon {
|
||||
id: userImage
|
||||
width: 40
|
||||
height: 40
|
||||
|
|
|
@ -22,7 +22,7 @@ Rectangle {
|
|||
color: selected || isHovered ? Theme.grey : Theme.transparent
|
||||
radius: Theme.radius
|
||||
|
||||
RoundImage {
|
||||
Identicon {
|
||||
id: accountImage
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.padding
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts 1.3
|
||||
import Qt.labs.platform 1.1
|
||||
import "../imports"
|
||||
|
||||
Rectangle {
|
||||
signal clicked
|
||||
property int iconWidth: 14
|
||||
property int iconHeight: 14
|
||||
property alias icon: imgIcon
|
||||
|
||||
id: btnAddContainer
|
||||
width: 36
|
||||
height: 36
|
||||
color: Theme.blue
|
||||
radius: width / 2
|
||||
|
||||
|
||||
Image {
|
||||
id: imgIcon
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "../app/img/plusSign.svg"
|
||||
width: iconWidth
|
||||
height: iconHeight
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
state: "default"
|
||||
rotation: 0
|
||||
states: [
|
||||
State {
|
||||
name: "default"
|
||||
PropertyChanges {
|
||||
target: imgIcon
|
||||
rotation: 0
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "rotated"
|
||||
PropertyChanges {
|
||||
target: imgIcon
|
||||
rotation: 45
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
from: "default"
|
||||
to: "rotated"
|
||||
RotationAnimation {
|
||||
duration: 150
|
||||
direction: RotationAnimation.Clockwise
|
||||
easing.type: Easing.InCubic
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: "rotated"
|
||||
to: "default"
|
||||
RotationAnimation {
|
||||
duration: 150
|
||||
direction: RotationAnimation.Counterclockwise
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
imgIcon.state = "rotated"
|
||||
btnAddContainer.clicked()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,14 +2,16 @@ import QtQuick 2.13
|
|||
import "../imports"
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
property int size: 36
|
||||
property color bg: Theme.blue
|
||||
property url imgPath: ""
|
||||
signal clicked
|
||||
|
||||
width: size
|
||||
height: size
|
||||
color: bg
|
||||
radius: 50
|
||||
radius: size / 2
|
||||
|
||||
Image {
|
||||
id: roundedIconImage
|
||||
|
@ -20,6 +22,16 @@ Rectangle {
|
|||
fillMode: Image.PreserveAspectFit
|
||||
source: imgPath
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*##^##
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
import QtQuick 2.12
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
Rectangle {
|
||||
id: root;
|
||||
signal clicked
|
||||
property alias source: imgStickerPackThumb.source
|
||||
|
||||
radius: width / 2
|
||||
|
||||
width: 24
|
||||
height: 24
|
||||
|
||||
// apply rounded corners mask
|
||||
layer.enabled: true
|
||||
layer.effect: OpacityMask {
|
||||
maskSource: Rectangle {
|
||||
x: root.x; y: root.y
|
||||
width: root.width
|
||||
height: root.height
|
||||
radius: root.radius
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: imgStickerPackThumb
|
||||
opacity: 1
|
||||
smooth: false
|
||||
anchors.fill: parent
|
||||
source: "https://ipfs.infura.io/ipfs/" + thumbnail
|
||||
|
||||
MouseArea {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
onClicked: root.clicked()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,4 +12,5 @@ StyledTextArea 1.0 StyledTextArea.qml
|
|||
StyledText 1.0 StyledText.qml
|
||||
StyledTextField 1.0 StyledTextField.qml
|
||||
StyledTextEdit 1.0 StyledTextEdit.qml
|
||||
RoundImage 1.0 RoundImage.qml
|
||||
Identicon 1.0 Identicon.qml
|
||||
RoundedImage 1.0 RoundedImage.qml
|
||||
|
|
Loading…
Reference in New Issue