diff --git a/src/app/global/local_account_sensitive_settings.nim b/src/app/global/local_account_sensitive_settings.nim
index 6fa33a5d8e..4da0242ef8 100644
--- a/src/app/global/local_account_sensitive_settings.nim
+++ b/src/app/global/local_account_sensitive_settings.nim
@@ -8,6 +8,8 @@ const LSS_KEY_WALLET_SPLIT_VIEW* = "walletSplitView"
const LSS_KEY_PROFILE_SPLIT_VIEW* = "profileSplitView"
const LSS_KEY_IS_WALLET_ENABLED* = "isExperimentalWalletEnabled"
const DEFAULT_IS_WALLET_ENABLED = false
+const LSS_KEY_IS_COMMUNITY_PERMISSIONS_ENABLED* = "isExperimentalCommunityPermissionsEnabled"
+const DEFAULT_IS_COMMUNITY_PERMISSIONS_ENABLED = false
const LSS_KEY_NODE_MANAGEMENT_ENABLED* = "nodeManagementEnabled"
const DEFAULT_NODE_MANAGEMENT_ENABLED = false
const LSS_KEY_IS_BROWSER_ENABLED* = "isExperimentalBrowserEnabled"
@@ -191,6 +193,18 @@ QtObject:
write = setProfileSplitView
notify = profileSplitViewChanged
+ proc isCommunityPermissionsEnabledChanged*(self: LocalAccountSensitiveSettings) {.signal.}
+ proc getIsCommunityPermissionsEnabled*(self: LocalAccountSensitiveSettings): bool {.slot.} =
+ getSettingsProp[bool](self, LSS_KEY_IS_COMMUNITY_PERMISSIONS_ENABLED, newQVariant(DEFAULT_IS_COMMUNITY_PERMISSIONS_ENABLED))
+ proc setIsCommunityPermissionsEnabled*(self: LocalAccountSensitiveSettings, value: bool) {.slot.} =
+ setSettingsProp(self, LSS_KEY_IS_COMMUNITY_PERMISSIONS_ENABLED, newQVariant(value)):
+ self.isCommunityPermissionsEnabledChanged()
+
+ QtProperty[bool] isCommunityPermissionsEnabled:
+ read = getIsCommunityPermissionsEnabled
+ write = setIsCommunityPermissionsEnabled
+ notify = isCommunityPermissionsEnabledChanged
+
proc isWalletEnabledChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getIsWalletEnabled*(self: LocalAccountSensitiveSettings): bool {.slot.} =
getSettingsProp[bool](self, LSS_KEY_IS_WALLET_ENABLED, newQVariant(DEFAULT_IS_WALLET_ENABLED))
@@ -740,6 +754,7 @@ QtObject:
of LSS_KEY_WALLET_SPLIT_VIEW: self.walletSplitViewChanged()
of LSS_KEY_PROFILE_SPLIT_VIEW: self.profileSplitViewChanged()
of LSS_KEY_IS_WALLET_ENABLED: self.isWalletEnabledChanged()
+ of LSS_KEY_IS_COMMUNITY_PERMISSIONS_ENABLED: self.isCommunityPermissionsEnabledChanged()
of LSS_KEY_NODE_MANAGEMENT_ENABLED: self.nodeManagementEnabledChanged()
of LSS_KEY_IS_BROWSER_ENABLED: self.isBrowserEnabledChanged()
of LSS_KEY_SHOW_ONLINE_USERS: self.showOnlineUsersChanged()
diff --git a/ui/app/AppLayouts/Chat/controls/community/HoldingsDropdown.qml b/ui/app/AppLayouts/Chat/controls/community/HoldingsDropdown.qml
new file mode 100644
index 0000000000..d253148596
--- /dev/null
+++ b/ui/app/AppLayouts/Chat/controls/community/HoldingsDropdown.qml
@@ -0,0 +1,277 @@
+import QtQuick 2.13
+import QtQuick.Layouts 1.14
+import QtQuick.Controls 2.13
+import QtGraphicalEffects 1.13
+
+import StatusQ.Core 0.1
+import StatusQ.Core.Theme 0.1
+import StatusQ.Components 0.1
+import StatusQ.Controls 0.1
+import StatusQ.Controls.Validators 0.1
+import StatusQ.Core.Utils 0.1 as SQ
+
+import utils 1.0
+
+StatusDropdown {
+ id: root
+
+ property real tokenAmountValue: 0
+ property string tokenName: d.defaultTokenNameText
+ property url tokenImage: ""
+ property int operator: SQ.Utils.Operators.None
+ property bool withOperatorSelector: true
+
+ signal addToken(string tokenText, url tokenImage, int operator)
+
+ function reset() {
+ root.tokenAmountValue = 0
+ root.tokenName = d.defaultTokenNameText
+ root.tokenImage = ""
+ root.operator = SQ.Utils.Operators.None
+ }
+
+ QtObject {
+ id: d
+
+ readonly property bool ready: root.tokenAmountValue > 0 && root.tokenName !== d.defaultTokenNameText
+
+ // By design values:
+ readonly property int initialHeight: 232
+ readonly property int mainHeight: 256
+ readonly property int operatorsHeight: 96
+ readonly property int extendedHeight: 417
+ readonly property int defaultWidth: 289
+ readonly property int operatorsWidth: 159
+
+ property string defaultTokenNameText: qsTr("Choose token")
+
+ function selectInitState() {
+ if(root.withOperatorSelector)
+ loader.sourceComponent = operatorsSelectorView
+ else
+ loader.sourceComponent = tabsView
+ }
+ }
+
+ width: d.defaultWidth
+ height: d.initialHeight
+
+ contentItem: Loader {
+ id: loader
+ anchors.fill: parent
+ sourceComponent: root.withOperatorSelector ? operatorsSelectorView : tabsView
+
+ onSourceComponentChanged: {
+ if(sourceComponent == tokensExtendedView) {
+ root.height = Math.min(item.contentHeight + item.anchors.topMargin + item.anchors.bottomMargin, d.extendedHeight)
+ root.width = d.defaultWidth
+ }
+ else if(sourceComponent == operatorsSelectorView) {
+ root.height = d.operatorsHeight
+ root.width = d.operatorsWidth
+ }
+ else if(sourceComponent == tabsView && root.withOperatorSelector) {
+ root.height = d.mainHeight
+ root.width = d.defaultWidth
+ }
+ else if(sourceComponent == tabsView && !root.withOperatorSelector) {
+ root.height = d.initialHeight
+ root.width = d.defaultWidth
+ }
+ }
+ }
+
+ onOpened: d.selectInitState()
+ onClosed: root.reset()
+ onWithOperatorSelectorChanged: d.selectInitState()
+
+ Component {
+ id: tabsView
+
+ ColumnLayout {
+ anchors.fill: parent
+ anchors.margins: 8
+ anchors.topMargin: 16
+ spacing: 8
+ StatusIconTextButton {
+ visible: root.withOperatorSelector
+ Layout.leftMargin: 8
+ spacing: 0
+ statusIcon: "next"
+ icon.width: 12
+ icon.height: 12
+ iconRotation: 180
+ text: qsTr("Back")
+ onClicked: loader.sourceComponent = operatorsSelectorView
+ }
+ StatusSwitchTabBar {
+ id: tabBar
+ Layout.preferredWidth: 273 // by design
+ Layout.preferredHeight: 36 // by design
+ StatusSwitchTabButton {
+ text: qsTr("Token")
+ fontPixelSize: 13
+ }
+ StatusSwitchTabButton {
+ text: qsTr("Collectibles")
+ fontPixelSize: 13
+ enabled: false // TODO
+ }
+ StatusSwitchTabButton {
+ text: qsTr("ENS")
+ fontPixelSize: 13
+ enabled: false // TODO
+ }
+ }
+ StackLayout {
+ Layout.fillWidth: true
+ currentIndex: tabBar.currentIndex
+ // Tokens layout definition:
+ ColumnLayout {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ StatusPickerButton {
+ Layout.fillWidth: true
+ Layout.topMargin: 8
+ Layout.preferredHeight: 36
+ bgColor: Theme.palette.baseColor5
+ contentColor: Theme.palette.directColor1
+ text: root.tokenName
+ font.pixelSize: 13
+ image.source: root.tokenImage
+ onClicked: loader.sourceComponent = tokensExtendedView
+ }
+
+ StatusInput {
+ Layout.fillWidth: true
+ minimumHeight: 36
+ maximumHeight: 36
+ topPadding: 0
+ bottomPadding: 0
+ text: root.tokenAmountValue == 0 ? "" : root.tokenAmountValue.toString()
+ font.pixelSize: 13
+ rightPadding: amountText.implicitWidth + amountText.anchors.rightMargin + leftPadding
+ input.placeholderText: "0"
+ validationMode: StatusInput.ValidationMode.IgnoreInvalidInput
+ validators: StatusFloatValidator { bottom: 0 }
+
+ StatusBaseText {
+ id: amountText
+ anchors.right: parent.right
+ anchors.rightMargin: 13
+ anchors.verticalCenter: parent.verticalCenter
+ text: qsTr("Amount")
+ color: Theme.palette.baseColor1
+ font.pixelSize: 13
+ }
+ onTextChanged: root.tokenAmountValue = Number(text)
+ }
+
+ // Just a filler
+ Item { Layout.fillHeight: true}
+
+ StatusButton {
+ enabled: d.ready
+ text: qsTr("Add")
+ height: 44
+ Layout.alignment: Qt.AlignHCenter
+ Layout.fillWidth: true
+ onClicked: { root.addToken(root.tokenAmountValue.toString() + " " + root.tokenName, root.tokenImage, root.operator) }
+ }
+ } // End of Tokens Layout definition
+
+ // TODO
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+
+ // TODO
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+ }
+ }
+ }
+
+ Component {
+ id: operatorsSelectorView
+ ColumnLayout {
+ anchors.fill: parent
+ anchors.margins: 8
+ StatusPickerButton {
+ Layout.fillWidth: true
+ Layout.preferredHeight: 36
+ horizontalPadding: 12
+ spacing: 10
+ bgColor: Theme.palette.primaryColor3
+ contentColor: Theme.palette.primaryColor1
+ image.source: Style.svg("add")
+ text: qsTr("And...")
+ image.height: 12
+ image.width: 12
+ font.pixelSize: 13
+ onClicked: {
+ root.operator = SQ.Utils.Operators.And
+ loader.sourceComponent = tabsView
+ }
+ }
+ StatusPickerButton {
+ Layout.fillWidth: true
+ Layout.preferredHeight: 36
+ horizontalPadding: 12
+ spacing: 10
+ bgColor: Theme.palette.primaryColor3
+ contentColor: Theme.palette.primaryColor1
+ image.source: Style.svg("condition-Or")
+ image.height: 12
+ image.width: 12
+ text: qsTr("Or...")
+ font.pixelSize: 13
+ onClicked: {
+ root.operator = SQ.Utils.Operators.Or
+ loader.sourceComponent = tabsView
+ }
+ }
+ }
+ }
+
+ Component {
+ id: tokensExtendedView
+
+ // TODO: It probabily will be a reusable component for collectibles and channels
+ TokensListDropdownContent {
+ anchors.fill: parent
+ anchors.topMargin: 8
+ anchors.bottomMargin: 8
+ headerModel: ListModel {
+ ListElement { index: 0; icon: "next"; iconSize: 12; description: qsTr("Back"); rotation: 180; spacing: 0 }
+ ListElement { index: 1; icon: "add"; iconSize: 16; description: qsTr("Mint token"); rotation: 0; spacing: 8 }
+ ListElement { index: 2; icon: "invite-users"; iconSize: 16; description: qsTr("Import existing token"); rotation: 180; spacing: 8 }
+ }
+ // TODO: Replace to real data, now dummy model
+ model: ListModel {
+ ListElement {imageSource: "qrc:imports/assets/png/tokens/SOCKS.png"; name: "Unisocks"; shortName: "SOCKS"; selected: false; category: "Community tokens"}
+ ListElement {imageSource: "qrc:imports/assets/png/tokens/ZRX.png"; name: "Ox"; shortName: "ZRX"; selected: false; category: "Listed tokens"}
+ ListElement {imageSource: "qrc:imports/assets/png/tokens/CUSTOM-TOKEN.png"; name: "1inch"; shortName: "ZRX"; selected: false; category: "Listed tokens"}
+ ListElement {imageSource: "qrc:imports/assets/png/tokens/CUSTOM-TOKEN.png"; name: "Aave"; shortName: "AAVE"; selected: false; category: "Listed tokens"}
+ ListElement {imageSource: "qrc:imports/assets/png/tokens/CUSTOM-TOKEN.png"; name: "Amp"; shortName: "AMP"; selected: false; category: "Listed tokens"}
+ }
+ onHeaderItemClicked: {
+ if(index === 0) loader.sourceComponent = tabsView // Go back
+ // TODO:
+ else if(index === 1) console.log("TODO: Mint token")
+ else if(index === 2) console.log("TODO: Import existing token")
+ }
+ onItemClicked: {
+ // Go back
+ loader.sourceComponent = tabsView
+
+ // Update new token info
+ root.tokenName = shortName
+ root.tokenImage = imageSource
+ }
+ }
+ }
+}
diff --git a/ui/app/AppLayouts/Chat/controls/community/TokensListDropdownContent.qml b/ui/app/AppLayouts/Chat/controls/community/TokensListDropdownContent.qml
new file mode 100644
index 0000000000..0b70251cd0
--- /dev/null
+++ b/ui/app/AppLayouts/Chat/controls/community/TokensListDropdownContent.qml
@@ -0,0 +1,113 @@
+import QtQuick 2.13
+import QtQuick.Layouts 1.14
+import QtQuick.Controls 2.13
+import QtGraphicalEffects 1.13
+
+import StatusQ.Core 0.1
+import StatusQ.Core.Theme 0.1
+import StatusQ.Controls 0.1
+import StatusQ.Components 0.1
+
+
+StatusListView {
+ id: root
+
+ property var headerModel
+
+ signal headerItemClicked(int index)
+ signal itemClicked(string name, string shortName, url imageSource)
+
+ implicitWidth: 273
+ currentIndex: -1
+ clip: true
+ headerPositioning: ListView.OverlayHeader
+ header: Rectangle {
+ z: 3 // Above delegate (z=1) and above section.delegate (z = 2)
+ color: Theme.palette.statusPopupMenu.backgroundColor
+ width: root.width
+ height: columnHeader.implicitHeight + 2 * columnHeader.anchors.topMargin
+ ColumnLayout {
+ id: columnHeader
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.leftMargin: 16
+ anchors.rightMargin: anchors.leftMargin
+ anchors.topMargin: 8
+ anchors.bottomMargin: 2 * anchors.topMargin
+ spacing: 20
+ Repeater {
+ model: root.headerModel
+ delegate: StatusIconTextButton {
+ z: 3 // Above delegate (z=1) and above section.delegate (z = 2)
+ spacing: model.spacing
+ statusIcon: model.icon
+ icon.width: model.iconSize
+ icon.height: model.iconSize
+ iconRotation: model.rotation
+ text: model.description
+ onClicked: root.headerItemClicked(model.index)
+ }
+ }
+ }
+ }// End of Header
+ delegate: Rectangle {
+ width: ListView.view.width
+ height: 44 // by design
+ color: mouseArea.containsMouse ? Theme.palette.baseColor4 : "transparent"
+ RowLayout {
+ anchors.fill: parent
+ anchors.leftMargin: 14
+ spacing: 8
+ StatusRoundedImage {
+ Layout.alignment: Qt.AlignVCenter
+ image.source: model.imageSource
+ visible: model.imageSource.toString() !== ""
+ Layout.preferredWidth: 28
+ Layout.preferredHeight: Layout.preferredWidth
+ }
+ ColumnLayout {
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignVCenter
+ spacing: 0
+ StatusBaseText {
+ Layout.fillWidth: true
+ text: model.name
+ color: Theme.palette.directColor1
+ font.pixelSize: 13
+ clip: true
+ elide: Text.ElideRight
+ }
+ StatusBaseText {
+ Layout.fillWidth: true
+ text: model.shortName
+ color: Theme.palette.baseColor1
+ font.pixelSize: 12
+ clip: true
+ elide: Text.ElideRight
+ }
+ }
+ }
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ cursorShape: Qt.PointingHandCursor
+ hoverEnabled: true
+ onClicked: { root.itemClicked(model.name, model.shortName, model.imageSource) }
+ }
+ }// End of Item
+ section.property: "category"
+ section.criteria: ViewSection.FullString
+ section.delegate: Item {
+ width: ListView.view.width
+ height: 34 // by design
+ StatusBaseText {
+ anchors.leftMargin: 18
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ text: section
+ color: Theme.palette.baseColor1
+ font.pixelSize: 12
+ elide: Text.ElideRight
+ }
+ }// End of Category item
+}// End of Root
diff --git a/ui/app/AppLayouts/Chat/layouts/SettingsPageLayout.qml b/ui/app/AppLayouts/Chat/layouts/SettingsPageLayout.qml
index 6434077400..01fdab803d 100644
--- a/ui/app/AppLayouts/Chat/layouts/SettingsPageLayout.qml
+++ b/ui/app/AppLayouts/Chat/layouts/SettingsPageLayout.qml
@@ -5,6 +5,8 @@ import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
+import utils 1.0
+import shared.panels 1.0
import shared.popups 1.0
Item {
@@ -44,24 +46,18 @@ Item {
id: layout
anchors.fill: parent
-
spacing: 16
- Item {
+ StatusIconTextButton {
implicitHeight: 32
-
- StatusBaseText {
- visible: root.previousPage
- text: "<- " + root.previousPage
- color: Theme.palette.primaryColor1
- font.pixelSize: 15
-
- MouseArea {
- anchors.fill: parent
- cursorShape: Qt.PointingHandCursor
- onClicked: root.previousPageClicked()
- }
- }
+ visible: root.previousPage
+ spacing: 8
+ statusIcon: "arrow"
+ icon.width: 24
+ icon.height: 24
+ text: root.previousPage
+ font.pixelSize: 15
+ onClicked: root.previousPageClicked()
}
StatusBaseText {
@@ -77,6 +73,7 @@ Item {
id: contentLoader
Layout.fillWidth: true
Layout.fillHeight: true
+ Layout.topMargin: 16
Layout.leftMargin: 24
Layout.rightMargin: 24
@@ -98,4 +95,3 @@ Item {
onSaveChangesClicked: root.saveChangesClicked()
}
}
-
diff --git a/ui/app/AppLayouts/Chat/panels/communities/CommunityPermissionsSettingsPanel.qml b/ui/app/AppLayouts/Chat/panels/communities/CommunityPermissionsSettingsPanel.qml
new file mode 100644
index 0000000000..343d195750
--- /dev/null
+++ b/ui/app/AppLayouts/Chat/panels/communities/CommunityPermissionsSettingsPanel.qml
@@ -0,0 +1,50 @@
+import QtQuick 2.14
+
+import "../../layouts"
+import "../../views/communities"
+
+SettingsPageLayout {
+ id: root
+
+ QtObject {
+ id: d
+
+ readonly property string welcomeViewState: "WELCOME"
+ readonly property string newPermissionViewState: "NEWPERMISSION"
+ }
+
+ state: d.welcomeViewState // Initial state
+ states: [
+ State {
+ name: d.welcomeViewState
+ PropertyChanges {target: root; title: qsTr("Permissions")}
+ PropertyChanges {target: root; previousPage: ""}
+ PropertyChanges {target: root; content: welcomeView}
+ },
+ State {
+ name: d.newPermissionViewState
+ PropertyChanges {target: root; title: qsTr("New permission")}
+ PropertyChanges {target: root; previousPage: qsTr("Permissions")}
+ PropertyChanges {target: root; content: newPermissionView}
+ }
+ ]
+
+ onPreviousPageClicked: {
+ if(root.state === d.newPermissionViewState) {
+ root.state = d.welcomeViewState
+ }
+ }
+
+ // Community Permissions possible view contents:
+ Component {
+ id: welcomeView
+ CommunityWelcomePermissionsView {
+ onAddPermission: root.state = d.newPermissionViewState
+ }
+ }
+
+ Component {
+ id: newPermissionView
+ CommunityNewPermissionView { }
+ }
+}
diff --git a/ui/app/AppLayouts/Chat/stores/RootStore.qml b/ui/app/AppLayouts/Chat/stores/RootStore.qml
index 17d03fe760..5fadaf1ef4 100644
--- a/ui/app/AppLayouts/Chat/stores/RootStore.qml
+++ b/ui/app/AppLayouts/Chat/stores/RootStore.qml
@@ -126,6 +126,7 @@ QtObject {
property var communitiesModuleInst: communitiesModule
property var communitiesList: communitiesModuleInst.model
+ property bool communityPermissionsEnabled: localAccountSensitiveSettings.isCommunityPermissionsEnabled
property var userProfileInst: userProfile
diff --git a/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml b/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml
index f954dc3ca4..51f237f478 100644
--- a/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml
+++ b/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml
@@ -23,17 +23,18 @@ StatusAppTwoPanelLayout {
id: root
// TODO: get this model from backend?
- property var settingsMenuModel: [
- {name: qsTr("Overview"), icon: "help"},
- {name: qsTr("Members"), icon: "group-chat"},
-// {name: qsTr("Permissions"), icon: "objects"},
-// {name: qsTr("Tokens"), icon: "token"},
-// {name: qsTr("Airdrops"), icon: "airdrop"},
-// {name: qsTr("Token sales"), icon: "token-sale"},
-// {name: qsTr("Subscriptions"), icon: "subscription"}
- ]
+ property var settingsMenuModel: root.rootStore.communityPermissionsEnabled ? [{name: qsTr("Overview"), icon: "help"},
+ {name: qsTr("Members"), icon: "group-chat"},
+ {name: qsTr("Permissions"), icon: "objects"}] :
+ [{name: qsTr("Overview"), icon: "help"},
+ {name: qsTr("Members"), icon: "group-chat"}]
+ // TODO: Next community settings options:
+ // {name: qsTr("Tokens"), icon: "token"},
+ // {name: qsTr("Airdrops"), icon: "airdrop"},
+ // {name: qsTr("Token sales"), icon: "token-sale"},
+ // {name: qsTr("Subscriptions"), icon: "subscription"},
- property var rootStore
+ property var rootStore
property var community
property var chatCommunitySectionModule
property bool hasAddedContacts: false
@@ -122,12 +123,8 @@ StatusAppTwoPanelLayout {
rightPanel: Loader {
anchors.fill: parent
- anchors.leftMargin: 28
- anchors.topMargin: 23
- anchors.margins: 16
-
+ anchors.margins: 32
active: root.community
-
sourceComponent: StackLayout {
currentIndex: d.currentIndex
@@ -199,9 +196,12 @@ StatusAppTwoPanelLayout {
communitySectionModule: root.chatCommunitySectionModule
})
}
+
+ CommunityPermissionsSettingsPanel {}
}
}
+ onSettingsMenuModelChanged: d.currentIndex = 0
QtObject {
id: d
diff --git a/ui/app/AppLayouts/Chat/views/communities/CommunityNewPermissionView.qml b/ui/app/AppLayouts/Chat/views/communities/CommunityNewPermissionView.qml
new file mode 100644
index 0000000000..ae993856f5
--- /dev/null
+++ b/ui/app/AppLayouts/Chat/views/communities/CommunityNewPermissionView.qml
@@ -0,0 +1,127 @@
+import QtQuick 2.14
+import QtQuick.Layouts 1.14
+
+import StatusQ.Core 0.1
+import StatusQ.Core.Theme 0.1
+import StatusQ.Components 0.1
+import StatusQ.Controls 0.1
+
+import utils 1.0
+import shared.panels 1.0
+
+import "../../../Chat/controls/community"
+
+Flickable {
+ id: root
+
+ signal createPermission()
+
+ QtObject {
+ id: d
+ property bool isPrivate: false
+ }
+
+ contentWidth: mainLayout.width
+ contentHeight: mainLayout.height
+ clip: true
+ flickableDirection: Flickable.AutoFlickIfNeeded
+
+ ColumnLayout {
+ id: mainLayout
+ width: 560 // by design
+ spacing: 0
+ CurveSeparatorWithText {
+ Layout.alignment: Qt.AlignLeft
+ Layout.leftMargin: 14
+ text: qsTr("Anyone")
+ }
+ StatusItemSelector {
+ id: tokensSelector
+ Layout.fillWidth: true
+ icon: Style.svg("contact_verified")
+ title: qsTr("Who holds")
+ defaultItemText: qsTr("Example: 10 SNT")
+ andOperatorText: qsTr("and")
+ orOperatorText: qsTr("or")
+ popupItem: HoldingsDropdown {
+ id: dropdown
+ withOperatorSelector: tokensSelector.itemsModel.count > 0
+ onAddToken: {
+ tokensSelector.addItem(tokenText, tokenImage, operator)
+ dropdown.close()
+ }
+ }
+ }
+ Rectangle {
+ Layout.leftMargin: 16
+ Layout.preferredWidth: 2
+ Layout.preferredHeight: 24
+ color: Style.current.separator
+ }
+ StatusItemSelector {
+ Layout.fillWidth: true
+ icon: Style.svg("profile/security")
+ iconSize: 24
+ title: qsTr("Is allowed to")
+ defaultItemText: qsTr("Example: View and post")
+ }
+ Rectangle {
+ Layout.leftMargin: 16
+ Layout.preferredWidth: 2
+ Layout.preferredHeight: 24
+ color: Style.current.separator
+ }
+ StatusItemSelector {
+ Layout.fillWidth: true
+ icon: Style.svg("create-category")
+ iconSize: 24
+ title: qsTr("In")
+ defaultItemText: qsTr("Example: `#general` channel")
+ }
+ Separator {
+ Layout.topMargin: 24
+ }
+ RowLayout {
+ Layout.topMargin: 12
+ Layout.fillWidth: true
+ Layout.leftMargin: 16
+ Layout.rightMargin: Layout.leftMargin
+ spacing: 16
+ StatusRoundIcon {
+ icon.name: "hide"
+ }
+ ColumnLayout {
+ Layout.fillWidth: true
+ StatusBaseText {
+ text: qsTr("Private")
+ color: Theme.palette.directColor1
+ font.pixelSize: 15
+ }
+ StatusBaseText {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ text: qsTr("Make this permission private to hide it from members who don’t meet it’s requirements")
+ color: Theme.palette.baseColor1
+ font.pixelSize: 15
+ lineHeight: 1.2
+ wrapMode: Text.WordWrap
+ elide: Text.ElideRight
+ clip: true
+ }
+ }
+ StatusSwitch {
+ checked: d.isPrivate
+ onToggled: { d.isPrivate = checked }
+ }
+ }
+ StatusButton {
+ Layout.topMargin: 24
+ text: qsTr("Create permission")
+ enabled: false
+ Layout.preferredHeight: 44
+ Layout.alignment: Qt.AlignHCenter
+ Layout.fillWidth: true
+ onClicked: root.createPermission()
+ }
+ }
+}
diff --git a/ui/app/AppLayouts/Chat/views/communities/CommunityWelcomePermissionsView.qml b/ui/app/AppLayouts/Chat/views/communities/CommunityWelcomePermissionsView.qml
new file mode 100644
index 0000000000..473f434ae6
--- /dev/null
+++ b/ui/app/AppLayouts/Chat/views/communities/CommunityWelcomePermissionsView.qml
@@ -0,0 +1,139 @@
+import QtQuick 2.14
+import QtQuick.Layouts 1.14
+
+import StatusQ.Core 0.1
+import StatusQ.Core.Theme 0.1
+import StatusQ.Controls 0.1
+
+import utils 1.0
+
+Flickable {
+ id: root
+
+ signal addPermission()
+
+ contentWidth: mainLayout.width
+ contentHeight: mainLayout.height + mainLayout.anchors.topMargin
+ clip: true
+ flickableDirection: Flickable.AutoFlickIfNeeded
+
+ ColumnLayout {
+ id: mainLayout
+ width: 560 // by design
+ spacing: 24
+
+ Rectangle {
+ Layout.fillWidth: true
+ Layout.preferredHeight: contentColumn.implicitHeight + contentColumn.anchors.topMargin + contentColumn.anchors.bottomMargin
+ color: "transparent"
+ radius: 16
+ border.color: Theme.palette.baseColor5
+ clip: true
+
+ ColumnLayout {
+ id: contentColumn
+ anchors.fill: parent
+ anchors.margins: 16
+ anchors.bottomMargin: 32
+ spacing: 8
+ clip: true
+ Image {
+ Layout.preferredWidth: 257
+ Layout.preferredHeight: Layout.preferredWidth
+ Layout.alignment: Qt.AlignHCenter
+ source: Style.png("community/permissions21_3_1")
+ mipmap: true
+ }
+ StatusBaseText {
+ Layout.fillWidth: true
+ horizontalAlignment: Text.AlignHCenter
+ text: qsTr("Permissions")
+ font.pixelSize: 17
+ font.weight: Font.Bold
+ color: Theme.palette.directColor1
+ }
+ StatusBaseText {
+ Layout.fillWidth: true
+ horizontalAlignment: Text.AlignHCenter
+ text: qsTr("You can manage your community by creating and issuing membership and access permissions")
+ lineHeight: 1.2
+ font.pixelSize: 15
+ color: Theme.palette.baseColor1
+ wrapMode: Text.WordWrap
+ }
+ ColumnLayout {
+ id: checkersColumn
+ property int rowChildSpacing: 10
+ property color rowIconColor: Theme.palette.primaryColor1
+ property string rowIconName: "checkmark-circle"
+ property int rowFontSize: 15
+ property color rowTextColor: Theme.palette.directColor1
+ property double rowTextLineHeight: 1.2
+
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignLeft
+ spacing: 10
+ RowLayout {
+ Layout.fillWidth: true
+ spacing: checkersColumn.rowChildSpacing
+ StatusIcon {
+ icon: checkersColumn.rowIconName
+ color: checkersColumn.rowIconColor
+ }
+ StatusBaseText {
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignVCenter
+ text: qsTr("Give individual members access to private channels")
+ lineHeight: checkersColumn.rowTextLineHeight
+ font.pixelSize: checkersColumn.rowFontSize
+ color: checkersColumn.rowTextColor
+ wrapMode: Text.WordWrap
+ }
+ }
+ RowLayout {
+ Layout.fillWidth: true
+ spacing: checkersColumn.rowChildSpacing
+ StatusIcon {
+ icon: checkersColumn.rowIconName
+ color: checkersColumn.rowIconColor
+ }
+ StatusBaseText {
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignVCenter
+ text: qsTr("Monetise your community with subscriptions and fees")
+ lineHeight: checkersColumn.rowTextLineHeight
+ font.pixelSize: checkersColumn.rowFontSize
+ color: Theme.palette.directColor1
+ wrapMode: Text.WordWrap
+ }
+ }
+ RowLayout {
+ Layout.fillWidth: true
+ spacing: checkersColumn.rowChildSpacing
+ StatusIcon {
+ icon: checkersColumn.rowIconName
+ color: checkersColumn.rowIconColor
+ }
+ StatusBaseText {
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignVCenter
+ text: qsTr("Require holding a token or NFT to obtain exclusive membership rights")
+ lineHeight: checkersColumn.rowTextLineHeight
+ font.pixelSize: checkersColumn.rowFontSize
+ color: checkersColumn.rowTextColor
+ wrapMode: Text.WordWrap
+ }
+ }
+ }
+ }
+ }
+
+ StatusButton {
+ text: qsTr("Add permission")
+ height: 44
+ Layout.alignment: Qt.AlignHCenter
+ Layout.fillWidth: true
+ onClicked: root.addPermission()
+ }
+ }
+}
diff --git a/ui/app/AppLayouts/Profile/stores/AdvancedStore.qml b/ui/app/AppLayouts/Profile/stores/AdvancedStore.qml
index 3f9abe64c4..82dd6d8576 100644
--- a/ui/app/AppLayouts/Profile/stores/AdvancedStore.qml
+++ b/ui/app/AppLayouts/Profile/stores/AdvancedStore.qml
@@ -33,6 +33,7 @@ QtObject {
readonly property string gifWidget: "gifWidget"
readonly property string communityHistoryArchiveSupport: "communityHistoryArchiveSupport"
readonly property string communitiesPortal: "communitiesPortal"
+ readonly property string communityPermissions: "communityPermissions"
}
function logDir() {
@@ -130,5 +131,8 @@ QtObject {
else if (feature === experimentalFeatures.gifWidget) {
localAccountSensitiveSettings.isGifWidgetEnabled = !localAccountSensitiveSettings.isGifWidgetEnabled
}
+ else if (feature === experimentalFeatures.communityPermissions) {
+ localAccountSensitiveSettings.isCommunityPermissionsEnabled = !localAccountSensitiveSettings.isCommunityPermissionsEnabled
+ }
}
}
diff --git a/ui/app/AppLayouts/Profile/views/AdvancedView.qml b/ui/app/AppLayouts/Profile/views/AdvancedView.qml
index aad789efca..709006670b 100644
--- a/ui/app/AppLayouts/Profile/views/AdvancedView.qml
+++ b/ui/app/AppLayouts/Profile/views/AdvancedView.qml
@@ -163,6 +163,23 @@ SettingsContentBase {
}
}
+ // TODO: replace with StatusQ component
+ StatusSettingsLineButton {
+ anchors.leftMargin: 0
+ anchors.rightMargin: 0
+ text: qsTr("Community Permissions Settings")
+ isSwitch: true
+ switchChecked: localAccountSensitiveSettings.isCommunityPermissionsEnabled
+ onClicked: {
+ if (!localAccountSensitiveSettings.isCommunityPermissionsEnabled) {
+ confirmationPopup.experimentalFeature = root.advancedStore.experimentalFeatures.communityPermissions
+ confirmationPopup.open()
+ } else {
+ root.advancedStore.toggleExperimentalFeature(root.advancedStore.experimentalFeatures.communityPermissions)
+ }
+ }
+ }
+
StatusSectionHeadline {
anchors.left: parent.left
anchors.right: parent.right
diff --git a/ui/imports/assets/icons/add.svg b/ui/imports/assets/icons/add.svg
new file mode 100644
index 0000000000..6c147debd0
--- /dev/null
+++ b/ui/imports/assets/icons/add.svg
@@ -0,0 +1,3 @@
+
diff --git a/ui/imports/assets/icons/condition-Or.svg b/ui/imports/assets/icons/condition-Or.svg
new file mode 100644
index 0000000000..c0b38a1a97
--- /dev/null
+++ b/ui/imports/assets/icons/condition-Or.svg
@@ -0,0 +1,5 @@
+
diff --git a/ui/imports/assets/icons/contact_verified.svg b/ui/imports/assets/icons/contact_verified.svg
new file mode 100644
index 0000000000..e0305776f8
--- /dev/null
+++ b/ui/imports/assets/icons/contact_verified.svg
@@ -0,0 +1,5 @@
+
diff --git a/ui/imports/assets/png/community/permissions21_3_1.png b/ui/imports/assets/png/community/permissions21_3_1.png
new file mode 100644
index 0000000000..7776721c86
Binary files /dev/null and b/ui/imports/assets/png/community/permissions21_3_1.png differ
diff --git a/ui/imports/shared/panels/CurveSeparatorWithText.qml b/ui/imports/shared/panels/CurveSeparatorWithText.qml
new file mode 100644
index 0000000000..979ddce1fc
--- /dev/null
+++ b/ui/imports/shared/panels/CurveSeparatorWithText.qml
@@ -0,0 +1,45 @@
+import QtQuick 2.14
+import QtQuick.Layouts 1.14
+
+import StatusQ.Core 0.1
+import StatusQ.Core.Theme 0.1
+
+import utils 1.0
+
+RowLayout {
+ id: root
+
+ property string text
+
+ implicitHeight: 32
+
+ Canvas {
+ readonly property int cornerRadius: 9
+ readonly property int lineWidth: 2
+ readonly property int verticalLine: 12
+ readonly property int horizontalLine: 19
+
+ Layout.preferredWidth: horizontalLine + cornerRadius
+ Layout.preferredHeight: verticalLine + lineWidth + cornerRadius
+ Layout.alignment: Qt.AlignTop
+ Layout.topMargin: 12
+ contextType: "2d"
+ onPaint: {
+ context.reset();
+ context.beginPath()
+ context.moveTo(width, lineWidth)
+ context.arc(cornerRadius + lineWidth, cornerRadius + lineWidth, cornerRadius, 3 * Math.PI / 2, Math.PI, true/*anticlockwise*/)
+ context.lineTo(lineWidth, cornerRadius + verticalLine + lineWidth)
+ context.strokeStyle = Style.current.separator
+ context.lineWidth = 2
+ context.stroke()
+ }
+ }
+ StatusBaseText {
+ Layout.alignment: Qt.AlignTop
+ Layout.topMargin: 2
+ text: root.text
+ color: Theme.palette.directColor1
+ font.pixelSize: 17
+ }
+}
diff --git a/ui/imports/shared/panels/qmldir b/ui/imports/shared/panels/qmldir
index ce47ce796f..271ee1b746 100644
--- a/ui/imports/shared/panels/qmldir
+++ b/ui/imports/shared/panels/qmldir
@@ -12,6 +12,7 @@ RoundedIcon 1.0 RoundedIcon.qml
RoundedImage 1.0 RoundedImage.qml
Separator 1.0 Separator.qml
SeparatorWithIcon 1.0 SeparatorWithIcon.qml
+CurveSeparatorWithText 1.0 CurveSeparatorWithText.qml
SplitViewHandle 1.0 SplitViewHandle.qml
StyledText 1.0 StyledText.qml
SVGImage 1.0 SVGImage.qml