diff --git a/storybook/figma.json b/storybook/figma.json
index 9003ae8cd5..78a4c6134c 100644
--- a/storybook/figma.json
+++ b/storybook/figma.json
@@ -67,7 +67,11 @@
"https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=682%3A17655",
"https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=682%3A17087",
"https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=4%3A23525",
- "https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=4%3A23932"
+ "https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=4%3A23932",
+ "https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=4%3A23932&t=h8DUW6Eysawqe5u0-0",
+ "https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=724%3A15511&t=h8DUW6Eysawqe5u0-0",
+ "https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=6%3A16845&t=h8DUW6Eysawqe5u0-0",
+ "https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=4%3A25437&t=h8DUW6Eysawqe5u0-0"
],
"StatusCommunityCard": [
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=8159%3A416159",
diff --git a/storybook/pages/ProfileDialogViewPage.qml b/storybook/pages/ProfileDialogViewPage.qml
index dee299078a..64169a9c46 100644
--- a/storybook/pages/ProfileDialogViewPage.qml
+++ b/storybook/pages/ProfileDialogViewPage.qml
@@ -2,13 +2,15 @@ import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
-import Storybook 1.0
-
import utils 1.0
import shared.views 1.0
import mainui 1.0
import StatusQ 0.1
+import StatusQ.Core.Utils 0.1 as CoreUtils
+
+import Storybook 1.0
+import Models 1.0
SplitView {
id: root
@@ -55,7 +57,7 @@ SplitView {
alias: "Mock Alias Triplet",
lastUpdated: Date.now(),
lastUpdatedLocally: Date.now(),
- localNickname: "MockNickname",
+ localNickname: localNickname.text,
thumbnailImage: "",
largeImage: userImage.checked ? Style.png("status-logo") : "",
isContact: isContact.checked,
@@ -74,8 +76,8 @@ SplitView {
text: "__twitter",
url: "https://twitter.com/ethstatus",
icon: "twitter"
- },
- {
+ },
+ {
text: "__github",
url: "https://github.com/status-im",
icon: "github"
@@ -122,6 +124,8 @@ SplitView {
publicKey: switchOwnProfile.checked ? "0xdeadbeef" : "0xrandomguy"
+ onCloseRequested: logs.logEvent("closeRequested()")
+
profileStore: QtObject {
readonly property string pubkey: "0xdeadbeef"
readonly property string ensName: name.text
@@ -169,6 +173,209 @@ SplitView {
logs.logEvent("contactsStore::verifiedUntrustworthy", ["publicKey"], arguments)
}
}
+
+ communitiesModel: ListModel {
+ ListElement {
+ name: "Not the cool gang"
+ amISectionAdmin: false
+ description: "Nothing to write home about"
+ color: "indigo"
+ image: ""
+ joined: true
+ members: [
+ ListElement { displayName: "Joe" }
+ ]
+ }
+ ListElement {
+ name: "Awesome bunch"
+ amISectionAdmin: true
+ description: "Where the cool guys hang out & Nothing to write home about"
+ color: "green"
+ image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
+ nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
+ joined: true
+ members: [
+ ListElement { displayName: "Alex" },
+ ListElement { displayName: "AlexJb" },
+ ListElement { displayName: "Michal" },
+ ListElement { displayName: "Noelia" },
+ ListElement { displayName: "Lukáš" }
+ ]
+ }
+ ListElement {
+ name: "Invisible community (should not display!)"
+ amISectionAdmin: false
+ description: "Get outta here"
+ color: "red"
+ image: ""
+ joined: false
+ members: []
+ }
+ }
+
+ walletStore: QtObject {
+ function switchAccountByAddress(address) {
+ logs.logEvent("walletStore::switchAccountByAddress", ["address"], arguments)
+ }
+
+ function selectCollectible(slug, id) {
+ logs.logEvent("walletStore::selectCollectible", ["slug", "id"], arguments)
+ }
+
+ readonly property var accounts: ListModel {
+ ListElement {
+ name: "My Status Account"
+ address: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7420"
+ color: "aliceblue"
+ emoji: "🇨🇿"
+ walletType: ""
+ }
+ ListElement {
+ name: "testing (no emoji, colored, saved, seed)"
+ address: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7000"
+ color: "olive"
+ walletType: "seed"
+ }
+ ListElement {
+ name: "My Bro's Account"
+ address: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7421"
+ color: "ghostwhite"
+ emoji: "🇸🇰"
+ walletType: "watch"
+ }
+ ListElement {
+ name: "Keycard"
+ address: "0xdeadbeef"
+ color: "red"
+ emoji: ""
+ walletType: "key"
+ }
+ }
+
+ function getNameForSavedWalletAddress(address) {
+ return CoreUtils.ModelUtils.getByKey(savedAddresses, "address", address, "name") ?? ""
+ }
+
+ function createOrUpdateSavedAddress(name, address, favourite) {
+ logs.logEvent("walletStore::createOrUpdateSavedAddress", ["name", "address", "favourite"], arguments)
+ savedAddresses.append({name, address, favourite, ens: false})
+ return "" // no error
+ }
+
+ readonly property var savedAddresses: ListModel {
+ ListElement {
+ name: "My Status Saved Account"
+ address: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7000"
+ favourite: true
+ ens: false
+ }
+ }
+
+ readonly property var currentAccount: QtObject {
+ readonly property var assets: ListModel {
+ readonly property var data: [
+ {
+ symbol: "MANA",
+ enabledNetworkBalance: {
+ amount: 301,
+ symbol: "MANA"
+ },
+ changePct24hour: -2.1,
+ visibleForNetworkWithPositiveBalance: true
+ },
+ {
+ symbol: "AAVE",
+ enabledNetworkBalance: {
+ amount: 23.3,
+ symbol: "AAVE"
+ },
+ changePct24hour: 4.56,
+ visibleForNetworkWithPositiveBalance: true
+ },
+ {
+ symbol: "POLY",
+ enabledNetworkBalance: {
+ amount: 3590,
+ symbol: "POLY"
+ },
+ changePct24hour: -11.6789,
+ visibleForNetworkWithPositiveBalance: true
+ },
+ {
+ symbol: "CDT",
+ enabledNetworkBalance: {
+ amount: 1000,
+ symbol: "CDT"
+ },
+ changePct24hour: 0,
+ visibleForNetworkWithPositiveBalance: true
+ },
+ {
+ symbol: "MKR",
+ enabledNetworkBalance: {
+ amount: 1.3,
+ symbol: "MKR"
+ },
+ //changePct24hour: undefined // NB 'undefined' on purpose
+ visibleForNetworkWithPositiveBalance: true
+ },
+ {
+ symbol: "InvisibleHere",
+ enabledNetworkBalance: {},
+ changePct24hour: 0,
+ visibleForNetworkWithPositiveBalance: false
+ }
+ ]
+ Component.onCompleted: append(data)
+ }
+ }
+
+ readonly property var flatCollectibles: ListModel {
+ readonly property var data: [
+ {
+ //id: 123,
+ name: "Crypto Kitties",
+ description: "Super Crypto Kitty",
+ backgroundColor: "",
+ imageUrl: ModelsData.collectibles.cryptoKitties,
+ permalink: ""
+ },
+ {
+ id: 34545656768,
+ name: "Kitty 1",
+ description: "",
+ backgroundColor: "green",
+ imageUrl: ModelsData.collectibles.kitty1Big,
+ permalink: ""
+ },
+ {
+ id: 123456,
+ name: "Kitty 2",
+ description: "",
+ backgroundColor: "",
+ imageUrl: ModelsData.collectibles.kitty2Big,
+ permalink: ""
+ },
+ {
+ id: 12345645459537432,
+ name: "",
+ description: "Kitty 3 description",
+ backgroundColor: "oink",
+ imageUrl: ModelsData.collectibles.kitty3Big,
+ permalink: ""
+ },
+ {
+ id: 691,
+ name: "KILLABEAR #691",
+ description: "Please note that weapons are not yet reflected in the rarity stats.",
+ backgroundColor: "#807c56",
+ imageUrl: "https://assets.killabears.com/content/killabears/img/691-e81f892696a8ae700e0dbc62eb072060679a2046d1ef5eb2671bdb1fad1f68e3.png",
+ permalink: "https://opensea.io/assets/ethereum/0xc99c679c50033bbc5321eb88752e89a93e9e83c5/691"
+ }
+ ]
+ Component.onCompleted: append(data)
+ }
+ }
}
}
}
@@ -192,6 +399,12 @@ SplitView {
}
RowLayout {
Layout.fillWidth: true
+ Label { text: "localNickname:" }
+ TextField {
+ id: localNickname
+ text: "MockNickname"
+ placeholderText: "Local Nickname"
+ }
Label { text: "displayName:" }
TextField {
id: displayName
@@ -237,7 +450,7 @@ SplitView {
TextField {
id: name
enabled: ensVerified.checked
- text: ensVerified.checked ? "mock-ens-name" : ""
+ text: ensVerified.checked ? "mock-ens-name.eth" : ""
placeholderText: "ENS name"
}
}
@@ -290,6 +503,7 @@ SplitView {
TextField {
Layout.fillWidth: true
id: bio
+ selectByMouse: true
text: "Hi, I am Alex. I'm an indie developer who mainly works on web products.
I worked for several different companies and created a couple of my own products from scratch. Currently building Telescope and Prepacked.
diff --git a/ui/StatusQ/src/StatusQ/Components/StatusToastMessage.qml b/ui/StatusQ/src/StatusQ/Components/StatusToastMessage.qml
index ad7815edbf..904fc0d747 100644
--- a/ui/StatusQ/src/StatusQ/Components/StatusToastMessage.qml
+++ b/ui/StatusQ/src/StatusQ/Components/StatusToastMessage.qml
@@ -140,7 +140,7 @@ Control {
This signal is emitted when the ToastMessage contains a url and this url
is clicked by the user.
*/
- signal linkActivated(var link)
+ signal linkActivated(string link)
QtObject {
id: d
diff --git a/ui/StatusQ/src/StatusQ/Controls/StatusAccountSelector.qml b/ui/StatusQ/src/StatusQ/Controls/StatusAccountSelector.qml
index ed012d2a5a..86cb431510 100644
--- a/ui/StatusQ/src/StatusQ/Controls/StatusAccountSelector.qml
+++ b/ui/StatusQ/src/StatusQ/Controls/StatusAccountSelector.qml
@@ -70,7 +70,7 @@ Item {
textSelectedAddress.text = selectedAccount.address
}
if (selectedAccount.currencyBalance) {
- textSelectedAddressFiatBalance.text = selectedAccount.currencyBalance + " " + currency.toUpperCase()
+ textSelectedAddressFiatBalance.text = LocaleUtils.currencyAmountToLocaleString(selectedAccount.currencyBalance)
}
if (selectedAccount.assets && showBalanceForAssetSymbol) {
assetFound = Utils.findAssetByChainAndSymbol(root.chainId, selectedAccount.assets, showBalanceForAssetSymbol)
@@ -239,7 +239,7 @@ Item {
id: txtFiatBalance
Layout.rightMargin: 4
font.pixelSize: 15
- text: currencyBalance
+ text: LocaleUtils.currencyAmountToLocaleString(currencyBalance, {onlyAmount: true})
color: Theme.palette.directColor1
}
StatusBaseText {
diff --git a/ui/StatusQ/src/StatusQ/Controls/StatusToolTip.qml b/ui/StatusQ/src/StatusQ/Controls/StatusToolTip.qml
index a2cbbd677a..3761f979ca 100644
--- a/ui/StatusQ/src/StatusQ/Controls/StatusToolTip.qml
+++ b/ui/StatusQ/src/StatusQ/Controls/StatusToolTip.qml
@@ -18,11 +18,8 @@ ToolTip {
property int offset: 0
property alias arrow: arrow
- implicitWidth: Math.min(maxWidth, contentItem.implicitWidth + 16)
- leftPadding: 8
- rightPadding: 8
- topPadding: 8
- bottomPadding: 8
+ implicitWidth: Math.min(maxWidth, implicitContentWidth + 16)
+ padding: 8
delay: 200
background: Item {
id: statusToolTipBackground
@@ -73,6 +70,6 @@ ToolTip {
font.weight: Font.Medium
horizontalAlignment: Text.AlignHCenter
bottomPadding: 8
+ textFormat: Text.RichText
}
}
-
diff --git a/ui/app/AppLayouts/Chat/panels/communities/CommunityPermissionsSettingsPanel.qml b/ui/app/AppLayouts/Chat/panels/communities/CommunityPermissionsSettingsPanel.qml
index 003876c3bf..c4d4466218 100644
--- a/ui/app/AppLayouts/Chat/panels/communities/CommunityPermissionsSettingsPanel.qml
+++ b/ui/app/AppLayouts/Chat/panels/communities/CommunityPermissionsSettingsPanel.qml
@@ -71,8 +71,7 @@ SettingsPageLayout {
}
}
- readonly property string initialState: root.permissionsModel.count > 0
- ? d.permissionsViewState : d.welcomeViewState
+ readonly property string initialState: d.permissionsExist ? d.permissionsViewState : d.welcomeViewState
function initializeData() {
holdingsToEditModel = emptyModel
diff --git a/ui/app/AppLayouts/CommunitiesPortal/stores/CommunitiesStore.qml b/ui/app/AppLayouts/CommunitiesPortal/stores/CommunitiesStore.qml
index 68210c62b8..3e86f7a5b8 100644
--- a/ui/app/AppLayouts/CommunitiesPortal/stores/CommunitiesStore.qml
+++ b/ui/app/AppLayouts/CommunitiesPortal/stores/CommunitiesStore.qml
@@ -101,7 +101,7 @@ QtObject {
}
function setActiveCommunity(communityId) {
- mainModule.setActiveSectionById(communityId);
+ root.mainModuleInst.setActiveSectionById(communityId);
}
function navigateToCommunity(communityId) {
diff --git a/ui/app/AppLayouts/Profile/ProfileLayout.qml b/ui/app/AppLayouts/Profile/ProfileLayout.qml
index 577f0a1b4b..3a54895fbd 100644
--- a/ui/app/AppLayouts/Profile/ProfileLayout.qml
+++ b/ui/app/AppLayouts/Profile/ProfileLayout.qml
@@ -107,6 +107,7 @@ StatusSectionLayout {
profileStore: root.store.profileStore
privacyStore: root.store.privacyStore
contactsStore: root.store.contactsStore
+ communitiesModel: root.store.communitiesList
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.profile)
contentWidth: d.contentWidth
}
diff --git a/ui/app/AppLayouts/Profile/controls/qmldir b/ui/app/AppLayouts/Profile/controls/qmldir
new file mode 100644
index 0000000000..7ba3436b2b
--- /dev/null
+++ b/ui/app/AppLayouts/Profile/controls/qmldir
@@ -0,0 +1,2 @@
+CommunityDelegate 1.0 CommunityDelegate.qml
+WalletAccountDelegate 1.0 WalletAccountDelegate.qml
diff --git a/ui/app/AppLayouts/Profile/views/MyProfileView.qml b/ui/app/AppLayouts/Profile/views/MyProfileView.qml
index 0c0ddc5c2f..13868f2e50 100644
--- a/ui/app/AppLayouts/Profile/views/MyProfileView.qml
+++ b/ui/app/AppLayouts/Profile/views/MyProfileView.qml
@@ -25,6 +25,7 @@ SettingsContentBase {
property ProfileStore profileStore
property PrivacyStore privacyStore
property ContactsStore contactsStore
+ property var communitiesModel
titleRowComponentLoader.sourceComponent: StatusButton {
objectName: "profileSettingsChangePasswordButton"
@@ -72,6 +73,7 @@ SettingsContentBase {
profileStore: root.profileStore
privacyStore: root.privacyStore
walletStore: root.walletStore
+ communitiesModel: root.communitiesModel
onVisibleChanged: if (visible) stackLayout.Layout.preferredHeight = settingsView.implicitHeight
Component.onCompleted: stackLayout.Layout.preferredHeight = Qt.binding(() => settingsView.implicitHeight)
@@ -82,6 +84,7 @@ SettingsContentBase {
profileStore: root.profileStore
contactsStore: root.contactsStore
+ communitiesModel: root.communitiesModel
dirtyValues: settingsView.dirtyValues
dirty: settingsView.dirty
diff --git a/ui/app/AppLayouts/Profile/views/profile/MyProfilePreview.qml b/ui/app/AppLayouts/Profile/views/profile/MyProfilePreview.qml
index 8c851f7358..0d1f8d8714 100644
--- a/ui/app/AppLayouts/Profile/views/profile/MyProfilePreview.qml
+++ b/ui/app/AppLayouts/Profile/views/profile/MyProfilePreview.qml
@@ -8,6 +8,7 @@ import StatusQ.Core.Theme 0.1
Item {
property alias profileStore: profilePreview.profileStore
property alias contactsStore: profilePreview.contactsStore
+ property alias communitiesModel: profilePreview.communitiesModel
property alias dirtyValues: profilePreview.dirtyValues
property alias dirty: profilePreview.dirty
diff --git a/ui/app/AppLayouts/Profile/views/profile/MyProfileSettingsView.qml b/ui/app/AppLayouts/Profile/views/profile/MyProfileSettingsView.qml
index 1006c4d6b8..8852f85c45 100644
--- a/ui/app/AppLayouts/Profile/views/profile/MyProfileSettingsView.qml
+++ b/ui/app/AppLayouts/Profile/views/profile/MyProfileSettingsView.qml
@@ -26,6 +26,7 @@ ColumnLayout {
property PrivacyStore privacyStore
property ProfileStore profileStore
property WalletStore walletStore
+ property var communitiesModel
property QtObject dirtyValues: QtObject {
property string displayName: descriptionPanel.displayName.text
@@ -158,7 +159,7 @@ ColumnLayout {
StatusListItem {
Layout.fillWidth: true
- visible: Qt.platform.os == "osx"
+ visible: Qt.platform.os === Constants.mac
title: qsTr("Biometric login and transaction authentication")
asset.name: "touch-id"
components: [ StatusSwitch {
@@ -218,13 +219,13 @@ ColumnLayout {
Repeater {
id: communitiesRepeater
- model: communitiesModule.model
+ model: root.communitiesModel
CommunityDelegate {
width: parent.width
visible: joined
community: model
- enabled: false
+ sensor.enabled: false
}
}
}
@@ -246,7 +247,7 @@ ColumnLayout {
width: parent.width
account: model
showShevronIcon: false
- enabled: false
+ sensor.enabled: false
}
}
}
diff --git a/ui/app/AppLayouts/Wallet/stores/RootStore.qml b/ui/app/AppLayouts/Wallet/stores/RootStore.qml
index 2b2cc77c0e..90f85ba7eb 100644
--- a/ui/app/AppLayouts/Wallet/stores/RootStore.qml
+++ b/ui/app/AppLayouts/Wallet/stores/RootStore.qml
@@ -141,6 +141,10 @@ QtObject {
walletSection.switchAccount(newIndex)
}
+ function switchAccountByAddress(address) {
+ walletSection.switchAccountByAddress(address)
+ }
+
function generateNewAccount(password, accountName, color, emoji, path, derivedFrom) {
return walletSectionAccounts.generateNewAccount(password, accountName, color, emoji, path, derivedFrom)
}
@@ -198,6 +202,10 @@ QtObject {
walletSectionCurrentCollectible.update(slug, id)
}
+ function getNameForSavedWalletAddress(address) {
+ return walletSectionSavedAddresses.getNameByAddress(address)
+ }
+
function createOrUpdateSavedAddress(name, address, favourite, chainShortNames, ens) {
return walletSectionSavedAddresses.createOrUpdateSavedAddress(name, address, favourite, chainShortNames, ens)
}
diff --git a/ui/app/AppLayouts/Wallet/views/LeftTabView.qml b/ui/app/AppLayouts/Wallet/views/LeftTabView.qml
index 3ead4045a0..f569780729 100644
--- a/ui/app/AppLayouts/Wallet/views/LeftTabView.qml
+++ b/ui/app/AppLayouts/Wallet/views/LeftTabView.qml
@@ -169,9 +169,9 @@ Rectangle {
components: [
StatusIcon {
icon: {
- if (model.walletType == "watch")
+ if (model.walletType === Constants.watchWalletType)
return "show"
- else if (model.walletType == "key")
+ if (model.walletType === Constants.keyWalletType)
return "keycard"
return ""
diff --git a/ui/app/mainui/AppMain.qml b/ui/app/mainui/AppMain.qml
index a4527cd7bd..a6ebe48830 100644
--- a/ui/app/mainui/AppMain.qml
+++ b/ui/app/mainui/AppMain.qml
@@ -163,6 +163,14 @@ Item {
Global.settingsSubsection = subsection;
}
}
+
+ function onOpenSendModal(address: string) {
+ sendModal.open(address)
+ }
+
+ function onSwitchToCommunity(communityId: string) {
+ communitiesPortalLayoutContainer.communitiesStore.setActiveCommunity(communityId)
+ }
}
function changeAppSectionBySectionId(sectionId) {
@@ -1119,7 +1127,10 @@ Item {
this.open = false
}
onLinkActivated: {
- Qt.openUrlExternally(link);
+ if (link.startsWith("#")) // internal link to section
+ globalConns.onAppSectionBySectionTypeChanged(link.substring(1))
+ else
+ Global.openLink(link)
}
onClose: {
diff --git a/ui/app/mainui/Popups.qml b/ui/app/mainui/Popups.qml
index f250eb8d05..81cff2e5e5 100644
--- a/ui/app/mainui/Popups.qml
+++ b/ui/app/mainui/Popups.qml
@@ -287,6 +287,7 @@ QtObject {
id: profilePopup
profileStore: rootStore.profileSectionStore.profileStore
contactsStore: rootStore.profileSectionStore.contactsStore
+ communitiesModel: rootStore.profileSectionStore.communitiesList
onClosed: {
if (profilePopup.parentPopup) {
diff --git a/ui/imports/shared/panels/StatusAssetSelector.qml b/ui/imports/shared/panels/StatusAssetSelector.qml
index d18b2c6736..f08bcac269 100644
--- a/ui/imports/shared/panels/StatusAssetSelector.qml
+++ b/ui/imports/shared/panels/StatusAssetSelector.qml
@@ -14,8 +14,6 @@ import StatusQ.Core.Backpressure 1.0
import shared.controls 1.0
import utils 1.0
-import utils 1.0
-
import "../controls"
Item {
diff --git a/ui/imports/shared/popups/ProfileDialog.qml b/ui/imports/shared/popups/ProfileDialog.qml
index 044a10cd95..9db8b7783e 100644
--- a/ui/imports/shared/popups/ProfileDialog.qml
+++ b/ui/imports/shared/popups/ProfileDialog.qml
@@ -13,6 +13,7 @@ StatusDialog {
property var profileStore
property var contactsStore
+ property var communitiesModel
width: 640
padding: 0
@@ -24,6 +25,7 @@ StatusDialog {
publicKey: root.publicKey
profileStore: root.profileStore
contactsStore: root.contactsStore
+ communitiesModel: root.communitiesModel
onCloseRequested: root.close()
}
}
diff --git a/ui/imports/shared/views/AssetsView.qml b/ui/imports/shared/views/AssetsView.qml
index 15f626bc5c..f2a00df573 100644
--- a/ui/imports/shared/views/AssetsView.qml
+++ b/ui/imports/shared/views/AssetsView.qml
@@ -32,9 +32,8 @@ Item {
id: assetListView
objectName: "assetViewStatusListView"
anchors.fill: parent
- model: RootStore.tokensLoading ? 25 : filteredModel
+ model: RootStore.tokensLoading ? Constants.dummyModelItems : filteredModel
delegate: RootStore.tokensLoading ? loadingTokenDelegate : tokenDelegate
- ScrollBar.vertical: StatusScrollBar {}
}
SortFilterProxyModel {
diff --git a/ui/imports/shared/views/ProfileDialogView.qml b/ui/imports/shared/views/ProfileDialogView.qml
index e7404d8bef..81c78b1648 100644
--- a/ui/imports/shared/views/ProfileDialogView.qml
+++ b/ui/imports/shared/views/ProfileDialogView.qml
@@ -1,7 +1,7 @@
-import QtQuick 2.14
-import QtQuick.Controls 2.14
-import QtQuick.Layouts 1.14
-import QtGraphicalEffects 1.14
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+import QtGraphicalEffects 1.15
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
@@ -9,6 +9,7 @@ import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Popups 0.1
import StatusQ.Popups.Dialog 0.1
+import StatusQ.Core.Utils 0.1 as StatusQUtils
import utils 1.0
import shared.controls 1.0
@@ -16,16 +17,23 @@ import shared.panels 1.0
import shared.popups 1.0
import shared.controls.chat 1.0
import shared.controls.chat.menuItems 1.0
+import shared.views.profile 1.0
+
+import SortFilterProxyModel 0.2
+
+import AppLayouts.Wallet.stores 1.0 as WalletNS
Pane {
id: root
- property bool readOnly
+ property bool readOnly // inside settings/profile/preview
property string publicKey: contactsStore.myPublicKey
property var profileStore
property var contactsStore
+ property var walletStore: WalletNS.RootStore
+ property var communitiesModel
property QtObject dirtyValues: null
property bool dirty: false
@@ -547,8 +555,10 @@ Pane {
StatusScrollView {
id: scrollView
+ implicitWidth: contentWidth + leftPadding + rightPadding
+ implicitHeight: contentHeight + topPadding + bottomPadding
Layout.fillWidth: true
- Layout.preferredHeight: contentHeight + topPadding + bottomPadding
+ Layout.fillHeight: true
Layout.leftMargin: -column.anchors.leftMargin
Layout.rightMargin: -column.anchors.rightMargin
Layout.topMargin: -column.spacing
@@ -562,8 +572,7 @@ Pane {
Layout.fillWidth: true
Layout.leftMargin: column.anchors.leftMargin + Style.current.halfPadding
Layout.rightMargin: column.anchors.rightMargin + Style.current.halfPadding
- bio: root.dirty ? root.dirtyValues.bio
- : d.contactDetails.bio
+ bio: root.dirty ? root.dirtyValues.bio : d.contactDetails.bio
userSocialLinksJson: root.dirty ? root.profileStore.temporarySocialLinksJson
: d.contactDetails.socialLinks
}
@@ -666,26 +675,17 @@ Pane {
height: width
mipmap: true
smooth: false
- source: root.profileStore.getQrCodeSource(root.profileStore.pubkey)
+ source: root.profileStore.getQrCodeSource(Utils.getCompressedPk(root.profileStore.pubkey))
}
}
}
StatusTabBar {
+ id: showcaseTabBar
Layout.fillWidth: true
Layout.leftMargin: column.anchors.leftMargin
Layout.rightMargin: column.anchors.rightMargin
bottomPadding: -4
-
- StatusTabButton {
- leftPadding: 0
- width: implicitWidth
- text: qsTr("Assets")
- }
- StatusTabButton {
- width: implicitWidth
- text: qsTr("Collectibles")
- }
StatusTabButton {
width: implicitWidth
text: qsTr("Communities")
@@ -694,27 +694,32 @@ Pane {
width: implicitWidth
text: qsTr("Accounts")
}
+ StatusTabButton {
+ width: implicitWidth
+ text: qsTr("Collectibles")
+ }
+ StatusTabButton {
+ leftPadding: 0
+ width: implicitWidth
+ text: qsTr("Assets")
+ }
}
- StatusDialogBackground {
+ // Profile Showcase
+ ProfileShowcaseView {
Layout.fillWidth: true
Layout.topMargin: -column.spacing
Layout.preferredHeight: 300
- color: Theme.palette.baseColor4
- Rectangle {
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.top: parent.top
- height: parent.radius
- color: parent.color
- }
+ currentTabIndex: showcaseTabBar.currentIndex
+ isCurrentUser: d.isCurrentUser
+ mainDisplayName: d.mainDisplayName
+ readOnly: root.readOnly
+ profileStore: root.profileStore
+ walletStore: root.walletStore
+ communitiesModel: root.communitiesModel
- StatusBaseText {
- anchors.centerIn: parent
- color: Theme.palette.baseColor1
- text: qsTr("More content to appear here soon...")
- }
+ onCloseRequested: root.closeRequested()
}
}
}
diff --git a/ui/imports/shared/views/chat/LinksMessageView.qml b/ui/imports/shared/views/chat/LinksMessageView.qml
index fc14096e79..323a4c4021 100644
--- a/ui/imports/shared/views/chat/LinksMessageView.qml
+++ b/ui/imports/shared/views/chat/LinksMessageView.qml
@@ -159,6 +159,7 @@ Column {
anchors.centerIn: parent
text: "GIF"
font.pixelSize: 13
+ color: "white"
}
}
}
diff --git a/ui/imports/shared/views/profile/ProfileShowcaseView.qml b/ui/imports/shared/views/profile/ProfileShowcaseView.qml
new file mode 100644
index 0000000000..34d4599c0e
--- /dev/null
+++ b/ui/imports/shared/views/profile/ProfileShowcaseView.qml
@@ -0,0 +1,395 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+
+import StatusQ.Core 0.1
+import StatusQ.Core.Theme 0.1
+import StatusQ.Controls 0.1
+import StatusQ.Components 0.1
+import StatusQ.Popups.Dialog 0.1
+import StatusQ.Core.Utils 0.1 as StatusQUtils
+
+import utils 1.0
+import shared.controls 1.0 // Timer
+
+import SortFilterProxyModel 0.2
+
+Control {
+ id: root
+
+ property alias currentTabIndex: stackLayout.currentIndex
+ property bool isCurrentUser
+ property string mainDisplayName
+ property bool readOnly
+ property var profileStore
+ property var walletStore
+ property var communitiesModel
+
+ signal closeRequested()
+
+ horizontalPadding: readOnly ? 20 : 40 // smaller in settings/preview
+ topPadding: Style.current.bigPadding
+
+ QtObject {
+ id: d
+
+ readonly property string copyLiteral: qsTr("Copy")
+
+ readonly property var timer: Timer {
+ id: timer
+ }
+ }
+
+ background: StatusDialogBackground {
+ color: Theme.palette.baseColor4
+
+ Rectangle {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ height: parent.radius
+ color: parent.color
+ }
+ }
+
+ contentItem: StackLayout {
+ id: stackLayout
+
+ // communities
+ ColumnLayout {
+ StatusBaseText {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.alignment: Qt.AlignCenter
+ visible: communitiesView.count == 0
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ color: Theme.palette.directColor1
+ text: qsTr("%1 hasn't joined any communities yet").arg(root.mainDisplayName)
+ }
+
+ StatusGridView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ id: communitiesView
+ rightMargin: Style.current.halfPadding
+ cellWidth: (width-rightMargin)/2
+ cellHeight: cellWidth/2
+ visible: count
+ model: SortFilterProxyModel {
+ sourceModel: root.isCurrentUser ? root.communitiesModel : null // TODO show other users too
+ filters: ValueFilter {
+ roleName: "joined"
+ value: true
+ }
+ sorters: [
+ RoleSorter {
+ roleName: "amISectionAdmin"
+ sortOrder: Qt.DescendingOrder // admin first
+ },
+ StringSorter {
+ roleName: "name"
+ caseSensitivity: Qt.CaseInsensitive
+ }
+ ]
+ }
+ ScrollBar.vertical: StatusScrollBar { }
+ delegate: StatusListItem { // TODO custom delegate
+ width: GridView.view.cellWidth - Style.current.smallPadding
+ height: GridView.view.cellHeight - Style.current.smallPadding
+ title: model.name
+ statusListItemTitle.font.pixelSize: 17
+ statusListItemTitle.font.bold: true
+ subTitle: model.description
+ tertiaryTitle: qsTr("%n member(s)", "", model.members.count)
+ asset.name: model.image ?? model.name
+ asset.isImage: asset.name.startsWith("data:image/")
+ asset.isLetterIdenticon: !model.image
+ asset.color: model.color
+ asset.width: 40
+ asset.height: 40
+ border.width: 1
+ border.color: Theme.palette.baseColor2
+ components: [
+ StatusIcon {
+ visible: model.amISectionAdmin
+ anchors.verticalCenter: parent.verticalCenter
+ icon: "crown"
+ color: Theme.palette.directColor1
+ }
+ ]
+ onClicked: {
+ if (root.readOnly)
+ return
+ root.closeRequested()
+ Global.switchToCommunity(model.id)
+ }
+ }
+ }
+ }
+
+ // wallets/accounts
+ ColumnLayout {
+ StatusBaseText {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.alignment: Qt.AlignCenter
+ visible: accountsView.count == 0
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ color: Theme.palette.directColor1
+ text: qsTr("%1 doesn't have any wallet accounts yet").arg(root.mainDisplayName)
+ }
+
+ StatusListView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ id: accountsView
+ spacing: Style.current.halfPadding
+ visible: count
+ model: SortFilterProxyModel {
+ sourceModel: root.isCurrentUser ? root.walletStore.accounts : null // TODO show other users too
+ filters: ValueFilter { // everything except keycards
+ roleName: "walletType"
+ value: Constants.keyWalletType
+ inverted: true
+ }
+ }
+ delegate: StatusListItem {
+ id: accountDelegate
+ property bool saved: root.walletStore.getNameForSavedWalletAddress(model.address) !== ""
+ border.width: 1
+ border.color: Theme.palette.baseColor2
+ width: ListView.view.width
+ title: model.name
+ subTitle: StatusQUtils.Utils.elideText(model.address, 6, 4).replace("0x", "0×")
+ asset.color: model.color
+ asset.emoji: model.emoji ?? ""
+ asset.name: asset.emoji || "filled-account"
+ asset.isLetterIdenticon: asset.emoji
+ asset.letterSize: 14
+ asset.bgColor: Theme.palette.primaryColor3
+ asset.isImage: asset.emoji
+ components: [
+ StatusIcon {
+ anchors.verticalCenter: parent.verticalCenter
+ visible: model.walletType === Constants.watchWalletType
+ icon: "show"
+ color: Theme.palette.directColor1
+ },
+ StatusFlatButton {
+ anchors.verticalCenter: parent.verticalCenter
+ size: StatusBaseButton.Size.Small
+ enabled: !accountDelegate.saved
+ text: accountDelegate.saved ? qsTr("Address saved") : qsTr("Save Address")
+ onClicked: {
+ accountDelegate.saved = root.walletStore.createOrUpdateSavedAddress(model.name, model.address, false) === ""
+ Global.displayToastMessage(qsTr("%1 saved to your wallet").arg(accountDelegate.subTitle),
+ qsTr("Go to your wallet"),
+ "wallet",
+ false,
+ Constants.ephemeralNotificationType.normal,
+ `#${Constants.appSection.wallet}` // internal link to wallet section
+ )
+ }
+ },
+ StatusFlatRoundButton {
+ anchors.verticalCenter: parent.verticalCenter
+ type: StatusFlatRoundButton.Type.Secondary
+ icon.name: "send"
+ tooltip.text: qsTr("Send")
+ onClicked: {
+ root.walletStore.switchAccountByAddress(model.address)
+ Global.openSendModal(model.address)
+ }
+ },
+ StatusFlatRoundButton {
+ anchors.verticalCenter: parent.verticalCenter
+ type: StatusFlatRoundButton.Type.Secondary
+ icon.name: "copy"
+ tooltip.text: d.copyLiteral
+ onClicked: {
+ tooltip.text = qsTr("Copied")
+ root.profileStore.copyToClipboard(model.address)
+ d.timer.setTimeout(function() {
+ tooltip.text = d.copyLiteral
+ }, 2000);
+ }
+ }
+ ]
+ onClicked: {
+ if (root.readOnly)
+ return
+ root.walletStore.switchAccountByAddress(model.address)
+ }
+ }
+ }
+ }
+
+ // collectibles/NFTs
+ ColumnLayout {
+ StatusBaseText {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.alignment: Qt.AlignCenter
+ visible: collectiblesView.count == 0
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ color: Theme.palette.directColor1
+ text: qsTr("%1 doesn't have any collectibles/NFTs yet").arg(root.mainDisplayName)
+ }
+
+ StatusGridView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ id: collectiblesView
+ rightMargin: Style.current.halfPadding
+ cellWidth: (width-rightMargin)/4
+ cellHeight: cellWidth
+ visible: count
+ model: root.isCurrentUser ? root.walletStore.flatCollectibles : null // TODO show other users too
+ ScrollBar.vertical: StatusScrollBar { }
+ delegate: StatusRoundedImage {
+ width: GridView.view.cellWidth - Style.current.smallPadding
+ height: GridView.view.cellHeight - Style.current.smallPadding
+ border.width: 1
+ border.color: Theme.palette.directColor7
+ color: !!model.backgroundColor ? model.backgroundColor : "transparent"
+ radius: Style.current.radius
+ showLoadingIndicator: model.isLoading
+ image.fillMode: Image.PreserveAspectCrop
+ image.source: model.imageUrl ?? ""
+
+ RowLayout {
+ anchors.left: parent.left
+ anchors.leftMargin: Style.current.halfPadding
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: Style.current.halfPadding
+ anchors.right: parent.right
+ anchors.rightMargin: Style.current.halfPadding
+
+ Control {
+ Layout.maximumWidth: parent.width
+ horizontalPadding: Style.current.halfPadding
+ verticalPadding: Style.current.halfPadding/2
+ visible: !!model.id
+
+ background: Rectangle {
+ radius: Style.current.halfPadding/2
+ color: Theme.palette.indirectColor2
+ }
+ contentItem: StatusBaseText {
+ font.pixelSize: 13
+ font.weight: Font.Medium
+ maximumLineCount: 1
+ elide: Text.ElideRight
+ text: `#${model.id}`
+ }
+ }
+ }
+
+ StatusToolTip {
+ visible: hhandler.hovered && (!!model.name || !!model.description)
+ text: {
+ const name = model.name
+ const descr = model.description
+ const sep = !!name && !!descr ? "
" : ""
+ return `${name}${sep}${descr}`
+ }
+ }
+
+ HoverHandler {
+ id: hhandler
+ cursorShape: hovered ? Qt.PointingHandCursor : undefined
+ }
+
+ TapHandler {
+ onSingleTapped: {
+ Global.openLink(model.permalink)
+ }
+ }
+ }
+ }
+ }
+
+ // assets/tokens
+ ColumnLayout {
+ StatusBaseText {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.alignment: Qt.AlignCenter
+ visible: assetsView.count == 0
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ color: Theme.palette.directColor1
+ text: qsTr("%1 doesn't have any assets/tokens yet").arg(root.mainDisplayName)
+ }
+
+ StatusGridView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ id: assetsView
+ rightMargin: Style.current.halfPadding
+ cellWidth: (width-rightMargin)/3
+ cellHeight: cellWidth/2.5
+ visible: count
+ model: SortFilterProxyModel {
+ // TODO show assets for all accounts, not just the current one?
+ sourceModel: root.isCurrentUser ? root.walletStore.currentAccount.assets : null // TODO show other users too
+ filters: ValueFilter {
+ roleName: "visibleForNetworkWithPositiveBalance"
+ value: true
+ }
+ sorters: [
+ StringSorter {
+ roleName: "name"
+ },
+ StringSorter {
+ roleName: "symbol"
+ }
+ ]
+ }
+ ScrollBar.vertical: StatusScrollBar { }
+ delegate: StatusListItem {
+ readonly property double changePct24hour: model.changePct24hour ?? 0
+ readonly property string textColor: changePct24hour === 0
+ ? Theme.palette.baseColor1 : changePct24hour < 0
+ ? Theme.palette.dangerColor1 : Theme.palette.successColor1
+ readonly property string arrow: changePct24hour === 0 ? "" : changePct24hour < 0 ? "↓" : "↑"
+
+ width: GridView.view.cellWidth - Style.current.halfPadding
+ height: GridView.view.cellHeight - Style.current.halfPadding
+ title: LocaleUtils.currencyAmountToLocaleString(model.enabledNetworkBalance)
+ statusListItemTitle.font.weight: Font.Medium
+ tertiaryTitle: qsTr("%1% today %2")
+ .arg(LocaleUtils.numberToLocaleString(changePct24hour, changePct24hour === 0 ? 0 : 2)).arg(arrow)
+ statusListItemTertiaryTitle.color: textColor
+ statusListItemTertiaryTitle.font.pixelSize: Theme.asideTextFontSize
+ statusListItemTertiaryTitle.anchors.topMargin: 6
+ leftPadding: Style.current.halfPadding
+ rightPadding: Style.current.halfPadding
+ border.width: 1
+ border.color: Theme.palette.baseColor2
+ components: [
+ Image {
+ width: 40
+ height: 40
+ anchors.verticalCenter: parent.verticalCenter
+ source: Style.png("tokens/" + model.symbol)
+ onStatusChanged: {
+ if (status === Image.Error) {
+ source = Style.png("tokens/DEFAULT-TOKEN")
+ }
+ }
+ }
+ ]
+ onClicked: {
+ if (root.readOnly)
+ return
+ // TODO what to do here?
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/ui/imports/shared/views/profile/qmldir b/ui/imports/shared/views/profile/qmldir
new file mode 100644
index 0000000000..c83591ed97
--- /dev/null
+++ b/ui/imports/shared/views/profile/qmldir
@@ -0,0 +1 @@
+ProfileShowcaseView 1.0 ProfileShowcaseView.qml
diff --git a/ui/imports/utils/Global.qml b/ui/imports/utils/Global.qml
index 1433515f20..3ee15253c2 100644
--- a/ui/imports/utils/Global.qml
+++ b/ui/imports/utils/Global.qml
@@ -47,6 +47,9 @@ QtObject {
signal setNthEnabledSectionActive(int nthSection)
signal appSectionBySectionTypeChanged(int sectionType, int subsection)
+ signal openSendModal(string address)
+ signal switchToCommunity(string communityId)
+
signal playSendMessageSound()
signal playNotificationSound()
signal playErrorSound()