feat(CommunitySettings / Permissions): Added `welcome` page and `How holds` tokens dropdown

- Added functionality as experimental advanced view button

feat(CommunitySettings / Permissions): Added welcome page
- Enabled new permissions tab.
- Created welcome page layout.
- Added permissions welcome image.
- Fixed top margin content in `SettingsPanelLayout` to fit designs.

Closes #6036

feat(CommunitySettings/Permissions): Created `new permission` page

- Added `new permission` page.
- Created first card layout.
- Added navigation between `welcome` and `newPermission` views.
- Improvements in base community settings layout pages.

Closes #6037

feat(CommunitySettings/Permissions): `Who holds` tokens dropdown component creation and integration

- Tokens dropdown component creation: main view, operators view and extended view.
- Logic to add new token and change operator.

Part of #6038
This commit is contained in:
Noelia 2022-06-09 17:27:14 +02:00 committed by Noelia
parent 5fb4c7f110
commit 7b54bf31b4
17 changed files with 829 additions and 31 deletions

View File

@ -8,6 +8,8 @@ const LSS_KEY_WALLET_SPLIT_VIEW* = "walletSplitView"
const LSS_KEY_PROFILE_SPLIT_VIEW* = "profileSplitView" const LSS_KEY_PROFILE_SPLIT_VIEW* = "profileSplitView"
const LSS_KEY_IS_WALLET_ENABLED* = "isExperimentalWalletEnabled" const LSS_KEY_IS_WALLET_ENABLED* = "isExperimentalWalletEnabled"
const DEFAULT_IS_WALLET_ENABLED = false 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 LSS_KEY_NODE_MANAGEMENT_ENABLED* = "nodeManagementEnabled"
const DEFAULT_NODE_MANAGEMENT_ENABLED = false const DEFAULT_NODE_MANAGEMENT_ENABLED = false
const LSS_KEY_IS_BROWSER_ENABLED* = "isExperimentalBrowserEnabled" const LSS_KEY_IS_BROWSER_ENABLED* = "isExperimentalBrowserEnabled"
@ -191,6 +193,18 @@ QtObject:
write = setProfileSplitView write = setProfileSplitView
notify = profileSplitViewChanged 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 isWalletEnabledChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getIsWalletEnabled*(self: LocalAccountSensitiveSettings): bool {.slot.} = proc getIsWalletEnabled*(self: LocalAccountSensitiveSettings): bool {.slot.} =
getSettingsProp[bool](self, LSS_KEY_IS_WALLET_ENABLED, newQVariant(DEFAULT_IS_WALLET_ENABLED)) 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_WALLET_SPLIT_VIEW: self.walletSplitViewChanged()
of LSS_KEY_PROFILE_SPLIT_VIEW: self.profileSplitViewChanged() of LSS_KEY_PROFILE_SPLIT_VIEW: self.profileSplitViewChanged()
of LSS_KEY_IS_WALLET_ENABLED: self.isWalletEnabledChanged() 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_NODE_MANAGEMENT_ENABLED: self.nodeManagementEnabledChanged()
of LSS_KEY_IS_BROWSER_ENABLED: self.isBrowserEnabledChanged() of LSS_KEY_IS_BROWSER_ENABLED: self.isBrowserEnabledChanged()
of LSS_KEY_SHOW_ONLINE_USERS: self.showOnlineUsersChanged() of LSS_KEY_SHOW_ONLINE_USERS: self.showOnlineUsersChanged()

View File

@ -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
}
}
}
}

View File

@ -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

View File

@ -5,6 +5,8 @@ import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import utils 1.0
import shared.panels 1.0
import shared.popups 1.0 import shared.popups 1.0
Item { Item {
@ -44,25 +46,19 @@ Item {
id: layout id: layout
anchors.fill: parent anchors.fill: parent
spacing: 16 spacing: 16
Item { StatusIconTextButton {
implicitHeight: 32 implicitHeight: 32
StatusBaseText {
visible: root.previousPage visible: root.previousPage
text: "<- " + root.previousPage spacing: 8
color: Theme.palette.primaryColor1 statusIcon: "arrow"
icon.width: 24
icon.height: 24
text: root.previousPage
font.pixelSize: 15 font.pixelSize: 15
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: root.previousPageClicked() onClicked: root.previousPageClicked()
} }
}
}
StatusBaseText { StatusBaseText {
Layout.leftMargin: 36 Layout.leftMargin: 36
@ -77,6 +73,7 @@ Item {
id: contentLoader id: contentLoader
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
Layout.topMargin: 16
Layout.leftMargin: 24 Layout.leftMargin: 24
Layout.rightMargin: 24 Layout.rightMargin: 24
@ -98,4 +95,3 @@ Item {
onSaveChangesClicked: root.saveChangesClicked() onSaveChangesClicked: root.saveChangesClicked()
} }
} }

View File

@ -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 { }
}
}

