feat: New design flows to integrate Revealing addresses...
... when joining Community functionality Closes #11138
This commit is contained in:
parent
fe94bd0c69
commit
02e40adfca
|
@ -249,7 +249,7 @@ QtObject:
|
|||
let addressesArray = map(parseJson(addressesToShare).getElems(), proc(x:JsonNode):string = x.getStr())
|
||||
self.delegate.requestToJoinCommunityWithAuthentication(ensName, addressesArray, airdropAddress)
|
||||
except Exception as e:
|
||||
echo "Error requesting to join community with authetication and shared addresses: ", e.msg
|
||||
echo "Error requesting to join community with authentication and shared addresses: ", e.msg
|
||||
|
||||
proc joinGroupChatFromInvitation*(self: View, groupName: string, chatId: string, adminPK: string) {.slot.} =
|
||||
self.delegate.joinGroupChatFromInvitation(groupName, chatId, adminPK)
|
||||
|
@ -421,4 +421,4 @@ QtObject:
|
|||
read = getAllTokenRequirementsMet
|
||||
notify = allTokenRequirementsMetChanged
|
||||
|
||||
proc userAuthenticationCanceled*(self: View) {.signal.}
|
||||
proc userAuthenticationCanceled*(self: View) {.signal.}
|
||||
|
|
|
@ -57,7 +57,6 @@ QtObject:
|
|||
let enumRole = role.ModelRole
|
||||
case enumRole:
|
||||
of ModelRole.Key:
|
||||
|
||||
if item.getType() == ord(TokenType.ENS):
|
||||
result = newQVariant(item.getEnsPattern())
|
||||
else:
|
||||
|
@ -69,7 +68,7 @@ QtObject:
|
|||
of ModelRole.ShortName:
|
||||
result = newQVariant(item.getSymbol())
|
||||
of ModelRole.Name:
|
||||
result = newQVariant(item.getSymbol())
|
||||
result = newQVariant(item.getName())
|
||||
of ModelRole.Amount:
|
||||
result = newQVariant(item.getAmount())
|
||||
of ModelRole.CriteriaMet:
|
||||
|
|
|
@ -162,7 +162,7 @@ QtObject:
|
|||
of "description": result = $item.getDescription()
|
||||
of "assetWebsiteUrl": result = $item.getAssetWebsiteUrl()
|
||||
of "builtOn": result = $item.getBuiltOn()
|
||||
of "Address": result = $item.getAddress()
|
||||
of "address": result = $item.getAddress()
|
||||
of "marketCap": result = $item.getMarketCap()
|
||||
of "highDay": result = $item.getHighDay()
|
||||
of "lowDay": result = $item.getLowDay()
|
||||
|
|
|
@ -89,7 +89,7 @@ proc buildTokenPermissionItem*(tokenPermission: CommunityTokenPermissionDto): To
|
|||
tokenCriteriaItems,
|
||||
tokenPermissionChatListItems,
|
||||
tokenPermission.isPrivate,
|
||||
false # allTokenCriteriaMet will be update by a call to checkPermissinosToJoin
|
||||
false # allTokenCriteriaMet will be updated by a call to checkPermissionsToJoin
|
||||
)
|
||||
|
||||
return tokenPermissionItem
|
||||
|
|
|
@ -253,6 +253,10 @@ ListModel {
|
|||
title: "RemotelyDestructPopup"
|
||||
section: "Popups"
|
||||
}
|
||||
ListElement {
|
||||
title: "SharedAddressesPopup"
|
||||
section: "Popups"
|
||||
}
|
||||
ListElement {
|
||||
title: "AlertPopup"
|
||||
section: "Popups"
|
||||
|
|
|
@ -242,6 +242,13 @@
|
|||
],
|
||||
"EditOwnerTokenView": [
|
||||
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?type=design&node-id=34794-590207&mode=design&t=ZnwK9yenS5oSgwws-0"
|
||||
|
||||
],
|
||||
"CommunityIntroDialog": [
|
||||
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=31461%3A563897&mode=dev"
|
||||
],
|
||||
"SharedAddressesPopup": [
|
||||
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=31461%3A564367&mode=dev",
|
||||
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=31461%3A563905&mode=dev",
|
||||
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=31461%3A579875&mode=dev"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -44,10 +44,16 @@ SplitView {
|
|||
5. 🚗 consectetur adipiscing elit
|
||||
|
||||
Nemo enim 😋 ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.".arg(dialog.name)
|
||||
loginType: ctrlLoginType.currentIndex
|
||||
|
||||
onJoined: logs.logEvent("CommunityIntroDialog::onJoined()")
|
||||
walletAccountsModel: WalletAccountsModel {}
|
||||
permissionsModel: dialog.accessType === Constants.communityChatOnRequestAccess ? PermissionsModel.complexPermissionsModel
|
||||
: null
|
||||
assetsModel: AssetsModel {}
|
||||
collectiblesModel: CollectiblesModel {}
|
||||
|
||||
onJoined: logs.logEvent("CommunityIntroDialog::onJoined", ["airdropAddress", "sharedAddresses"], arguments)
|
||||
onCancelMembershipRequest: logs.logEvent("CommunityIntroDialog::onCancelMembershipRequest()")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,6 +152,20 @@ Nemo enim 😋 ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
|||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
visible: dialog.accessType == Constants.communityChatOnRequestAccess && !dialog.isInvitationPending
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: "Login type"
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: ctrlLoginType
|
||||
Layout.fillWidth: true
|
||||
model: ["Password","Biometrics","Keycard"]
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import QtQuick.Layouts 1.14
|
|||
|
||||
import StatusQ.Core.Utils 0.1
|
||||
|
||||
import AppLayouts.Communities.controls 1.0
|
||||
|
||||
Flickable {
|
||||
id: root
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ SplitView {
|
|||
id: d
|
||||
|
||||
property string name: "Uniswap"
|
||||
property string channelName: "#vip"
|
||||
property string channelName: "vip"
|
||||
property bool joinCommunity: true // Otherwise, enter channel
|
||||
property bool requirementsMet: true
|
||||
property bool isInvitationPending: false
|
||||
|
@ -40,8 +40,6 @@ SplitView {
|
|||
orientation: Qt.Vertical
|
||||
SplitView.fillWidth: true
|
||||
|
||||
|
||||
|
||||
Item {
|
||||
SplitView.fillWidth: true
|
||||
SplitView.fillHeight: true
|
||||
|
|
|
@ -59,6 +59,7 @@ SplitView {
|
|||
readonly property string image: ModelsData.icons.socks
|
||||
readonly property string color: "red"
|
||||
readonly property bool owner: isOwnerCheckBox.checked
|
||||
readonly property bool admin: isAdminCheckBox.checked
|
||||
}
|
||||
|
||||
function log(method, index) {
|
||||
|
@ -94,6 +95,12 @@ SplitView {
|
|||
text: "Is owner"
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
id: isAdminCheckBox
|
||||
|
||||
text: "Is admin"
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
id: emptyModelCheckBox
|
||||
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQml 2.15
|
||||
|
||||
import Storybook 1.0
|
||||
import Models 1.0
|
||||
|
||||
import AppLayouts.Communities.popups 1.0
|
||||
|
||||
SplitView {
|
||||
id: root
|
||||
Logs { id: logs }
|
||||
|
||||
ListModel {
|
||||
id: emptyModel
|
||||
}
|
||||
|
||||
Component {
|
||||
id: dlgComponent
|
||||
SharedAddressesPopup {
|
||||
//anchors.centerIn: parent
|
||||
isEditMode: ctrlEditMode.checked
|
||||
communityName: "Decentraland"
|
||||
communityIcon: ModelsData.assets.uni
|
||||
loginType: ctrlLoginType.currentIndex
|
||||
walletAccountsModel: WalletAccountsModel {}
|
||||
permissionsModel: {
|
||||
if (ctrlPermissions.checked && ctrlTokenGatedChannels.checked)
|
||||
return PermissionsModel.complexPermissionsModel
|
||||
if (ctrlPermissions.checked)
|
||||
return PermissionsModel.permissionsModel
|
||||
if (ctrlTokenGatedChannels.checked)
|
||||
return PermissionsModel.channelsOnlyPermissionsModel
|
||||
|
||||
return emptyModel
|
||||
}
|
||||
|
||||
assetsModel: AssetsModel {}
|
||||
collectiblesModel: CollectiblesModel {}
|
||||
visible: true
|
||||
|
||||
onShareSelectedAddressesClicked: logs.logEvent("::shareSelectedAddressesClicked", ["airdropAddress", "sharedAddresses"], arguments)
|
||||
onClosed: destroy()
|
||||
}
|
||||
}
|
||||
|
||||
property var dialog
|
||||
|
||||
function createAndOpenDialog() {
|
||||
dialog = dlgComponent.createObject(root)
|
||||
dialog.open()
|
||||
}
|
||||
|
||||
Component.onCompleted: createAndOpenDialog()
|
||||
|
||||
SplitView {
|
||||
orientation: Qt.Vertical
|
||||
SplitView.fillWidth: true
|
||||
|
||||
Pane {
|
||||
id: pane
|
||||
|
||||
SplitView.fillWidth: true
|
||||
SplitView.fillHeight: true
|
||||
|
||||
PopupBackground {
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
Button {
|
||||
anchors.centerIn: parent
|
||||
text: "Reopen"
|
||||
|
||||
onClicked: createAndOpenDialog()
|
||||
}
|
||||
}
|
||||
|
||||
LogsAndControlsPanel {
|
||||
id: logsAndControlsPanel
|
||||
|
||||
SplitView.minimumHeight: 100
|
||||
SplitView.preferredHeight: 150
|
||||
|
||||
logsView.logText: logs.logText
|
||||
}
|
||||
}
|
||||
|
||||
Pane {
|
||||
SplitView.minimumWidth: 300
|
||||
SplitView.preferredWidth: 300
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
Switch {
|
||||
id: ctrlPermissions
|
||||
text: "With permissions"
|
||||
checked: true
|
||||
}
|
||||
|
||||
Switch {
|
||||
id: ctrlTokenGatedChannels
|
||||
text: "With token gated channels"
|
||||
checked: true
|
||||
}
|
||||
|
||||
Switch {
|
||||
id: ctrlEditMode
|
||||
text: "Edit mode"
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
visible: ctrlEditMode.checked
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: "Login type"
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: ctrlLoginType
|
||||
Layout.fillWidth: true
|
||||
model: ["Password","Biometrics","Keycard"]
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1
|
||||
color: "lightgray"
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Info"
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: "Shared addresses: %1".arg(!!dialog ? dialog.selectedSharedAddresses.join(";") : "")
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: "Airdrop address: %1".arg(!!dialog ? dialog.selectedAirdropAddress : "")
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -65,8 +65,8 @@ SplitView {
|
|||
errorText: errorTextField.text
|
||||
totalFeeText: "0.01 ETH ($265.43)"
|
||||
|
||||
onSignTransactionClicked: logs.logEvent("SignTokenTransactionsPopup::onSignTransactionClicked")
|
||||
onCancelClicked: logs.logEvent("SignTokenTransactionsPopup::onCancelClicked")
|
||||
onSignTransactionClicked: logs.logEvent("SignMultiTokenTransactionsPopup::onSignTransactionClicked")
|
||||
onCancelClicked: logs.logEvent("SignMultiTokenTransactionsPopup::onCancelClicked")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ SplitView {
|
|||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: "Network name"
|
||||
text: "Network fee"
|
||||
}
|
||||
|
||||
TextField {
|
||||
|
|
|
@ -50,7 +50,7 @@ SplitView {
|
|||
id: editor
|
||||
|
||||
isOnlyChannelPanelEditor: true
|
||||
channelName: "#vip"
|
||||
channelName: "vip"
|
||||
joinCommunity: false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ ListModel {
|
|||
iconSource: ModelsData.assets.snt,
|
||||
name: "snt",
|
||||
shortName: "snt",
|
||||
symbol: "snt",
|
||||
symbol: "SNT",
|
||||
category: TokenCategories.Category.General,
|
||||
communityId: ""
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ ListModel {
|
|||
key: "Anniversary",
|
||||
iconSource: ModelsData.collectibles.anniversary,
|
||||
name: "Anniversary",
|
||||
symbol: "Anniversary",
|
||||
symbol: "ANN",
|
||||
category: TokenCategories.Category.Community,
|
||||
imageUrl: ModelsData.collectibles.anniversary,
|
||||
id: 1767698,
|
||||
|
@ -18,7 +18,7 @@ ListModel {
|
|||
key: "Anniversary2",
|
||||
iconSource: ModelsData.collectibles.anniversary,
|
||||
name: "Anniversary2",
|
||||
symbol: "Anniversary2",
|
||||
symbol: "ANN2",
|
||||
category: TokenCategories.Category.Community,
|
||||
imageUrl: ModelsData.collectibles.anniversary,
|
||||
id: 1767699,
|
||||
|
@ -28,7 +28,7 @@ ListModel {
|
|||
key: "CryptoKitties",
|
||||
iconSource: ModelsData.collectibles.cryptoKitties,
|
||||
name: "CryptoKitties",
|
||||
symbol: "CryptoKitties",
|
||||
symbol: "CK",
|
||||
category: TokenCategories.Category.Own,
|
||||
subItems: [
|
||||
{
|
||||
|
@ -82,7 +82,7 @@ ListModel {
|
|||
key: "SuperRare",
|
||||
iconSource: ModelsData.collectibles.superRare,
|
||||
name: "SuperRare",
|
||||
symbol: "SuperRare",
|
||||
symbol: "SR",
|
||||
category: TokenCategories.Category.Own,
|
||||
imageUrl: ModelsData.collectibles.superRare,
|
||||
id: 1767701,
|
||||
|
@ -92,7 +92,7 @@ ListModel {
|
|||
key: "Custom",
|
||||
iconSource: ModelsData.collectibles.custom,
|
||||
name: "Custom Collectible",
|
||||
symbol: "Custom",
|
||||
symbol: "CUS",
|
||||
category: TokenCategories.Category.General,
|
||||
imageUrl: ModelsData.collectibles.custom,
|
||||
id: 1767764,
|
||||
|
|
|
@ -14,13 +14,15 @@ QtObject {
|
|||
holdingsListModel: root.createHoldingsModel1(),
|
||||
channelsListModel: root.createChannelsModel1(),
|
||||
permissionType: PermissionTypes.Type.Admin,
|
||||
isPrivate: true
|
||||
isPrivate: true,
|
||||
tokenCriteriaMet: false
|
||||
},
|
||||
{
|
||||
holdingsListModel: root.createHoldingsModel2(),
|
||||
channelsListModel: root.createChannelsModel2(),
|
||||
permissionType: PermissionTypes.Type.Member,
|
||||
isPrivate: false
|
||||
isPrivate: false,
|
||||
tokenCriteriaMet: true
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -29,7 +31,7 @@ QtObject {
|
|||
holdingsListModel: root.createHoldingsModel4(),
|
||||
channelsListModel: root.createChannelsModel1(),
|
||||
permissionType: PermissionTypes.Type.Admin,
|
||||
isPrivate: true,
|
||||
isPrivate: true
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -138,6 +140,124 @@ QtObject {
|
|||
}
|
||||
]
|
||||
|
||||
readonly property var complexPermissionsModelData: [
|
||||
{
|
||||
id: "admin1",
|
||||
holdingsListModel: root.createHoldingsModel2b(),
|
||||
channelsListModel: root.createChannelsModel2(),
|
||||
permissionType: PermissionTypes.Type.Admin,
|
||||
isPrivate: false,
|
||||
tokenCriteriaMet: true
|
||||
},
|
||||
{
|
||||
id: "admin2",
|
||||
holdingsListModel: root.createHoldingsModel3(),
|
||||
channelsListModel: root.createChannelsModel2(),
|
||||
permissionType: PermissionTypes.Type.Admin,
|
||||
isPrivate: false,
|
||||
tokenCriteriaMet: false
|
||||
},
|
||||
{
|
||||
id: "member1",
|
||||
holdingsListModel: root.createHoldingsModel2(),
|
||||
channelsListModel: root.createChannelsModel2(),
|
||||
permissionType: PermissionTypes.Type.Member,
|
||||
isPrivate: false,
|
||||
tokenCriteriaMet: true
|
||||
},
|
||||
{
|
||||
id: "member2",
|
||||
holdingsListModel: root.createHoldingsModel3(),
|
||||
channelsListModel: root.createChannelsModel2(),
|
||||
permissionType: PermissionTypes.Type.Member,
|
||||
isPrivate: false,
|
||||
tokenCriteriaMet: false
|
||||
}
|
||||
]
|
||||
|
||||
readonly property var channelsOnlyPermissionsModelData: [
|
||||
{
|
||||
id: "read1a",
|
||||
holdingsListModel: root.createHoldingsModel1b(),
|
||||
channelsListModel: root.createChannelsModel1(),
|
||||
permissionType: PermissionTypes.Type.Read,
|
||||
isPrivate: false,
|
||||
tokenCriteriaMet: true
|
||||
},
|
||||
{
|
||||
id: "read1b",
|
||||
holdingsListModel: root.createHoldingsModel1(),
|
||||
channelsListModel: root.createChannelsModel1(),
|
||||
permissionType: PermissionTypes.Type.Read,
|
||||
isPrivate: false,
|
||||
tokenCriteriaMet: false
|
||||
},
|
||||
{
|
||||
id: "read1c",
|
||||
holdingsListModel: root.createHoldingsModel3(),
|
||||
channelsListModel: root.createChannelsModel1(),
|
||||
permissionType: PermissionTypes.Type.Read,
|
||||
isPrivate: false,
|
||||
tokenCriteriaMet: false
|
||||
},
|
||||
{
|
||||
id: "read2a",
|
||||
holdingsListModel: root.createHoldingsModel2(),
|
||||
channelsListModel: root.createChannelsModel3(),
|
||||
permissionType: PermissionTypes.Type.Read,
|
||||
isPrivate: false,
|
||||
tokenCriteriaMet: true
|
||||
},
|
||||
{
|
||||
id: "read2b",
|
||||
holdingsListModel: root.createHoldingsModel5(),
|
||||
channelsListModel: root.createChannelsModel3(),
|
||||
permissionType: PermissionTypes.Type.Read,
|
||||
isPrivate: false,
|
||||
tokenCriteriaMet: false
|
||||
},
|
||||
{
|
||||
id: "viewAndPost1a",
|
||||
holdingsListModel: root.createHoldingsModel3(),
|
||||
channelsListModel: root.createChannelsModel1(),
|
||||
permissionType: PermissionTypes.Type.ViewAndPost,
|
||||
isPrivate: false,
|
||||
tokenCriteriaMet: false
|
||||
},
|
||||
{
|
||||
id: "viewAndPost1b",
|
||||
holdingsListModel: root.createHoldingsModel2b(),
|
||||
channelsListModel: root.createChannelsModel1(),
|
||||
permissionType: PermissionTypes.Type.ViewAndPost,
|
||||
isPrivate: false,
|
||||
tokenCriteriaMet: true
|
||||
},
|
||||
{
|
||||
id: "viewAndPost2a",
|
||||
holdingsListModel: root.createHoldingsModel3(),
|
||||
channelsListModel: root.createChannelsModel3(),
|
||||
permissionType: PermissionTypes.Type.ViewAndPost,
|
||||
isPrivate: false,
|
||||
tokenCriteriaMet: false
|
||||
},
|
||||
{
|
||||
id: "viewAndPost2b",
|
||||
holdingsListModel: root.createHoldingsModel5(),
|
||||
channelsListModel: root.createChannelsModel3(),
|
||||
permissionType: PermissionTypes.Type.ViewAndPost,
|
||||
isPrivate: false,
|
||||
tokenCriteriaMet: false
|
||||
},
|
||||
{
|
||||
id: "viewAndPost2c",
|
||||
holdingsListModel: root.createHoldingsModel1(),
|
||||
channelsListModel: root.createChannelsModel3(),
|
||||
permissionType: PermissionTypes.Type.ViewAndPost,
|
||||
isPrivate: false,
|
||||
tokenCriteriaMet: false
|
||||
}
|
||||
]
|
||||
|
||||
readonly property ListModel permissionsModel: ListModel {
|
||||
readonly property ModelChangeGuard guard: ModelChangeGuard {
|
||||
model: root.permissionsModel
|
||||
|
@ -215,6 +335,29 @@ QtObject {
|
|||
}
|
||||
}
|
||||
|
||||
readonly property var complexPermissionsModel: ListModel {
|
||||
readonly property ModelChangeGuard guard: ModelChangeGuard {
|
||||
model: root.complexPermissionsModel
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
append(complexPermissionsModelData)
|
||||
append(channelsOnlyPermissionsModelData)
|
||||
guard.enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
readonly property var channelsOnlyPermissionsModel: ListModel {
|
||||
readonly property ModelChangeGuard guard: ModelChangeGuard {
|
||||
model: root.channelsOnlyPermissionsModel
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
append(channelsOnlyPermissionsModelData)
|
||||
guard.enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
function createHoldingsModel1() {
|
||||
return [
|
||||
{
|
||||
|
@ -230,7 +373,7 @@ QtObject {
|
|||
return [
|
||||
{
|
||||
type: HoldingTypes.Type.Ens,
|
||||
key: "Ens",
|
||||
key: "*.eth",
|
||||
amount: 1,
|
||||
available: true
|
||||
}
|
||||
|
@ -249,7 +392,24 @@ QtObject {
|
|||
type: HoldingTypes.Type.Asset,
|
||||
key: "Dai",
|
||||
amount: 11,
|
||||
available: false
|
||||
available: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
function createHoldingsModel2b() {
|
||||
return [
|
||||
{
|
||||
type: HoldingTypes.Type.Collectible,
|
||||
key: "Anniversary2",
|
||||
amount: 1,
|
||||
available: true
|
||||
},
|
||||
{
|
||||
type: HoldingTypes.Type.Asset,
|
||||
key: "snt",
|
||||
amount: 666,
|
||||
available: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -293,7 +453,7 @@ QtObject {
|
|||
},
|
||||
{
|
||||
type: HoldingTypes.Type.Ens,
|
||||
key: "ENS",
|
||||
key: "foo.bar.eth",
|
||||
amount: 1,
|
||||
available: false
|
||||
},
|
||||
|
@ -317,7 +477,7 @@ QtObject {
|
|||
{
|
||||
type: HoldingTypes.Type.Asset,
|
||||
key: "zrx",
|
||||
amount: 1,
|
||||
amount: 10,
|
||||
available: false
|
||||
},
|
||||
{
|
||||
|
@ -355,4 +515,8 @@ QtObject {
|
|||
function createChannelsModel2() {
|
||||
return []
|
||||
}
|
||||
|
||||
function createChannelsModel3() {
|
||||
return [{ key: "_vip" } ]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,122 @@
|
|||
import QtQuick 2.15
|
||||
|
||||
import utils 1.0
|
||||
|
||||
ListModel {
|
||||
ListElement { name: "Test account"; emoji: "😋"; colorId: "primary"; address: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240"; walletType: "" }
|
||||
ListElement { name: "Another account - generated"; emoji: "🚗"; colorId: "army"; address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8888"; walletType: "generated" }
|
||||
ListElement { name: "Another account - seed"; emoji: "🎨"; colorId: "army"; address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8888"; walletType: "seed" }
|
||||
ListElement { name: "Another account - watch"; emoji: "🔗"; colorId: "army"; address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8888"; walletType: "watch" }
|
||||
ListElement { name: "Another account - key"; emoji: "💼"; colorId: "army"; address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8888"; walletType: "key" }
|
||||
readonly property var data: [
|
||||
{
|
||||
name: "helloworld",
|
||||
emoji: "😋",
|
||||
colorId: "primary",
|
||||
address: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240",
|
||||
walletType: "",
|
||||
position: 0,
|
||||
assets: [
|
||||
{
|
||||
symbol: "socks",
|
||||
enabledNetworkBalance: {
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: true,
|
||||
amount: 15.0,
|
||||
symbol: "SOX"
|
||||
}
|
||||
},
|
||||
{
|
||||
symbol: "snt",
|
||||
enabledNetworkBalance: {
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: true,
|
||||
amount: 670.2345,
|
||||
symbol: "SNT"
|
||||
}
|
||||
},
|
||||
{
|
||||
symbol: "zrx",
|
||||
enabledNetworkBalance: {
|
||||
displayDecimals: 4,
|
||||
stripTrailingZeroes: true,
|
||||
amount: 7.456000,
|
||||
symbol: "ZRX"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Hot wallet (generated)",
|
||||
emoji: "🚗",
|
||||
colorId: "army",
|
||||
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8881",
|
||||
walletType: Constants.generatedWalletType,
|
||||
position: 3,
|
||||
assets: [
|
||||
{
|
||||
symbol: "deadbeef",
|
||||
enabledNetworkBalance: {
|
||||
displayDecimals: 1,
|
||||
stripTrailingZeroes: true,
|
||||
amount: 1,
|
||||
symbol: "DBF"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Family (seed)",
|
||||
emoji: "🎨", colorId: "magenta",
|
||||
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8882",
|
||||
walletType: Constants.seedWalletType,
|
||||
position: 1,
|
||||
assets: [
|
||||
{
|
||||
symbol: "Aave",
|
||||
enabledNetworkBalance: {
|
||||
displayDecimals: 6,
|
||||
stripTrailingZeroes: true,
|
||||
amount: 42,
|
||||
symbol: "AAVE"
|
||||
}
|
||||
},
|
||||
{
|
||||
symbol: "dai",
|
||||
enabledNetworkBalance: {
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: true,
|
||||
amount: 120.123,
|
||||
symbol: "DAI"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Tag Heuer (watch)",
|
||||
emoji: "⌚",
|
||||
colorId: "copper",
|
||||
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8883",
|
||||
walletType: Constants.watchWalletType,
|
||||
position: 2,
|
||||
assets: [
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Fab (key)",
|
||||
emoji: "⌚",
|
||||
colorId: Constants.walletAccountColors.camel,
|
||||
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8884",
|
||||
walletType: Constants.keyWalletType,
|
||||
position: 4,
|
||||
assets: [
|
||||
{
|
||||
symbol: "socks",
|
||||
enabledNetworkBalance: {
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false,
|
||||
amount: 3.5,
|
||||
symbol: "SOX"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
Component.onCompleted: append(data)
|
||||
}
|
||||
|
|
|
@ -91,11 +91,13 @@ add_library(StatusQ SHARED
|
|||
src/plugin.cpp
|
||||
include/StatusQ/QClipboardProxy.h
|
||||
include/StatusQ/modelutilsinternal.h
|
||||
include/StatusQ/permissionutilsinternal.h
|
||||
include/StatusQ/rxvalidator.h
|
||||
include/StatusQ/statussyntaxhighlighter.h
|
||||
include/StatusQ/statuswindow.h
|
||||
src/QClipboardProxy.cpp
|
||||
src/modelutilsinternal.cpp
|
||||
src/permissionutilsinternal.cpp
|
||||
src/rxvalidator.cpp
|
||||
src/statussyntaxhighlighter.cpp
|
||||
src/statuswindow.cpp
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class QAbstractItemModel;
|
||||
|
||||
class PermissionUtilsInternal : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PermissionUtilsInternal(QObject* parent = nullptr);
|
||||
|
||||
//!< traverse the permissions @p model, and look for unique token keys recursively under holdingsListModel->key
|
||||
Q_INVOKABLE QStringList getUniquePermissionTokenKeys(QAbstractItemModel *model) const;
|
||||
|
||||
//!< traverse the permissions @p model, and look for unique channel keys recursively under channelsListModel->key; filtering out @permissionTypes ([PermissionTypes.Type.FOO])
|
||||
Q_INVOKABLE QStringList getUniquePermissionChannels(QAbstractItemModel *model, const QList<int> &permissionTypes = {}) const;
|
||||
};
|
|
@ -359,8 +359,8 @@ Rectangle {
|
|||
id: tagsScrollView
|
||||
visible: tagsRepeater.count > 0
|
||||
anchors.top: statusListItemTertiaryTitle.bottom
|
||||
anchors.topMargin: visible ? 8 : 0
|
||||
width: Math.min(statusListItemTagsSlotInline.width, statusListItemTagsSlotInline.availableWidth)
|
||||
anchors.topMargin: visible ? 2 : 0
|
||||
width: Math.min(statusListItemTagsSlotInline.width, statusListItemTagsSlotInline.availableWidth, parent.width)
|
||||
height: visible ? contentHeight : 0
|
||||
padding: 0
|
||||
|
||||
|
@ -378,7 +378,7 @@ Rectangle {
|
|||
|
||||
RowLayout {
|
||||
anchors.top: tagsScrollView.bottom
|
||||
anchors.topMargin: visible ? 8 : 0
|
||||
anchors.topMargin: visible ? 4 : 0
|
||||
width: parent.width
|
||||
visible: !!root.beneathTagsIcon || !!root.beneathTagsTitle
|
||||
spacing: 4
|
||||
|
|
|
@ -2,4 +2,3 @@ module StatusQ.Components.private
|
|||
|
||||
StatusImageMessage 0.1 statusMessage/StatusImageMessage.qml
|
||||
StatusMessageImageAlbum 0.1 statusMessage/StatusMessageImageAlbum.qml
|
||||
StatusBaseDateInput 0.1 dateInput/StatusBaseDateInput.qml
|
||||
|
|
|
@ -79,6 +79,7 @@ CheckBox {
|
|||
: root.indicator.width) : 0
|
||||
rightPadding: !root.leftSide? (!!root.text ? root.indicator.width + root.spacing
|
||||
: root.indicator.width) : 0
|
||||
visible: !!text
|
||||
}
|
||||
|
||||
HoverHandler {
|
||||
|
|
|
@ -21,6 +21,7 @@ RadioButton {
|
|||
Large
|
||||
}
|
||||
|
||||
opacity: enabled ? 1.0 : 0.3
|
||||
font.family: Theme.palette.baseFont.name
|
||||
|
||||
indicator: Rectangle {
|
||||
|
@ -47,5 +48,6 @@ RadioButton {
|
|||
verticalAlignment: Text.AlignVCenter
|
||||
leftPadding: root.indicator && !root.mirrored ? root.indicator.width + root.spacing : 0
|
||||
rightPadding: root.indicator && root.mirrored ? root.indicator.width + root.spacing : 0
|
||||
visible: !!text
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ QtObject {
|
|||
return num.toString().split('.')[1].length
|
||||
}
|
||||
|
||||
|
||||
function stripTrailingZeroes(numStr, locale) {
|
||||
let regEx = locale.decimalPoint == "." ? /(\.[0-9]*[1-9])0+$|\.0*$/ : /(\,[0-9]*[1-9])0+$|\,0*$/
|
||||
return numStr.replace(regEx, '$1')
|
||||
|
@ -101,8 +102,6 @@ QtObject {
|
|||
}
|
||||
|
||||
function currencyAmountToLocaleString(currencyAmount, options = null, locale = null) {
|
||||
locale = locale || Qt.locale()
|
||||
|
||||
if (!currencyAmount) {
|
||||
return qsTr("N/A")
|
||||
}
|
||||
|
@ -114,6 +113,8 @@ QtObject {
|
|||
if (typeof currencyAmount.amount === "undefined")
|
||||
return qsTr("N/A")
|
||||
|
||||
locale = locale || Qt.locale()
|
||||
|
||||
// Parse options
|
||||
var optNoSymbol = false
|
||||
var optRawAmount = false
|
||||
|
@ -141,7 +142,7 @@ QtObject {
|
|||
if (currencyAmount.amount > 0 && currencyAmount.amount < minAmount && !optRawAmount)
|
||||
{
|
||||
// Handle amounts smaller than resolution
|
||||
amountStr = "<%1".arg(numberToLocaleString(minAmount, displayDecimals, locale))
|
||||
amountStr = "<%1".arg(numberToLocaleString(minAmount, optDisplayDecimals, locale))
|
||||
} else {
|
||||
var amount
|
||||
var displayDecimals
|
||||
|
@ -158,11 +159,10 @@ QtObject {
|
|||
// For normal numbers, we show the whole integral part and as many decimal places not
|
||||
// not to exceed the maximum
|
||||
amount = currencyAmount.amount
|
||||
// For numbers over 1M , dont show decimal places
|
||||
// For numbers over 1M , dont show decimal places
|
||||
if(numIntegerDigits > maxDigitsToShowDecimal) {
|
||||
displayDecimals = 0
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
displayDecimals = Math.min(optDisplayDecimals, Math.max(0, maxDigits - numIntegerDigits))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,9 +16,8 @@ Image {
|
|||
if(icon.startsWith("data:image/") || icon.startsWith("https://") || icon.startsWith("qrc:/") || icon.startsWith("file:/")) {
|
||||
//raw image data
|
||||
source = icon
|
||||
objectName = "custom-icon"
|
||||
}
|
||||
else if (icon !== "") {
|
||||
objectName = "custom-icon"
|
||||
} else if (icon !== "") {
|
||||
source = "../../assets/img/icons/" + icon+ ".svg";
|
||||
objectName = icon + "-icon"
|
||||
}
|
||||
|
|
|
@ -45,6 +45,10 @@ QtObject {
|
|||
return array
|
||||
}
|
||||
|
||||
function modelToFlatArray(model, role) {
|
||||
return modelToArray(model, [role]).map(entry => entry[role])
|
||||
}
|
||||
|
||||
function indexOf(model, role, key) {
|
||||
const count = model.rowCount()
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@ QtObject {
|
|||
case OperatorsUtils.Operators.None:
|
||||
default:
|
||||
return ""
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import QtQuick 2.14
|
||||
import QtQuick.Controls 2.14
|
||||
import QtQuick.Layouts 1.14
|
||||
import QtQml.Models 2.14
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQml.Models 2.15
|
||||
import QtQml 2.15
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
|
@ -28,6 +29,14 @@ Dialog {
|
|||
margins: 64
|
||||
modal: true
|
||||
|
||||
// workaround for https://bugreports.qt.io/browse/QTBUG-87804
|
||||
Binding on margins {
|
||||
id: workaroundBinding
|
||||
|
||||
when: false
|
||||
restoreMode: Binding.RestoreBindingOrValue
|
||||
}
|
||||
|
||||
standardButtons: Dialog.Cancel | Dialog.Ok
|
||||
|
||||
Overlay.modal: Rectangle {
|
||||
|
|
|
@ -23,7 +23,7 @@ StatusModal {
|
|||
visible: replaceItem || stackLayout.currentIndex > 0
|
||||
onClicked: {
|
||||
if (replaceItem) {
|
||||
replaceItem = null;
|
||||
replaceItem = undefined; // unload the replaceItem
|
||||
} else {
|
||||
let prevAction = stackLayout.currentItem.prevAction
|
||||
stackLayout.currentIndex--;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "StatusQ/modelutilsinternal.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QDebug>
|
||||
|
||||
ModelUtilsInternal::ModelUtilsInternal(QObject* parent)
|
||||
: QObject(parent)
|
||||
|
@ -16,7 +17,6 @@ QStringList ModelUtilsInternal::roleNames(QAbstractItemModel *model) const
|
|||
return {roles.cbegin(), roles.cend()};
|
||||
}
|
||||
|
||||
|
||||
int ModelUtilsInternal::roleByName(QAbstractItemModel* model,
|
||||
const QString &roleName) const
|
||||
{
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
#include "StatusQ/permissionutilsinternal.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QDebug>
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace {
|
||||
int roleByName(QAbstractItemModel* model, const QString &roleName)
|
||||
{
|
||||
if (!model)
|
||||
return -1;
|
||||
|
||||
return model->roleNames().key(roleName.toUtf8(), -1);
|
||||
}
|
||||
}
|
||||
|
||||
PermissionUtilsInternal::PermissionUtilsInternal(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QStringList PermissionUtilsInternal::getUniquePermissionTokenKeys(QAbstractItemModel* model) const
|
||||
{
|
||||
if (!model)
|
||||
return {};
|
||||
|
||||
const auto role = roleByName(model, QStringLiteral("holdingsListModel"));
|
||||
if (role == -1) {
|
||||
qWarning() << Q_FUNC_INFO << "Requested roleName 'holdingsListModel' not found!";
|
||||
return {};
|
||||
}
|
||||
|
||||
std::set<QString> result; // unique, sorted by default
|
||||
|
||||
const auto permissionsCount = model->rowCount();
|
||||
for (int i = 0; i < permissionsCount; i++) {
|
||||
const auto isPrivate = model->data(model->index(i, 0), roleByName(model, QStringLiteral("isPrivate"))).toBool();
|
||||
if (isPrivate)
|
||||
continue;
|
||||
|
||||
const auto holdings = model->data(model->index(i, 0), role);
|
||||
if (holdings.isValid() && !holdings.isNull()) {
|
||||
const auto holdingItems = holdings.value<QAbstractItemModel*>();
|
||||
if (!holdingItems) {
|
||||
qWarning() << Q_FUNC_INFO << "Unable to cast 'holdingsListModel' to QAbstractItemModel *!";
|
||||
continue;
|
||||
}
|
||||
const auto holdingItemsCount = holdingItems->rowCount();
|
||||
for (int j = 0; j < holdingItemsCount; j++) {
|
||||
const auto keyRole = roleByName(holdingItems, QStringLiteral("key"));
|
||||
if (keyRole == -1) {
|
||||
qWarning() << Q_FUNC_INFO << "Requested roleName 'key' not found!";
|
||||
continue;
|
||||
}
|
||||
result.insert(holdingItems->data(holdingItems->index(j, 0), keyRole).toString().toUpper());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {result.cbegin(), result.cend()};
|
||||
}
|
||||
|
||||
// TODO return a QVariantMap (https://github.com/status-im/status-desktop/issues/11481) with key->channelName
|
||||
QStringList PermissionUtilsInternal::getUniquePermissionChannels(QAbstractItemModel* model, const QList<int> &permissionTypes) const
|
||||
{
|
||||
if (!model)
|
||||
return {};
|
||||
|
||||
const auto role = roleByName(model, QStringLiteral("channelsListModel"));
|
||||
if (role == -1) {
|
||||
qWarning() << Q_FUNC_INFO << "Requested roleName 'channelsListModel' not found!";
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto permissionTypeRole = roleByName(model, QStringLiteral("permissionType"));
|
||||
|
||||
std::set<QString> result; // unique, sorted by default
|
||||
|
||||
const auto permissionsCount = model->rowCount();
|
||||
for (int i = 0; i < permissionsCount; i++) {
|
||||
if (!permissionTypes.isEmpty()) {
|
||||
const auto permissionType = model->data(model->index(i, 0), permissionTypeRole).toInt();
|
||||
if (!permissionTypes.contains(permissionType))
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto channels = model->data(model->index(i, 0), role);
|
||||
if (channels.isValid() && !channels.isNull()) {
|
||||
const auto channelItems = channels.value<QAbstractItemModel *>();
|
||||
if (!channelItems) {
|
||||
qWarning() << Q_FUNC_INFO << "Unable to cast 'channelsListModel' to QAbstractItemModel *!";
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto channelItemsCount = channelItems->rowCount();
|
||||
for (int j = 0; j < channelItemsCount; j++) {
|
||||
const auto keyRole = roleByName(channelItems, QStringLiteral("key"));
|
||||
if (keyRole == -1) {
|
||||
qWarning() << Q_FUNC_INFO << "Requested roleName 'key' not found!";
|
||||
continue;
|
||||
}
|
||||
result.insert(channelItems->data(channelItems->index(j, 0), keyRole).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {result.cbegin(), result.cend()};
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "StatusQ/QClipboardProxy.h"
|
||||
#include "StatusQ/modelutilsinternal.h"
|
||||
#include "StatusQ/permissionutilsinternal.h"
|
||||
#include "StatusQ/rxvalidator.h"
|
||||
#include "StatusQ/statussyntaxhighlighter.h"
|
||||
#include "StatusQ/statuswindow.h"
|
||||
|
@ -26,6 +27,10 @@ public:
|
|||
qmlRegisterSingletonType<ModelUtilsInternal>(
|
||||
"StatusQ.Internal", 0, 1, "ModelUtils", &ModelUtilsInternal::qmlInstance);
|
||||
|
||||
qmlRegisterSingletonType<PermissionUtilsInternal>("StatusQ.Internal", 0, 1, "PermissionUtils", [](QQmlEngine *, QJSEngine *) {
|
||||
return new PermissionUtilsInternal;
|
||||
});
|
||||
|
||||
QZXing::registerQMLTypes();
|
||||
qqsfpm::registerTypes();
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import "stores"
|
|||
import AppLayouts.Communities.popups 1.0
|
||||
|
||||
import AppLayouts.Chat.stores 1.0
|
||||
import AppLayouts.Wallet.stores 1.0 as WalletStore
|
||||
|
||||
StackLayout {
|
||||
id: root
|
||||
|
@ -176,8 +177,14 @@ StackLayout {
|
|||
|
||||
property string communityId
|
||||
|
||||
loginType: root.rootStore.loginType
|
||||
walletAccountsModel: WalletStore.RootStore.receiveAccounts
|
||||
permissionsModel: root.permissionsStore.permissionsModel
|
||||
assetsModel: root.rootStore.assetsModel
|
||||
collectiblesModel: root.rootStore.collectiblesModel
|
||||
|
||||
onJoined: {
|
||||
root.rootStore.requestToJoinCommunityWithAuthentication(root.rootStore.userProfileInst.name)
|
||||
root.rootStore.requestToJoinCommunityWithAuthentication(root.rootStore.userProfileInst.name, sharedAddresses, airdropAddress)
|
||||
}
|
||||
|
||||
onCancelMembershipRequest: {
|
||||
|
|
|
@ -378,8 +378,8 @@ QtObject {
|
|||
return communitiesModuleInst.spectateCommunity(id, ensName)
|
||||
}
|
||||
|
||||
function requestToJoinCommunityWithAuthentication(ensName) {
|
||||
chatCommunitySectionModule.requestToJoinCommunityWithAuthentication(ensName)
|
||||
function requestToJoinCommunityWithAuthentication(ensName, addressesToShare = [], airdropAddress = "") {
|
||||
chatCommunitySectionModule.requestToJoinCommunityWithAuthenticationWithSharedAddresses(ensName, JSON.stringify(addressesToShare), airdropAddress)
|
||||
}
|
||||
|
||||
function userCanJoin(id) {
|
||||
|
@ -475,7 +475,7 @@ QtObject {
|
|||
const userCanJoin = userCanJoin(result.communityId)
|
||||
// TODO find what to do when you can't join
|
||||
if (userCanJoin) {
|
||||
requestToJoinCommunityWithAuthentication(userProfileInst.preferredName)
|
||||
requestToJoinCommunityWithAuthentication(userProfileInst.preferredName) // FIXME what addresses to share?
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
@ -608,9 +608,9 @@ QtObject {
|
|||
|
||||
if(userProfileInst.usingBiometricLogin)
|
||||
return Constants.LoginType.Biometrics
|
||||
else if(userProfileInst.isKeycardUser)
|
||||
if(userProfileInst.isKeycardUser)
|
||||
return Constants.LoginType.Keycard
|
||||
else return Constants.LoginType.Password
|
||||
return Constants.LoginType.Password
|
||||
}
|
||||
|
||||
readonly property Connections communitiesModuleConnections: Connections {
|
||||
|
|
|
@ -26,7 +26,7 @@ StatusSectionLayout {
|
|||
id: root
|
||||
|
||||
property var contactsStore
|
||||
property bool hasAddedContacts: root.contactsStore.myContactsModel.count > 0
|
||||
property bool hasAddedContacts: contactsStore.myContactsModel.count > 0
|
||||
|
||||
property RootStore rootStore
|
||||
property var createChatPropertiesStore
|
||||
|
@ -36,7 +36,7 @@ StatusSectionLayout {
|
|||
property var stickersPopup
|
||||
property bool stickersLoaded: false
|
||||
|
||||
readonly property var chatContentModule: root.rootStore.currentChatContentModule() || null
|
||||
readonly property var chatContentModule: rootStore.currentChatContentModule() || null
|
||||
readonly property bool viewOnlyPermissionsSatisfied: chatContentModule.viewOnlyPermissionsSatisfied
|
||||
readonly property bool viewAndPostPermissionsSatisfied: chatContentModule.viewAndPostPermissionsSatisfied
|
||||
property bool hasViewOnlyPermissions: false
|
||||
|
|
|
@ -6,7 +6,7 @@ import StatusQ.Core.Theme 0.1
|
|||
|
||||
QtObject {
|
||||
enum Type {
|
||||
None, Admin, Member, Read, ViewAndPost
|
||||
None, Admin, Member, Read, ViewAndPost, Moderator
|
||||
}
|
||||
|
||||
function getName(type) {
|
||||
|
@ -15,12 +15,12 @@ QtObject {
|
|||
return qsTr("Become admin")
|
||||
case PermissionTypes.Type.Member:
|
||||
return qsTr("Become member")
|
||||
case PermissionTypes.Type.Moderator:
|
||||
return qsTr("Moderate")
|
||||
case PermissionTypes.Type.ViewAndPost:
|
||||
return qsTr("View and post")
|
||||
case PermissionTypes.Type.Read:
|
||||
return qsTr("View only")
|
||||
case PermissionTypes.Type.ViewAndPost:
|
||||
return qsTr("View and post")
|
||||
case PermissionTypes.Type.Moderator:
|
||||
return qsTr("Moderate")
|
||||
}
|
||||
|
||||
return ""
|
||||
|
@ -32,12 +32,12 @@ QtObject {
|
|||
return "admin"
|
||||
case PermissionTypes.Type.Member:
|
||||
return "in-contacts"
|
||||
case PermissionTypes.Type.Moderator:
|
||||
return "arbitrator"
|
||||
case PermissionTypes.Type.ViewAndPost:
|
||||
return "edit"
|
||||
case PermissionTypes.Type.Read:
|
||||
return "show"
|
||||
case PermissionTypes.Type.Moderator:
|
||||
return "arbitrator"
|
||||
}
|
||||
|
||||
return ""
|
||||
|
|
|
@ -4,6 +4,7 @@ import QtQml 2.14
|
|||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Utils 0.1
|
||||
import StatusQ.Internal 0.1 as Internal
|
||||
|
||||
import AppLayouts.Communities.controls 1.0
|
||||
|
||||
|
@ -63,6 +64,15 @@ QtObject {
|
|||
return ""
|
||||
}
|
||||
|
||||
function getUniquePermissionTokenKeys(model) {
|
||||
return Internal.PermissionUtils.getUniquePermissionTokenKeys(model)
|
||||
}
|
||||
|
||||
function getUniquePermissionChannels(model, permissionsTypesArray = []) {
|
||||
// TODO return a QVariantMap (https://github.com/status-im/status-desktop/issues/11481)
|
||||
return Internal.PermissionUtils.getUniquePermissionChannels(model, permissionsTypesArray)
|
||||
}
|
||||
|
||||
function setHoldingsTextFormat(type, name, amount) {
|
||||
switch (type) {
|
||||
case HoldingTypes.Type.Asset:
|
||||
|
|
|
@ -27,10 +27,6 @@ Control {
|
|||
|
||||
// By design values:
|
||||
readonly property int defaultHoldingsSpacing: 8
|
||||
|
||||
function holdingsTextFormat(name, amount) {
|
||||
return PermissionsHelpers.setHoldingsTextFormat(HoldingTypes.Type.Asset, name, amount)
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
|
@ -83,7 +79,7 @@ Control {
|
|||
asset.color: asset.isImage ? "transparent" : titleText.color
|
||||
closeButtonVisible: false
|
||||
titleText.color: model.available ? Theme.palette.primaryColor1 : Theme.palette.dangerColor1
|
||||
bgColor: model.available ? Theme.palette.primaryColor2 :Theme.palette.dangerColor2
|
||||
bgColor: model.available ? Theme.palette.primaryColor2 : Theme.palette.dangerColor2
|
||||
titleText.font.pixelSize: 15
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,15 +92,23 @@ Control {
|
|||
]
|
||||
}
|
||||
|
||||
readonly property var moderatePermissionsModel: SortFilterProxyModel {
|
||||
sourceModel: root.moderateHoldingsModel
|
||||
filters: [
|
||||
ExpressionFilter {
|
||||
expression: d.filterPermissions(model)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
padding: 35 // default by design
|
||||
spacing: 32 // default by design
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
id: column
|
||||
|
||||
spacing: root.spacing
|
||||
|
||||
component CustomHoldingsListPanel: HoldingsListPanel {
|
||||
Layout.fillWidth: true
|
||||
|
||||
|
@ -123,25 +131,23 @@ Control {
|
|||
CustomHoldingsListPanel {
|
||||
visible: !root.joinCommunity && d.viewOnlyPermissionsModel.count > 0
|
||||
introText: root.requiresRequest ?
|
||||
qsTr("To view the #<b>%1</b> channel you need to join <b>%2</b> and prove that you hold").arg(root.channelName).arg(root.communityName) :
|
||||
qsTr("To view the #<b>%1</b> channel you need to hold").arg(root.channelName)
|
||||
qsTr("To view the <b>#%1</b> channel you need to join <b>%2</b> and prove that you hold").arg(root.channelName).arg(root.communityName) :
|
||||
qsTr("To view the <b>#%1</b> channel you need to hold").arg(root.channelName)
|
||||
model: d.viewOnlyPermissionsModel
|
||||
}
|
||||
|
||||
CustomHoldingsListPanel {
|
||||
visible: !root.joinCommunity && d.viewAndPostPermissionsModel.count > 0
|
||||
introText: root.requiresRequest ?
|
||||
qsTr("To view and post in the #<b>%1</b> channel you need to join <b>%2</b> and prove that you hold").arg(root.channelName).arg(root.communityName) :
|
||||
qsTr("To view and post in the #<b>%1</b> channel you need to hold").arg(root.channelName)
|
||||
qsTr("To view and post in the <b>#%1</b> channel you need to join <b>%2</b> and prove that you hold").arg(root.channelName).arg(root.communityName) :
|
||||
qsTr("To view and post in the <b>#%1</b> channel you need to hold").arg(root.channelName)
|
||||
model: d.viewAndPostPermissionsModel
|
||||
}
|
||||
|
||||
HoldingsListPanel {
|
||||
Layout.fillWidth: true
|
||||
spacing: root.spacing
|
||||
visible: !root.joinCommunity && !!d.moderateHoldings
|
||||
introText: qsTr("To moderate in the <b>%1</b> channel you need to hold").arg(root.channelName)
|
||||
model: d.moderateHoldingsModel
|
||||
CustomHoldingsListPanel {
|
||||
visible: !root.joinCommunity && d.moderatePermissionsModel.count > 0
|
||||
introText: qsTr("To moderate in the <b>#%1</b> channel you need to hold").arg(root.channelName)
|
||||
model: d.moderatePermissionsModel
|
||||
}
|
||||
|
||||
StatusButton {
|
||||
|
@ -150,7 +156,7 @@ Control {
|
|||
text: root.isInvitationPending ? d.getInvitationPendingText() : d.getRevealAddressText()
|
||||
icon.name: root.isInvitationPending ? "" : Constants.authenticationIconByType[root.loginType]
|
||||
font.pixelSize: 13
|
||||
enabled: root.requirementsMet || d.communityPermissionsModel.count == 0
|
||||
enabled: root.requirementsMet || d.communityPermissionsModel.count === 0
|
||||
onClicked: root.isInvitationPending ? root.invitationPendingClicked() : root.revealAddressClicked()
|
||||
}
|
||||
|
||||
|
@ -163,4 +169,3 @@ Control {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Core.Utils 0.1
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import utils 1.0
|
||||
|
||||
StatusListView {
|
||||
id: root
|
||||
|
||||
property bool hasPermissions
|
||||
property var uniquePermissionTokenKeys
|
||||
|
||||
// read/write properties
|
||||
property string selectedAirdropAddress: selectedSharedAddresses.length ? selectedSharedAddresses[0] : ""
|
||||
property var selectedSharedAddresses: count ? ModelUtils.modelToFlatArray(model, "address") : []
|
||||
|
||||
leftMargin: d.absLeftMargin
|
||||
topMargin: Style.current.padding
|
||||
rightMargin: Style.current.padding
|
||||
bottomMargin: Style.current.padding
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
// UI
|
||||
readonly property int absLeftMargin: 12
|
||||
|
||||
readonly property ButtonGroup airdropGroup: ButtonGroup {
|
||||
exclusive: true
|
||||
}
|
||||
|
||||
readonly property ButtonGroup addressesGroup: ButtonGroup {
|
||||
exclusive: false
|
||||
}
|
||||
|
||||
function selectFirstAvailableAirdropAddress() {
|
||||
root.selectedAirdropAddress = ModelUtils.modelToFlatArray(root.model, "address").find(address => selectedSharedAddresses.includes(address))
|
||||
}
|
||||
}
|
||||
|
||||
spacing: Style.current.halfPadding
|
||||
delegate: StatusListItem {
|
||||
width: ListView.view.width - ListView.view.leftMargin - ListView.view.rightMargin
|
||||
statusListItemTitle.font.weight: Font.Medium
|
||||
title: model.name
|
||||
tertiaryTitle: !walletAccountAssetsModel.count && root.hasPermissions ? qsTr("No relevant tokens") : ""
|
||||
|
||||
tagsModel: SortFilterProxyModel {
|
||||
id: walletAccountAssetsModel
|
||||
sourceModel: model.assets
|
||||
|
||||
function filterPredicate(modelData) {
|
||||
return root.uniquePermissionTokenKeys.includes(modelData.symbol.toUpperCase())
|
||||
}
|
||||
|
||||
filters: ExpressionFilter {
|
||||
expression: walletAccountAssetsModel.filterPredicate(model)
|
||||
}
|
||||
sorters: ExpressionSorter {
|
||||
expression: {
|
||||
return modelLeft.enabledNetworkBalance.amount > modelRight.enabledNetworkBalance.amount // descending, biggest first
|
||||
}
|
||||
}
|
||||
}
|
||||
statusListItemInlineTagsSlot.spacing: Style.current.padding
|
||||
tagsDelegate: Row {
|
||||
spacing: 4
|
||||
StatusRoundedImage {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 16
|
||||
height: 16
|
||||
image.source: Constants.tokenIcon(model.symbol.toUpperCase())
|
||||
}
|
||||
StatusBaseText {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.pixelSize: Theme.tertiaryTextFontSize
|
||||
text: LocaleUtils.currencyAmountToLocaleString(enabledNetworkBalance)
|
||||
}
|
||||
}
|
||||
|
||||
asset.color: !!model.colorId ? Utils.getColorForId(model.colorId): ""
|
||||
asset.emoji: model.emoji
|
||||
asset.name: !model.emoji ? "filled-account": ""
|
||||
asset.letterSize: 14
|
||||
asset.isLetterIdenticon: !!model.emoji
|
||||
asset.isImage: asset.isLetterIdenticon
|
||||
|
||||
components: [
|
||||
StatusFlatButton {
|
||||
ButtonGroup.group: d.airdropGroup
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
icon.name: "airdrop"
|
||||
icon.color: hovered ? Theme.palette.primaryColor3 :
|
||||
checked ? Theme.palette.primaryColor1 : disabledTextColor
|
||||
checkable: true
|
||||
checked: model.address === root.selectedAirdropAddress
|
||||
enabled: shareAddressCheckbox.checked && root.selectedSharedAddresses.length > 1 // last cannot be unchecked
|
||||
visible: shareAddressCheckbox.checked
|
||||
opacity: enabled ? 1.0 : 0.3
|
||||
onCheckedChanged: if (checked) root.selectedAirdropAddress = model.address
|
||||
|
||||
StatusToolTip {
|
||||
text: qsTr("Use this address for any Community airdrops")
|
||||
visible: parent.hovered
|
||||
delay: 500
|
||||
}
|
||||
},
|
||||
StatusCheckBox {
|
||||
id: shareAddressCheckbox
|
||||
ButtonGroup.group: d.addressesGroup
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checkable: true
|
||||
checked: root.selectedSharedAddresses.includes(model.address)
|
||||
enabled: !(root.selectedSharedAddresses.length === 1 && checked) // last cannot be unchecked
|
||||
onToggled: {
|
||||
// handle selected addresses
|
||||
const index = root.selectedSharedAddresses.indexOf(model.address)
|
||||
const selectedSharedAddressesCopy = Object.assign([], root.selectedSharedAddresses) // deep copy
|
||||
if (index === -1) {
|
||||
selectedSharedAddressesCopy.push(model.address)
|
||||
} else {
|
||||
selectedSharedAddressesCopy.splice(index, 1)
|
||||
}
|
||||
root.selectedSharedAddresses = selectedSharedAddressesCopy
|
||||
|
||||
// switch to next available airdrop address when unchecking
|
||||
if (!checked && model.address === root.selectedAirdropAddress) {
|
||||
d.selectFirstAvailableAirdropAddress()
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
import QtQuick 2.15
|
||||
import QtQml.Models 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtGraphicalEffects 1.15
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Core.Utils 0.1
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import AppLayouts.Profile.controls 1.0
|
||||
import AppLayouts.Communities.controls 1.0
|
||||
import AppLayouts.Communities.views 1.0
|
||||
import AppLayouts.Communities.helpers 1.0
|
||||
|
||||
import utils 1.0
|
||||
|
||||
Control {
|
||||
id: root
|
||||
|
||||
property bool isEditMode
|
||||
|
||||
required property string communityName
|
||||
required property string communityIcon
|
||||
property int loginType: Constants.LoginType.Password
|
||||
|
||||
required property var walletAccountsModel // name, address, emoji, colorId, assets
|
||||
required property var permissionsModel // id, key, permissionType, holdingsListModel, channelsListModel, isPrivate, tokenCriteriaMet
|
||||
required property var assetsModel
|
||||
required property var collectiblesModel
|
||||
|
||||
readonly property string title: isEditMode ? qsTr("Edit which addresses you share with %1").arg(communityName)
|
||||
: qsTr("Select addresses to share with %1").arg(communityName)
|
||||
|
||||
readonly property var buttons: ObjectModel {
|
||||
StatusFlatButton {
|
||||
visible: root.isEditMode
|
||||
borderColor: Theme.palette.baseColor2
|
||||
text: qsTr("Cancel")
|
||||
onClicked: root.close()
|
||||
}
|
||||
StatusButton {
|
||||
enabled: root.selectedSharedAddresses.length && root.selectedAirdropAddress
|
||||
visible: root.isEditMode
|
||||
icon.name: Constants.authenticationIconByType[root.loginType]
|
||||
text: qsTr("Save changes")
|
||||
onClicked: {
|
||||
// TODO connect to backend
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
StatusButton {
|
||||
visible: !root.isEditMode
|
||||
enabled: root.selectedAirdropAddress && root.selectedSharedAddresses.length
|
||||
text: qsTr("Share selected addresses to join")
|
||||
onClicked: {
|
||||
root.shareSelectedAddressesClicked(root.selectedAirdropAddress, root.selectedSharedAddresses)
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
// NB no more buttons after this, see property `rightButtons` below
|
||||
}
|
||||
|
||||
readonly property var rightButtons: [buttons.get(buttons.count-1)] // "magically" used by CommunityIntroDialog StatusStackModal impl
|
||||
|
||||
readonly property string selectedAirdropAddress: accountSelector.selectedAirdropAddress
|
||||
readonly property var selectedSharedAddresses: accountSelector.selectedSharedAddresses
|
||||
|
||||
signal close()
|
||||
signal shareSelectedAddressesClicked(string airdropAddress, var sharedAddresses)
|
||||
|
||||
spacing: Style.current.padding
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
// internal logic
|
||||
readonly property bool hasPermissions: root.permissionsModel && root.permissionsModel.count
|
||||
}
|
||||
|
||||
padding: 0
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
// addresses
|
||||
SharedAddressesAccountSelector {
|
||||
id: accountSelector
|
||||
hasPermissions: d.hasPermissions
|
||||
uniquePermissionTokenKeys: PermissionsHelpers.getUniquePermissionTokenKeys(root.permissionsModel)
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: contentHeight + topMargin + bottomMargin
|
||||
Layout.maximumHeight: hasPermissions ? permissionsView.implicitHeight > root.availableHeight / 2 ? root.availableHeight / 2 : root.availableHeight : -1
|
||||
Layout.fillHeight: !hasPermissions
|
||||
model: SortFilterProxyModel {
|
||||
sourceModel: root.walletAccountsModel
|
||||
filters: ValueFilter {
|
||||
roleName: "walletType"
|
||||
value: Constants.watchWalletType
|
||||
inverted: true
|
||||
}
|
||||
sorters: [
|
||||
ExpressionSorter {
|
||||
function isGenerated(modelData) {
|
||||
return modelData.walletType === Constants.generatedWalletType
|
||||
}
|
||||
|
||||
expression: {
|
||||
return isGenerated(modelLeft)
|
||||
}
|
||||
},
|
||||
RoleSorter {
|
||||
roleName: "position"
|
||||
},
|
||||
RoleSorter {
|
||||
roleName: "name"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// divider with top rounded corners + drop shadow
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Style.current.padding * 2
|
||||
color: Theme.palette.baseColor2
|
||||
radius: Style.current.padding
|
||||
border.width: 1
|
||||
border.color: Theme.palette.baseColor3
|
||||
visible: d.hasPermissions
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: DropShadow {
|
||||
horizontalOffset: 0
|
||||
verticalOffset: -9
|
||||
radius: 14
|
||||
samples: 29
|
||||
color: Qt.rgba(0, 0, 0, 0.04)
|
||||
}
|
||||
}
|
||||
|
||||
// permissions
|
||||
SharedAddressesPermissionsPanel {
|
||||
id: permissionsView
|
||||
permissionsModel: root.permissionsModel
|
||||
assetsModel: root.assetsModel
|
||||
collectiblesModel: root.collectiblesModel
|
||||
communityName: root.communityName
|
||||
communityIcon: root.communityIcon
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: -Style.current.padding // compensate for the half-rounded divider above
|
||||
visible: d.hasPermissions
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,437 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Core.Utils 0.1
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import AppLayouts.Communities.controls 1.0
|
||||
import AppLayouts.Communities.views 1.0
|
||||
import AppLayouts.Communities.helpers 1.0
|
||||
|
||||
import utils 1.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property var permissionsModel
|
||||
property var assetsModel
|
||||
property var collectiblesModel
|
||||
property string communityName
|
||||
property string communityIcon
|
||||
|
||||
implicitHeight: permissionsScrollView.contentHeight - permissionsScrollView.anchors.topMargin
|
||||
color: Theme.palette.baseColor2
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
// UI
|
||||
readonly property int absLeftMargin: 12
|
||||
readonly property color tableBorderColor: Theme.palette.directColor7
|
||||
|
||||
// internal logic
|
||||
readonly property var uniquePermissionChannels:
|
||||
root.permissionsModel && root.permissionsModel.count ?
|
||||
PermissionsHelpers.getUniquePermissionChannels(root.permissionsModel, [PermissionTypes.Type.Read, PermissionTypes.Type.ViewAndPost])
|
||||
: []
|
||||
|
||||
// models
|
||||
readonly property var adminPermissionsModel: SortFilterProxyModel {
|
||||
id: adminPermissionsModel
|
||||
sourceModel: root.permissionsModel
|
||||
function filterPredicate(modelData) {
|
||||
return (modelData.permissionType === Constants.permissionType.admin) &&
|
||||
(modelData.tokenCriteriaMet && !modelData.isPrivate) // admin privs are hidden if criteria not met
|
||||
}
|
||||
filters: ExpressionFilter {
|
||||
expression: adminPermissionsModel.filterPredicate(model)
|
||||
}
|
||||
}
|
||||
readonly property var joinPermissionsModel: SortFilterProxyModel {
|
||||
id: joinPermissionsModel
|
||||
sourceModel: root.permissionsModel
|
||||
function filterPredicate(modelData) {
|
||||
return (modelData.permissionType === Constants.permissionType.member) &&
|
||||
(modelData.tokenCriteriaMet || !modelData.isPrivate)
|
||||
}
|
||||
filters: ExpressionFilter {
|
||||
expression: joinPermissionsModel.filterPredicate(model)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StatusScrollView {
|
||||
id: permissionsScrollView
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: -Style.current.padding
|
||||
contentWidth: availableWidth
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
spacing: Style.current.halfPadding
|
||||
|
||||
// header
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 4
|
||||
spacing: Style.current.padding
|
||||
StatusRoundedImage {
|
||||
Layout.preferredWidth: 40
|
||||
Layout.preferredHeight: 40
|
||||
Layout.leftMargin: d.absLeftMargin
|
||||
image.source: root.communityIcon
|
||||
}
|
||||
StatusBaseText {
|
||||
font.weight: Font.Medium
|
||||
text: qsTr("Permissions")
|
||||
}
|
||||
}
|
||||
|
||||
// permission types
|
||||
PermissionPanel {
|
||||
permissionType: PermissionTypes.Type.Member
|
||||
permissionsModel: d.joinPermissionsModel
|
||||
}
|
||||
PermissionPanel {
|
||||
permissionType: PermissionTypes.Type.Admin
|
||||
permissionsModel: d.adminPermissionsModel
|
||||
}
|
||||
|
||||
Repeater { // channel repeater
|
||||
model: d.uniquePermissionChannels // TODO get channelName in addition (https://github.com/status-im/status-desktop/issues/11481)
|
||||
delegate: ChannelPermissionPanel {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component PanelBg: Rectangle {
|
||||
color: Theme.palette.statusListItem.backgroundColor
|
||||
border.width: 1
|
||||
border.color: Theme.palette.baseColor2
|
||||
radius: Style.current.radius
|
||||
}
|
||||
|
||||
component PanelIcon: StatusRoundIcon {
|
||||
Layout.preferredWidth: 40
|
||||
Layout.preferredHeight: 40
|
||||
Layout.alignment: Qt.AlignTop
|
||||
asset.name: {
|
||||
switch (permissionType) {
|
||||
case PermissionTypes.Type.Admin:
|
||||
return "admin"
|
||||
case PermissionTypes.Type.Member:
|
||||
return "communities"
|
||||
default:
|
||||
return "channel"
|
||||
}
|
||||
}
|
||||
radius: height/2
|
||||
}
|
||||
|
||||
component PanelHeading: StatusBaseText {
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
font.weight: Font.Medium
|
||||
text: {
|
||||
switch (permissionType) {
|
||||
case PermissionTypes.Type.Admin:
|
||||
return qsTr("Become an admin")
|
||||
case PermissionTypes.Type.Member:
|
||||
return qsTr("Join %1").arg(root.communityName)
|
||||
default:
|
||||
return modelData // TODO display channel name https://github.com/status-im/status-desktop/issues/11481
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component SinglePermissionFlow: Flow {
|
||||
width: parent.width
|
||||
spacing: Style.current.halfPadding
|
||||
Repeater {
|
||||
model: HoldingsSelectionModel {
|
||||
sourceModel: model.holdingsListModel
|
||||
assetsModel: root.assetsModel
|
||||
collectiblesModel: root.collectiblesModel
|
||||
}
|
||||
delegate: Row {
|
||||
spacing: 4
|
||||
StatusRoundedImage {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 16
|
||||
height: 16
|
||||
image.source: model.imageSource
|
||||
}
|
||||
StatusBaseText {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.pixelSize: Theme.tertiaryTextFontSize
|
||||
text: model.text
|
||||
color: model.available ? Theme.palette.successColor1 : Theme.palette.directColor1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component PermissionPanel: Control {
|
||||
id: permissionPanel
|
||||
property int permissionType: PermissionTypes.Type.None
|
||||
property var permissionsModel
|
||||
|
||||
readonly property bool tokenCriteriaMet: overallPermissionRow.tokenCriteriaMet
|
||||
|
||||
visible: permissionsModel.count
|
||||
Layout.fillWidth: true
|
||||
padding: d.absLeftMargin
|
||||
background: PanelBg {}
|
||||
contentItem: RowLayout {
|
||||
spacing: Style.current.padding
|
||||
PanelIcon {}
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
PanelHeading {}
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: grid.implicitHeight + grid.anchors.margins*2
|
||||
border.width: 1
|
||||
border.color: d.tableBorderColor
|
||||
radius: Style.current.radius
|
||||
color: "transparent"
|
||||
|
||||
GridLayout {
|
||||
id: grid
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.current.halfPadding
|
||||
rowSpacing: Style.current.halfPadding
|
||||
columnSpacing: Style.current.halfPadding
|
||||
columns: 2
|
||||
|
||||
Repeater {
|
||||
id: permissionsRepeater
|
||||
|
||||
property int revision
|
||||
|
||||
model: permissionPanel.permissionsModel
|
||||
delegate: Column {
|
||||
Layout.column: 0
|
||||
Layout.row: index
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.current.halfPadding
|
||||
|
||||
readonly property bool tokenCriteriaMet: model.tokenCriteriaMet ?? false
|
||||
onTokenCriteriaMetChanged: permissionsRepeater.revision++
|
||||
|
||||
SinglePermissionFlow {}
|
||||
|
||||
Rectangle {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: parent.width + grid.anchors.margins*2
|
||||
height: 1
|
||||
color: d.tableBorderColor
|
||||
visible: index < permissionsRepeater.count - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
id: overallPermissionRow
|
||||
Layout.column: 1
|
||||
Layout.rowSpan: permissionsRepeater.count || 1
|
||||
Layout.preferredWidth: 110
|
||||
Layout.fillHeight: true
|
||||
|
||||
readonly property bool tokenCriteriaMet: {
|
||||
permissionsRepeater.revision // NB no let/const here b/c of https://bugreports.qt.io/browse/QTBUG-91917
|
||||
for (var i = 0; i < permissionsRepeater.count; i++) {
|
||||
var permissionItem = permissionsRepeater.itemAt(i);
|
||||
if (permissionItem.tokenCriteriaMet)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.preferredWidth: 1
|
||||
Layout.fillHeight: true
|
||||
Layout.topMargin: -Style.current.halfPadding
|
||||
Layout.bottomMargin: -Style.current.halfPadding
|
||||
color: d.tableBorderColor
|
||||
}
|
||||
Row {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
StatusIcon {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 16
|
||||
height: 16
|
||||
icon: overallPermissionRow.tokenCriteriaMet ? "tiny/checkmark" : "tiny/secure"
|
||||
color: overallPermissionRow.tokenCriteriaMet ? Theme.palette.successColor1 : Theme.palette.baseColor1
|
||||
}
|
||||
StatusBaseText {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.pixelSize: Theme.tertiaryTextFontSize
|
||||
text: {
|
||||
switch (permissionPanel.permissionType) {
|
||||
case PermissionTypes.Type.Admin:
|
||||
return qsTr("Admin")
|
||||
case PermissionTypes.Type.Member:
|
||||
return qsTr("Join")
|
||||
case PermissionTypes.Type.Read:
|
||||
return qsTr("View only")
|
||||
case PermissionTypes.Type.ViewAndPost:
|
||||
return qsTr("View & post")
|
||||
default:
|
||||
return "???"
|
||||
}
|
||||
}
|
||||
|
||||
color: overallPermissionRow.tokenCriteriaMet ? Theme.palette.directColor1 : Theme.palette.baseColor1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component ChannelPermissionPanel: Control {
|
||||
id: channelPermsPanel
|
||||
Layout.fillWidth: true
|
||||
spacing: 10
|
||||
padding: d.absLeftMargin
|
||||
background: PanelBg {}
|
||||
|
||||
readonly property string channelKey: modelData
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: Style.current.padding
|
||||
PanelIcon {}
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
spacing: Style.current.smallPadding
|
||||
PanelHeading {}
|
||||
Repeater { // permissions repeater
|
||||
model: [PermissionTypes.Type.Read, PermissionTypes.Type.ViewAndPost]
|
||||
|
||||
delegate: Rectangle {
|
||||
id: channelPermsSubPanel
|
||||
|
||||
readonly property int permissionType: modelData
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: grid2.implicitHeight + grid2.anchors.margins*2
|
||||
border.width: 1
|
||||
border.color: d.tableBorderColor
|
||||
radius: Style.current.radius
|
||||
color: "transparent"
|
||||
|
||||
GridLayout {
|
||||
id: grid2
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.current.halfPadding
|
||||
rowSpacing: Style.current.halfPadding
|
||||
columnSpacing: Style.current.halfPadding
|
||||
columns: 2
|
||||
|
||||
Repeater {
|
||||
id: permissionsRepeater2
|
||||
|
||||
property int revision
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: channelPermissionsModel
|
||||
sourceModel: root.permissionsModel
|
||||
function filterPredicate(modelData) {
|
||||
return modelData.permissionType === channelPermsSubPanel.permissionType &&
|
||||
!modelData.isPrivate &&
|
||||
ModelUtils.contains(modelData.channelsListModel, "key", channelPermsPanel.channelKey) // filter and group by channel "key"
|
||||
}
|
||||
filters: ExpressionFilter {
|
||||
expression: channelPermissionsModel.filterPredicate(model)
|
||||
}
|
||||
}
|
||||
delegate: Column {
|
||||
Layout.column: 0
|
||||
Layout.row: index
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.current.halfPadding
|
||||
|
||||
readonly property bool tokenCriteriaMet: model.tokenCriteriaMet ?? false
|
||||
onTokenCriteriaMetChanged: permissionsRepeater2.revision++
|
||||
|
||||
SinglePermissionFlow {}
|
||||
|
||||
Rectangle {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: parent.width + grid2.anchors.margins*2
|
||||
height: 1
|
||||
color: d.tableBorderColor
|
||||
visible: index < permissionsRepeater2.count - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: overallPermissionRow2
|
||||
Layout.column: 1
|
||||
Layout.rowSpan: channelPermissionsModel.count || 1
|
||||
Layout.preferredWidth: 110
|
||||
Layout.fillHeight: true
|
||||
|
||||
readonly property bool tokenCriteriaMet: {
|
||||
permissionsRepeater2.revision
|
||||
for (let i = 0; i < permissionsRepeater2.count; i++) {
|
||||
const permissionItem = permissionsRepeater2.itemAt(i);
|
||||
if (permissionItem.tokenCriteriaMet)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.preferredWidth: 1
|
||||
Layout.fillHeight: true
|
||||
Layout.topMargin: -Style.current.halfPadding
|
||||
Layout.bottomMargin: -Style.current.halfPadding
|
||||
color: d.tableBorderColor
|
||||
}
|
||||
Row {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
StatusIcon {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 16
|
||||
height: 16
|
||||
icon: overallPermissionRow2.tokenCriteriaMet ? "tiny/checkmark" : "tiny/secure"
|
||||
color: overallPermissionRow2.tokenCriteriaMet ? Theme.palette.successColor1 : Theme.palette.baseColor1
|
||||
}
|
||||
StatusBaseText {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.pixelSize: Theme.tertiaryTextFontSize
|
||||
text: {
|
||||
switch (channelPermsSubPanel.permissionType) {
|
||||
case PermissionTypes.Type.Read:
|
||||
return qsTr("View only")
|
||||
case PermissionTypes.Type.ViewAndPost:
|
||||
return qsTr("View & post")
|
||||
case PermissionTypes.Type.Moderator:
|
||||
return qsTr("Moderate")
|
||||
default:
|
||||
return "???"
|
||||
}
|
||||
}
|
||||
|
||||
color: overallPermissionRow2.tokenCriteriaMet ? Theme.palette.directColor1 : Theme.palette.baseColor1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ PrivilegedTokenArtworkPanel 1.0 PrivilegedTokenArtworkPanel.qml
|
|||
ProfilePopupInviteFriendsPanel 1.0 ProfilePopupInviteFriendsPanel.qml
|
||||
ProfilePopupInviteMessagePanel 1.0 ProfilePopupInviteMessagePanel.qml
|
||||
ProfilePopupOverviewPanel 1.0 ProfilePopupOverviewPanel.qml
|
||||
SharedAddressesPanel 1.0 SharedAddressesPanel.qml
|
||||
SortableTokenHoldersList 1.0 SortableTokenHoldersList.qml
|
||||
SortableTokenHoldersPanel 1.0 SortableTokenHoldersPanel.qml
|
||||
TagsPanel 1.0 TagsPanel.qml
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
import QtQuick 2.15
|
||||
|
||||
import StatusQ.Popups.Dialog 0.1
|
||||
|
||||
import AppLayouts.Communities.panels 1.0
|
||||
|
||||
import utils 1.0
|
||||
|
||||
StatusDialog {
|
||||
id: root
|
||||
|
||||
property bool isEditMode
|
||||
|
||||
required property string communityName
|
||||
required property string communityIcon
|
||||
property int loginType: Constants.LoginType.Password
|
||||
|
||||
required property var walletAccountsModel // name, address, emoji, colorId, assets
|
||||
required property var permissionsModel // id, key, permissionType, holdingsListModel, channelsListModel, isPrivate, tokenCriteriaMet
|
||||
required property var assetsModel
|
||||
required property var collectiblesModel
|
||||
|
||||
readonly property string selectedAirdropAddress: panel.selectedAirdropAddress
|
||||
readonly property var selectedSharedAddresses: panel.selectedSharedAddresses
|
||||
|
||||
signal shareSelectedAddressesClicked(string airdropAddress, var sharedAddresses)
|
||||
|
||||
title: panel.title
|
||||
implicitWidth: 640 // by design
|
||||
padding: 0
|
||||
|
||||
contentItem: SharedAddressesPanel {
|
||||
id: panel
|
||||
isEditMode: root.isEditMode
|
||||
communityName: root.communityName
|
||||
communityIcon: root.communityIcon
|
||||
loginType: root.loginType
|
||||
walletAccountsModel: root.walletAccountsModel
|
||||
permissionsModel: root.permissionsModel
|
||||
assetsModel: root.assetsModel
|
||||
collectiblesModel: root.collectiblesModel
|
||||
onShareSelectedAddressesClicked: root.shareSelectedAddressesClicked(airdropAddress, sharedAddresses)
|
||||
onClose: root.close()
|
||||
}
|
||||
|
||||
footer: StatusDialogFooter {
|
||||
spacing: Style.current.padding
|
||||
rightButtons: panel.buttons
|
||||
}
|
||||
}
|
|
@ -16,3 +16,4 @@ RemotelyDestructPopup 1.0 RemotelyDestructPopup.qml
|
|||
SignMultiTokenTransactionsPopup 1.0 SignMultiTokenTransactionsPopup.qml
|
||||
SignTokenTransactionsPopup 1.0 SignTokenTransactionsPopup.qml
|
||||
TransferOwnershipPopup 1.0 TransferOwnershipPopup.qml
|
||||
SharedAddressesPopup 1.0 SharedAddressesPopup.qml
|
||||
|
|
|
@ -20,6 +20,7 @@ import shared.views.chat 1.0
|
|||
|
||||
import AppLayouts.Communities.popups 1.0
|
||||
import AppLayouts.Communities.panels 1.0
|
||||
import AppLayouts.Wallet.stores 1.0 as WalletStore
|
||||
|
||||
// FIXME: Rework me to use ColumnLayout instead of anchors!!
|
||||
Item {
|
||||
|
@ -126,10 +127,15 @@ Item {
|
|||
introMessage: communityData.introMessage
|
||||
imageSrc: communityData.image
|
||||
accessType: communityData.access
|
||||
loginType: root.store.loginType
|
||||
walletAccountsModel: WalletStore.RootStore.receiveAccounts
|
||||
permissionsModel: root.store.permissionsStore.permissionsModel
|
||||
assetsModel: root.store.assetsModel
|
||||
collectiblesModel: root.store.collectiblesModel
|
||||
|
||||
onJoined: {
|
||||
joinCommunityButton.loading = true
|
||||
root.store.requestToJoinCommunityWithAuthentication(root.store.userProfileInst.name)
|
||||
root.store.requestToJoinCommunityWithAuthentication(root.store.userProfileInst.name, sharedAddresses, airdropAddress)
|
||||
}
|
||||
onCancelMembershipRequest: {
|
||||
root.store.cancelPendingRequest(communityData.id)
|
||||
|
|
|
@ -18,6 +18,8 @@ import SortFilterProxyModel 0.2
|
|||
import "../panels"
|
||||
import AppLayouts.Communities.popups 1.0
|
||||
import AppLayouts.Communities.panels 1.0
|
||||
import AppLayouts.Wallet.stores 1.0 as WalletStore
|
||||
import AppLayouts.Chat.stores 1.0 as ChatStore
|
||||
|
||||
SettingsContentBase {
|
||||
id: root
|
||||
|
@ -208,22 +210,23 @@ SettingsContentBase {
|
|||
|
||||
property string communityId
|
||||
|
||||
readonly property var chatCommunitySectionModule: {
|
||||
root.rootStore.mainModuleInst.prepareCommunitySectionModuleForCommunityId(communityIntroDialog.communityId)
|
||||
return root.rootStore.mainModuleInst.getCommunitySectionModule()
|
||||
readonly property var chatStore: ChatStore.RootStore {
|
||||
chatCommunitySectionModule: {
|
||||
root.rootStore.mainModuleInst.prepareCommunitySectionModuleForCommunityId(communityIntroDialog.communityId)
|
||||
return root.rootStore.mainModuleInst.getCommunitySectionModule()
|
||||
}
|
||||
}
|
||||
|
||||
onJoined: {
|
||||
chatCommunitySectionModule.requestToJoinCommunityWithAuthentication(root.rootStore.userProfileInst.name)
|
||||
}
|
||||
loginType: chatStore.loginType
|
||||
walletAccountsModel: WalletStore.RootStore.receiveAccounts
|
||||
permissionsModel: chatStore.permissionsStore.permissionsModel
|
||||
assetsModel: chatStore.assetsModel
|
||||
collectiblesModel: chatStore.collectiblesModel
|
||||
|
||||
onCancelMembershipRequest: {
|
||||
root.rootStore.cancelPendingRequest(communityIntroDialog.communityId)
|
||||
}
|
||||
onJoined: chatStore.requestToJoinCommunityWithAuthentication(root.rootStore.userProfileInst.name, JSON.stringify(sharedAddresses), airdropAddress)
|
||||
onCancelMembershipRequest: root.rootStore.cancelPendingRequest(communityIntroDialog.communityId)
|
||||
|
||||
onClosed: {
|
||||
destroy()
|
||||
}
|
||||
onClosed: destroy()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import QtQuick 2.14
|
||||
import QtQuick.Controls 2.14
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQml.Models 2.14
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import utils 1.0
|
||||
|
||||
|
@ -9,9 +8,14 @@ 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.Popups 0.1
|
||||
import StatusQ.Core.Utils 0.1
|
||||
|
||||
StatusDialog {
|
||||
import AppLayouts.Communities.panels 1.0
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
StatusStackModal {
|
||||
id: root
|
||||
|
||||
property string name
|
||||
|
@ -19,74 +23,131 @@ StatusDialog {
|
|||
property int accessType
|
||||
property url imageSrc
|
||||
property bool isInvitationPending: false
|
||||
property int loginType: Constants.LoginType.Password
|
||||
|
||||
signal joined
|
||||
signal cancelMembershipRequest
|
||||
required property var walletAccountsModel // name, address, emoji, colorId
|
||||
required property var permissionsModel // id, key, permissionType, holdingsListModel, channelsListModel, isPrivate, tokenCriteriaMet
|
||||
required property var assetsModel
|
||||
required property var collectiblesModel
|
||||
|
||||
signal joined(string airdropAddress, var sharedAddresses)
|
||||
signal cancelMembershipRequest()
|
||||
|
||||
width: 640 // by design
|
||||
padding: 0
|
||||
title: qsTr("Welcome to %1").arg(name)
|
||||
stackTitle: root.accessType === Constants.communityChatOnRequestAccess ? qsTr("Request to join %1").arg(name) : qsTr("Welcome to %1").arg(name)
|
||||
|
||||
footer: StatusDialogFooter {
|
||||
rightButtons: ObjectModel {
|
||||
StatusButton {
|
||||
text: root.isInvitationPending ? qsTr("Cancel Membership Request")
|
||||
: (root.accessType === Constants.communityChatOnRequestAccess
|
||||
? qsTr("Request to join %1").arg(root.name)
|
||||
: qsTr("Join %1").arg(root.name) )
|
||||
type: root.isInvitationPending ? StatusBaseButton.Type.Danger
|
||||
: StatusBaseButton.Type.Normal
|
||||
enabled: checkBox.checked || root.isInvitationPending
|
||||
onClicked: {
|
||||
if (root.isInvitationPending) {
|
||||
root.cancelMembershipRequest()
|
||||
} else {
|
||||
root.joined()
|
||||
rightButtons: [d.shareButton, finishButton]
|
||||
|
||||
finishButton: StatusButton {
|
||||
text: root.isInvitationPending ? qsTr("Cancel Membership Request")
|
||||
: (root.accessType === Constants.communityChatOnRequestAccess
|
||||
? qsTr("Share your addresses to join")
|
||||
: qsTr("Join %1").arg(root.name) )
|
||||
type: root.isInvitationPending ? StatusBaseButton.Type.Danger
|
||||
: StatusBaseButton.Type.Normal
|
||||
icon.name: root.accessType === Constants.communityChatOnRequestAccess && !root.isInvitationPending ? Constants.authenticationIconByType[root.loginType] : ""
|
||||
onClicked: {
|
||||
if (root.isInvitationPending) {
|
||||
root.cancelMembershipRequest()
|
||||
} else {
|
||||
root.joined(d.selectedAirdropAddress, d.selectedSharedAddresses)
|
||||
}
|
||||
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
readonly property var tempAddressesModel: SortFilterProxyModel {
|
||||
sourceModel: root.walletAccountsModel
|
||||
filters: [
|
||||
ValueFilter {
|
||||
roleName: "walletType"
|
||||
value: Constants.watchWalletType
|
||||
inverted: true
|
||||
}
|
||||
]
|
||||
sorters: [
|
||||
ExpressionSorter {
|
||||
function isGenerated(modelData) {
|
||||
return modelData.walletType === Constants.generatedWalletType
|
||||
}
|
||||
|
||||
root.close()
|
||||
expression: {
|
||||
return isGenerated(modelLeft)
|
||||
}
|
||||
},
|
||||
RoleSorter {
|
||||
roleName: "position"
|
||||
},
|
||||
RoleSorter {
|
||||
roleName: "name"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// all non-watched addresses by default, unless selected otherwise below in SharedAddressesPanel
|
||||
property var selectedSharedAddresses: tempAddressesModel.count ? ModelUtils.modelToFlatArray(tempAddressesModel, "address") : []
|
||||
property string selectedAirdropAddress: selectedSharedAddresses.length ? selectedSharedAddresses[0] : ""
|
||||
|
||||
readonly property var shareButton: StatusFlatButton {
|
||||
height: finishButton.height
|
||||
visible: !root.isInvitationPending && !root.replaceItem
|
||||
borderColor: Theme.palette.baseColor2
|
||||
text: qsTr("Select addresses to share")
|
||||
onClicked: root.replace(sharedAddressesPanelComponent)
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: sharedAddressesPanelComponent
|
||||
SharedAddressesPanel {
|
||||
communityName: root.name
|
||||
communityIcon: root.imageSrc
|
||||
loginType: root.loginType
|
||||
walletAccountsModel: root.walletAccountsModel
|
||||
permissionsModel: root.permissionsModel
|
||||
assetsModel: root.assetsModel
|
||||
collectiblesModel: root.collectiblesModel
|
||||
onShareSelectedAddressesClicked: {
|
||||
d.selectedAirdropAddress = airdropAddress
|
||||
d.selectedSharedAddresses = sharedAddresses
|
||||
root.replaceItem = undefined // go back, unload us
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stackItems: [
|
||||
StatusScrollView {
|
||||
id: scrollView
|
||||
contentWidth: availableWidth
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 24
|
||||
width: scrollView.availableWidth
|
||||
|
||||
StatusRoundedImage {
|
||||
id: roundImage
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.preferredHeight: 64
|
||||
Layout.preferredWidth: Layout.preferredHeight
|
||||
visible: image.status == Image.Loading || image.status == Image.Ready
|
||||
image.source: root.imageSrc
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
id: introText
|
||||
|
||||
Layout.fillWidth: true
|
||||
text: root.introMessage || qsTr("Community <b>%1</b> has no intro message...").arg(root.name)
|
||||
color: Theme.palette.directColor1
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StatusScrollView {
|
||||
id: scrollView
|
||||
anchors.fill: parent
|
||||
implicitWidth: 640 // by design
|
||||
contentWidth: availableWidth
|
||||
|
||||
ColumnLayout {
|
||||
id: columnContent
|
||||
|
||||
spacing: 24
|
||||
width: scrollView.availableWidth
|
||||
|
||||
StatusRoundedImage {
|
||||
id: roundImage
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.preferredHeight: 64
|
||||
Layout.preferredWidth: Layout.preferredHeight
|
||||
visible: image.status == Image.Loading || image.status == Image.Ready
|
||||
image.source: root.imageSrc
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
id: introText
|
||||
|
||||
Layout.fillWidth: true
|
||||
text: root.introMessage !== "" ? root.introMessage : qsTr("Community <b>%1</b> has no intro message...").arg(root.name)
|
||||
color: Theme.palette.directColor1
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
StatusCheckBox {
|
||||
id: checkBox
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
visible: !root.isInvitationPending
|
||||
text: qsTr("I agree with the above")
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -54,7 +54,6 @@ QtObject {
|
|||
return (modelData.permissionType == Constants.permissionType.viewAndPost) &&
|
||||
root.permissionsModel.belongsToChat(modelData.id, root.activeChannelId) &&
|
||||
(modelData.tokenCriteriaMet || !modelData.isPrivate)
|
||||
|
||||
}
|
||||
filters: [
|
||||
ExpressionFilter {
|
||||
|
|
|
@ -987,7 +987,8 @@ QtObject {
|
|||
enum TokenType {
|
||||
Unknown = 0,
|
||||
ERC20 = 1, // Asset
|
||||
ERC721 = 2 // Collectible
|
||||
ERC721 = 2, // Collectible
|
||||
ENS = 3
|
||||
}
|
||||
|
||||
// Mirrors src/backend/activity.nim ActivityStatus
|
||||
|
|
|
@ -24,7 +24,7 @@ QtObject {
|
|||
}
|
||||
|
||||
function startsWith0x(value) {
|
||||
return value.startsWith('0x')
|
||||
return !!value && value.startsWith('0x')
|
||||
}
|
||||
|
||||
function isChatKey(value) {
|
||||
|
@ -248,8 +248,8 @@ QtObject {
|
|||
* Returns text in the format "✓ 12 words" for seed phrases input boxes
|
||||
*/
|
||||
function seedPhraseWordCountText(text) {
|
||||
let wordCount = countWords(text);
|
||||
return getTick(wordCount) + wordCount.toString() + " " + qsTr("words")
|
||||
const wordCount = countWords(text);
|
||||
return getTick(wordCount) + qsTr("%n word(s)", "", wordCount)
|
||||
}
|
||||
|
||||
function uuid() {
|
||||
|
@ -288,7 +288,7 @@ QtObject {
|
|||
} else if (!/^\d+$/.test(firstPINField.pinInput)) {
|
||||
return [false, qsTr("The PIN must contain only digits")];
|
||||
} else if (firstPINField.pinInput.length != Constants.keycard.general.keycardPinLength) {
|
||||
return [false, qsTr("The PIN must be exactly %1 digits").arg(Constants.keycard.general.keycardPinLength)];
|
||||
return [false, qsTr("The PIN must be exactly %n digit(s)", "", Constants.keycard.general.keycardPinLength)];
|
||||
}
|
||||
return [true, ""];
|
||||
|
||||
|
@ -296,7 +296,7 @@ QtObject {
|
|||
if (repeatPINField.pinInput === "") {
|
||||
return [false, qsTr("You need to repeat your PIN")];
|
||||
} else if (repeatPINField.pinInput !== firstPINField.pinInput) {
|
||||
return [false, qsTr("PIN don't match")];
|
||||
return [false, qsTr("PINs don't match")];
|
||||
}
|
||||
return [true, ""];
|
||||
|
||||
|
@ -373,7 +373,7 @@ QtObject {
|
|||
}
|
||||
|
||||
if(validation & Utils.Validate.TextLength && str.length > limit) {
|
||||
errMsg = qsTr("The %1 cannot exceed %2 characters").arg(fieldName, limit)
|
||||
errMsg = qsTr("The %1 cannot exceed %n character(s)", "", limit).arg(fieldName)
|
||||
}
|
||||
|
||||
if(validation & Utils.Validate.TextHexColor && !isHexColor(str)) {
|
||||
|
@ -392,7 +392,7 @@ QtObject {
|
|||
if (errors.minLength) {
|
||||
return errors.minLength.min === 1 ?
|
||||
qsTr("You need to enter a %1").arg(fieldName) :
|
||||
qsTr("Value has to be at least %1 characters long").arg(errors.minLength.min)
|
||||
qsTr("Value has to be at least %n character(s) long", "", errors.minLength.min)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
|
@ -657,7 +657,7 @@ QtObject {
|
|||
// special handling because on an index attached to the constant
|
||||
if (key.startsWith(Constants.appTranslatableConstants.keycardAccountNameOfUnknownWalletAccount)) {
|
||||
let num = key.substring(Constants.appTranslatableConstants.keycardAccountNameOfUnknownWalletAccount.length)
|
||||
return "%1%2".arg(qsTr("acc")).arg(num) //short name of an unknown (removed) wallet account
|
||||
return "%1%2".arg(qsTr("acc", "short for account")).arg(num) //short name of an unknown (removed) wallet account
|
||||
}
|
||||
|
||||
return key
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 6a471f1bef1288407751400d93b12b7fa911474d
|
||||
Subproject commit 70b76297fd074b4adda5e659d260c8cc18e51ef9
|
Loading…
Reference in New Issue