View File

@ -126,6 +126,7 @@ QtObject {
property var communitiesModuleInst: communitiesModule property var communitiesModuleInst: communitiesModule
property var communitiesList: communitiesModuleInst.model property var communitiesList: communitiesModuleInst.model
property bool communityPermissionsEnabled: localAccountSensitiveSettings.isCommunityPermissionsEnabled
property var userProfileInst: userProfile property var userProfileInst: userProfile

View File

@ -23,15 +23,16 @@ StatusAppTwoPanelLayout {
id: root id: root
// TODO: get this model from backend? // TODO: get this model from backend?
property var settingsMenuModel: [ property var settingsMenuModel: root.rootStore.communityPermissionsEnabled ? [{name: qsTr("Overview"), icon: "help"},
{name: qsTr("Overview"), icon: "help"},
{name: qsTr("Members"), icon: "group-chat"}, {name: qsTr("Members"), icon: "group-chat"},
// {name: qsTr("Permissions"), icon: "objects"}, {name: qsTr("Permissions"), icon: "objects"}] :
// {name: qsTr("Tokens"), icon: "token"}, [{name: qsTr("Overview"), icon: "help"},
// {name: qsTr("Airdrops"), icon: "airdrop"}, {name: qsTr("Members"), icon: "group-chat"}]
// {name: qsTr("Token sales"), icon: "token-sale"}, // TODO: Next community settings options:
// {name: qsTr("Subscriptions"), icon: "subscription"} // {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 community
@ -122,12 +123,8 @@ StatusAppTwoPanelLayout {
rightPanel: Loader { rightPanel: Loader {
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 28 anchors.margins: 32
anchors.topMargin: 23
anchors.margins: 16
active: root.community active: root.community
sourceComponent: StackLayout { sourceComponent: StackLayout {
currentIndex: d.currentIndex currentIndex: d.currentIndex
@ -199,9 +196,12 @@ StatusAppTwoPanelLayout {
communitySectionModule: root.chatCommunitySectionModule communitySectionModule: root.chatCommunitySectionModule
}) })
} }
CommunityPermissionsSettingsPanel {}
} }
} }
onSettingsMenuModelChanged: d.currentIndex = 0
QtObject { QtObject {
id: d id: d

View File

@ -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 dont meet its 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()
}
}
}

View File

@ -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()
}
}
}

View File

@ -33,6 +33,7 @@ QtObject {
readonly property string gifWidget: "gifWidget" readonly property string gifWidget: "gifWidget"
readonly property string communityHistoryArchiveSupport: "communityHistoryArchiveSupport" readonly property string communityHistoryArchiveSupport: "communityHistoryArchiveSupport"
readonly property string communitiesPortal: "communitiesPortal" readonly property string communitiesPortal: "communitiesPortal"
readonly property string communityPermissions: "communityPermissions"
} }
function logDir() { function logDir() {
@ -130,5 +131,8 @@ QtObject {
else if (feature === experimentalFeatures.gifWidget) { else if (feature === experimentalFeatures.gifWidget) {
localAccountSensitiveSettings.isGifWidgetEnabled = !localAccountSensitiveSettings.isGifWidgetEnabled localAccountSensitiveSettings.isGifWidgetEnabled = !localAccountSensitiveSettings.isGifWidgetEnabled
} }
else if (feature === experimentalFeatures.communityPermissions) {
localAccountSensitiveSettings.isCommunityPermissionsEnabled = !localAccountSensitiveSettings.isCommunityPermissionsEnabled
}
} }
} }

View File

@ -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 { StatusSectionHeadline {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right

View File

@ -0,0 +1,3 @@
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5 0.5C5.27614 0.5 5.5 0.723858 5.5 1V4.16667C5.5 4.35076 5.64924 4.5 5.83333 4.5H9C9.27614 4.5 9.5 4.72386 9.5 5C9.5 5.27614 9.27614 5.5 9 5.5H5.83333C5.64924 5.5 5.5 5.64924 5.5 5.83333V9C5.5 9.27614 5.27614 9.5 5 9.5C4.72386 9.5 4.5 9.27614 4.5 9V5.83333C4.5 5.64924 4.35076 5.5 4.16667 5.5H1C0.723858 5.5 0.5 5.27614 0.5 5C0.5 4.72386 0.723858 4.5 1 4.5H4.16667C4.35076 4.5 4.5 4.35076 4.5 4.16667V1C4.5 0.723858 4.72386 0.5 5 0.5Z" fill="#4360DF"/>
</svg>

After

Width:  |  Height:  |  Size: 566 B

View File

@ -0,0 +1,5 @@
<svg width="14" height="12" viewBox="0 0 14 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.99838 0.00722752C7.70764 -0.0407138 7.43287 0.154896 7.38468 0.444134L5.5622 11.3825C5.51401 11.6718 5.71063 11.9451 6.00138 11.993C6.29212 12.041 6.56688 11.8454 6.61508 11.5561L8.43756 0.617744C8.48575 0.328507 8.28913 0.0551688 7.99838 0.00722752Z" fill="#4360DF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.3333 3.5C9.95254 3.5 8.83325 4.61929 8.83325 6C8.83325 7.38071 9.95254 8.5 11.3333 8.5C12.714 8.5 13.8333 7.38071 13.8333 6C13.8333 4.61929 12.714 3.5 11.3333 3.5ZM9.83325 6C9.83325 6.82843 10.5048 7.5 11.3333 7.5C12.1617 7.5 12.8333 6.82843 12.8333 6C12.8333 5.17157 12.1617 4.5 11.3333 4.5C10.5048 4.5 9.83325 5.17157 9.83325 6Z" fill="#4360DF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.66659 3.66667C0.930206 3.66667 0.333252 4.26362 0.333252 5V7C0.333252 7.73638 0.930206 8.33333 1.66659 8.33333H3.66659C4.40297 8.33333 4.99992 7.73638 4.99992 7V5C4.99992 4.26362 4.40297 3.66667 3.66659 3.66667H1.66659ZM3.66659 4.66667H1.66659C1.48249 4.66667 1.33325 4.81591 1.33325 5V7C1.33325 7.18409 1.48249 7.33333 1.66659 7.33333H3.66659C3.85068 7.33333 3.99992 7.18409 3.99992 7V5C3.99992 4.81591 3.85068 4.66667 3.66659 4.66667Z" fill="#4360DF"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,5 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 10C10.7614 10 13 7.76142 13 5C13 2.23858 10.7614 0 8 0C5.23858 0 3 2.23858 3 5C3 7.76142 5.23858 10 8 10ZM8 8.5C9.933 8.5 11.5 6.933 11.5 5C11.5 3.067 9.933 1.5 8 1.5C6.067 1.5 4.5 3.067 4.5 5C4.5 6.933 6.067 8.5 8 8.5Z" fill="#4360DF"/>
<path d="M8.93455 13.7839C8.89975 14.2015 8.52884 14.506 8.10986 14.5007C8.07325 14.5002 8.03657 14.5 7.99985 14.5C5.45645 14.5 3.17395 15.6171 1.61624 17.3874C1.31374 17.7312 0.777725 17.7779 0.453922 17.454C0.193192 17.1933 0.161813 16.7784 0.401673 16.4984C2.23574 14.357 4.95932 13 7.99985 13C8.08678 13 8.17346 13.0011 8.25987 13.0033C8.66888 13.0138 8.96852 13.3762 8.93455 13.7839Z" fill="#4360DF"/>
<path d="M17.6708 10.3354C17.8561 9.96493 17.7059 9.51442 17.3354 9.32918C16.9649 9.14394 16.5144 9.29411 16.3292 9.66459L14.1048 14.1134C13.9522 14.4186 13.5453 14.4847 13.304 14.2433L12.5303 13.4697C12.2374 13.1768 11.7626 13.1768 11.4697 13.4697C11.1768 13.7626 11.1768 14.2374 11.4697 14.5303L12.9791 16.0398C13.5824 16.6431 14.5995 16.4781 14.9811 15.7149L17.6708 10.3354Z" fill="#4360DF"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -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
}
}

View File

@ -12,6 +12,7 @@ RoundedIcon 1.0 RoundedIcon.qml
RoundedImage 1.0 RoundedImage.qml RoundedImage 1.0 RoundedImage.qml
Separator 1.0 Separator.qml Separator 1.0 Separator.qml
SeparatorWithIcon 1.0 SeparatorWithIcon.qml SeparatorWithIcon 1.0 SeparatorWithIcon.qml
CurveSeparatorWithText 1.0 CurveSeparatorWithText.qml
SplitViewHandle 1.0 SplitViewHandle.qml SplitViewHandle 1.0 SplitViewHandle.qml
StyledText 1.0 StyledText.qml StyledText 1.0 StyledText.qml
SVGImage 1.0 SVGImage.qml SVGImage 1.0 SVGImage.qml