feat(CommunityPermissions): Created `CommunityPermissionsView` layout

- Created `CommunityPermissionsView` and integrated into the flow.
- Created `PermissionItem` component.
- Added `holdingsListModel`, `permissionsObjectModel` and `channelsListModel` flows with mocked data.
- Added `isPrivate` permission property.
- Added button header in `SettingsPageLayout`
- Added signals/methods for edit/duplicate/remove permissions
- Created new file `OperatorsUtils.qml` specific for `Operators`
This commit is contained in:
Noelia 2022-11-25 18:35:30 +01:00 committed by Noelia
parent 5aeef81bad
commit 1cbb3e2ad3
19 changed files with 531 additions and 115 deletions

View File

@ -13,8 +13,6 @@ ColumnLayout {
iconSize: 24 iconSize: 24
title: "Item Selector Title" title: "Item Selector Title"
defaultItemText: "Example: Empty items" defaultItemText: "Example: Empty items"
andOperatorText: "and"
orOperatorText: "or"
itemsModel: ListModel { itemsModel: ListModel {
id: model id: model
@ -39,7 +37,7 @@ ColumnLayout {
model.append({ model.append({
text: input.text, text: input.text,
imageSource: "qrc:/images/SNT.png", imageSource: "qrc:/images/SNT.png",
operator: model.count > 0 ? Utils.Operators.Or : Utils.Operators.None operator: model.count > 0 ? OperatorsUtils.Operators.Or : OperatorsUtils.Operators.None
}) })
dropdown.close() dropdown.close()

View File

@ -100,38 +100,12 @@ Rectangle {
an image or an icon. an image or an icon.
*/ */
property bool useIcons: false property bool useIcons: false
/*!
\qmlproperty string StatusItemSelector::andOperatorText
This property holds the string text representation for an `AND` logical operator.
*/
property string andOperatorText: qsTr("and")
/*!
\qmlproperty string StatusItemSelector::orOperatorText
This property holds the string text representation for an `OR` logical operator.
*/
property string orOperatorText: qsTr("or")
/*! /*!
\qmlsignal StatusItemSelector::itemClicked \qmlsignal StatusItemSelector::itemClicked
This signal is emitted when the item is clicked. This signal is emitted when the item is clicked.
*/ */
signal itemClicked(var item, int index, var mouse) signal itemClicked(var item, int index, var mouse)
QtObject {
id: d
function operatorTextFormat(operator) {
switch(operator) {
case Utils.Operators.And:
return root.andOperatorText
case Utils.Operators.Or:
return root.orOperatorText
case Utils.Operators.None:
return ""
}
}
}
color: Theme.palette.baseColor4 color: Theme.palette.baseColor4
implicitHeight: columnLayout.implicitHeight + columnLayout.anchors.topMargin + columnLayout.anchors.bottomMargin implicitHeight: columnLayout.implicitHeight + columnLayout.anchors.topMargin + columnLayout.anchors.bottomMargin
implicitWidth: 560 implicitWidth: 560
@ -190,9 +164,9 @@ Rectangle {
spacing: flow.spacing spacing: flow.spacing
StatusBaseText { StatusBaseText {
visible: model.operator !== Utils.Operators.None visible: model.operator !== OperatorsUtils.Operators.None
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
text: d.operatorTextFormat(model.operator) text: OperatorsUtils.setOperatorTextFormat(model.operator)
color: Theme.palette.primaryColor1 color: Theme.palette.primaryColor1
font.pixelSize: 17 font.pixelSize: 17
MouseArea { MouseArea {
@ -200,10 +174,10 @@ Rectangle {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
// Switch operator // Switch operator
if(model.operator === Utils.Operators.And) if(model.operator === OperatorsUtils.Operators.And)
model.operator = Utils.Operators.Or model.operator = OperatorsUtils.Operators.Or
else else
model.operator = Utils.Operators.And model.operator = OperatorsUtils.Operators.And
} }
} }
} }

View File

@ -0,0 +1,36 @@
pragma Singleton
import QtQuick 2.13
QtObject {
id: root
/*!
\qmlproperty string OperatorsUtils::andOperatorText
This property holds the string text representation for an `AND` logical operator.
*/
readonly property string andOperatorText: qsTr("and")
/*!
\qmlproperty string OperatorsUtils::orOperatorText
This property holds the string text representation for an `OR` logical operator.
*/
readonly property string orOperatorText: qsTr("or")
// Logical operators
enum Operators {
None,
And,
Or
}
function setOperatorTextFormat(operator) {
switch(operator) {
case OperatorsUtils.Operators.And:
return root.andOperatorText
case OperatorsUtils.Operators.Or:
return root.orOperatorText
case OperatorsUtils.Operators.None:
return ""
}
}
}

View File

@ -5,13 +5,7 @@ import StatusQ.Core.Theme 0.1
import "./xss.js" as XSS import "./xss.js" as XSS
QtObject { QtObject {
id: root
// Logical operators
enum Operators {
None,
And,
Or
}
function getAbsolutePosition(node) { function getAbsolutePosition(node) {
var returnPos = {}; var returnPos = {};

View File

@ -5,3 +5,4 @@ XSS 1.0 xss.js
singleton Utils 0.1 Utils.qml singleton Utils 0.1 Utils.qml
singleton Emoji 0.1 Emoji.qml singleton Emoji 0.1 Emoji.qml
JSONListModel 0.1 JSONListModel.qml JSONListModel 0.1 JSONListModel.qml
singleton OperatorsUtils 0.1 OperatorsUtils.qml

View File

@ -193,5 +193,6 @@
<file>StatusQ/Core/StatusRollArea.qml</file> <file>StatusQ/Core/StatusRollArea.qml</file>
<file>StatusQ/Popups/Dialog/StatusDialogBackground.qml</file> <file>StatusQ/Popups/Dialog/StatusDialogBackground.qml</file>
<file>StatusQ/Popups/StatusMenuInstantiator.qml</file> <file>StatusQ/Popups/StatusMenuInstantiator.qml</file>
<file>StatusQ/Core/Utils/OperatorsUtils.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -5,7 +5,7 @@ import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1 import StatusQ.Components 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import StatusQ.Core.Utils 0.1 as SQ import StatusQ.Core.Utils 0.1
StatusDropdown { StatusDropdown {
@ -35,7 +35,7 @@ StatusDropdown {
function reset() { function reset() {
d.currentHoldingType = HoldingTypes.Type.Token d.currentHoldingType = HoldingTypes.Type.Token
d.operator = SQ.Utils.Operators.None d.operator = OperatorsUtils.Operators.None
d.tokenAmountText = "" d.tokenAmountText = ""
d.collectibleAmountText = "" d.collectibleAmountText = ""
@ -106,7 +106,7 @@ StatusDropdown {
property int currentHoldingType: HoldingTypes.Type.Token property int currentHoldingType: HoldingTypes.Type.Token
property int operator: SQ.Utils.Operators.None property int operator: OperatorsUtils.Operators.None
property bool ensDomainNameValid: false property bool ensDomainNameValid: false
signal addClicked signal addClicked
@ -304,7 +304,7 @@ StatusDropdown {
const modelItem = store.getTokenByKey(tokenKey) const modelItem = store.getTokenByKey(tokenKey)
if (modelItem) { if (modelItem) {
tokensPanel.tokenName = modelItem.name tokensPanel.tokenName = modelItem.shortName
tokensPanel.tokenImage = modelItem.iconSource tokensPanel.tokenImage = modelItem.iconSource
} else { } else {
tokensPanel.tokenName = d.defaultTokenNameText tokensPanel.tokenName = d.defaultTokenNameText

View File

@ -3,7 +3,7 @@ import QtQuick 2.14
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1 as SQ import StatusQ.Core.Utils 0.1
import utils 1.0 import utils 1.0
@ -19,12 +19,12 @@ ColumnLayout {
{ {
icon: "add", icon: "add",
text: qsTr("And..."), text: qsTr("And..."),
operator: SQ.Utils.Operators.And operator: OperatorsUtils.Operators.And
}, },
{ {
icon: "condition-Or", icon: "condition-Or",
text: qsTr("Or..."), text: qsTr("Or..."),
operator: SQ.Utils.Operators.Or operator: OperatorsUtils.Operators.Or
} }
] ]

View File

@ -0,0 +1,245 @@
import QtQuick 2.3
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.14
import StatusQ.Core.Theme 0.1
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Utils 0.1
Control{
id: root
property var holdingsListModel
property string permissionName
property var permissionImageSource
property var channelsListModel
property bool isPrivate: false
signal editClicked
signal duplicateClicked
signal removeClicked
QtObject {
id: d
readonly property int flowRowHeight: 32
readonly property int commonMargin: 16
readonly property int designRadius: 16
readonly property int itemTextPixelSize: 17
readonly property int tagTextPixelSize: 15
readonly property int buttonTextPixelSize: 12
readonly property int buttonDiameter: 36
readonly property int buttonTextSpacing: 6
}
background: Rectangle {
color: "transparent"
border.color: Theme.palette.baseColor2
border.width: 1
radius: d.designRadius
}
contentItem: ColumnLayout {
spacing: 0
Rectangle {
id: header
color: Theme.palette.baseColor2
Layout.fillWidth: true
Layout.preferredHeight: 34
radius: d.designRadius
RowLayout {
anchors.fill: parent
spacing: 8
StatusIcon {
Layout.leftMargin: 19
icon: "checkmark"
Layout.preferredWidth: 11
Layout.preferredHeight: 8
color: Theme.palette.directColor1
}
StatusBaseText {
Layout.fillWidth: true
text: qsTr("Active")
font.pixelSize: d.tagTextPixelSize
}
StatusIcon {
Layout.rightMargin: 10
visible: root.isPrivate
icon: "hide"
color: Theme.palette.baseColor1
}
}
}
Flow {
id: content
Layout.fillWidth: true
Layout.fillHeight: true
Layout.topMargin: 8
Layout.rightMargin: d.commonMargin
Layout.leftMargin: d.commonMargin
Layout.bottomMargin: 20
spacing: 6
StatusBaseText {
font.pixelSize: d.itemTextPixelSize
height: d.flowRowHeight
text: qsTr("Anyone who holds")
verticalAlignment: Text.AlignVCenter
}
Repeater {
model: root.holdingsListModel
RowLayout {
spacing: content.spacing
StatusBaseText {
Layout.preferredHeight: d.flowRowHeight
visible: model.operator !== OperatorsUtils.Operators.None
Layout.alignment: Qt.AlignVCenter
text: OperatorsUtils.setOperatorTextFormat(model.operator)
font.pixelSize: d.itemTextPixelSize
verticalAlignment: Text.AlignVCenter
}
StatusListItemTag {
Layout.preferredHeight: d.flowRowHeight
title: model.text
asset.name: model.imageSource
asset.isImage: true
asset.bgColor: "transparent"
asset.height: 28
asset.width: asset.height
color: Theme.palette.primaryColor3
closeButtonVisible: false
titleText.color: Theme.palette.primaryColor1
titleText.font.pixelSize: d.tagTextPixelSize
}
}
}
StatusBaseText {
height: d.flowRowHeight
font.pixelSize: d.itemTextPixelSize
text: qsTr("is allowed to")
verticalAlignment: Text.AlignVCenter
}
StatusListItemTag {
height: d.flowRowHeight
title: root.permissionName
asset.name: root.permissionImageSource
asset.isImage: false
asset.bgColor: "transparent"
color: Theme.palette.primaryColor3
closeButtonVisible: false
titleText.color: Theme.palette.primaryColor1
titleText.font.pixelSize: d.tagTextPixelSize
}
StatusBaseText {
height: d.flowRowHeight
font.pixelSize: d.itemTextPixelSize
text: qsTr("in")
verticalAlignment: Text.AlignVCenter
}
Repeater {
model: root.channelsListModel
RowLayout {
spacing: content.spacing
StatusBaseText {
Layout.preferredHeight: d.flowRowHeight
visible: model.index !== 0
Layout.alignment: Qt.AlignVCenter
text: qsTr("and")
font.pixelSize: d.itemTextPixelSize
verticalAlignment: Text.AlignVCenter
}
StatusListItemTag {
Layout.preferredHeight: d.flowRowHeight
title: model.text
asset.name: model.imageSource
asset.isImage: true
asset.bgColor: "transparent"
color: Theme.palette.primaryColor3
closeButtonVisible: false
titleText.color: Theme.palette.primaryColor1
titleText.font.pixelSize: d.tagTextPixelSize
}
}
}
}
RowLayout {
id: footer
spacing: 85
Layout.fillWidth: true
Layout.bottomMargin: d.commonMargin
Layout.alignment: Qt.AlignHCenter
ColumnLayout {
spacing: d.buttonTextSpacing
StatusRoundButton {
Layout.alignment: Qt.AlignHCenter
icon.name: "edit_pencil"
Layout.preferredHeight: d.buttonDiameter
Layout.preferredWidth: Layout.preferredHeight
type: StatusRoundButton.Type.Primary
onClicked: root.editClicked()
}
StatusBaseText {
Layout.alignment: Qt.AlignHCenter
text: qsTr("Edit")
color: Theme.palette.primaryColor1
font.pixelSize: d.buttonTextPixelSize
}
}
ColumnLayout {
spacing: d.buttonTextSpacing
StatusRoundButton {
Layout.alignment: Qt.AlignHCenter
icon.name: "copy"
Layout.preferredHeight: d.buttonDiameter
Layout.preferredWidth: Layout.preferredHeight
type: StatusRoundButton.Type.Primary
onClicked: root.duplicateClicked()
}
StatusBaseText {
Layout.alignment: Qt.AlignHCenter
text: qsTr("Duplicate")
color: Theme.palette.primaryColor1
font.pixelSize: d.buttonTextPixelSize
}
}
ColumnLayout {
spacing: d.buttonTextSpacing
StatusRoundButton {
Layout.alignment: Qt.AlignHCenter
icon.name: "delete"
Layout.preferredHeight: d.buttonDiameter
Layout.preferredWidth: Layout.preferredHeight
type: StatusRoundButton.Type.Quaternary
onClicked: root.removeClicked()
}
StatusBaseText {
Layout.alignment: Qt.AlignHCenter
text: qsTr("Remove")
color: Theme.palette.dangerColor1
font.pixelSize: d.buttonTextPixelSize
}
}
}
}
}

View File

@ -0,0 +1,2 @@
HoldingTypes 1.0 HoldingTypes.qml
PermissionItem 1.0 PermissionItem.qml

View File

@ -19,6 +19,9 @@ Item {
// optional // optional
property bool dirty: false property bool dirty: false
property bool editable: false property bool editable: false
property bool headerButtonVisible: false
property string headerButtonText: ""
property int headerWidth: 0
readonly property Item contentItem: contentLoader.item readonly property Item contentItem: contentLoader.item
readonly property size settingsDirtyToastMessageImplicitSize: readonly property size settingsDirtyToastMessageImplicitSize:
@ -27,6 +30,7 @@ Item {
signal saveChangesClicked signal saveChangesClicked
signal resetChangesClicked signal resetChangesClicked
signal headerButtonClicked
function reloadContent() { function reloadContent() {
contentLoader.active = false contentLoader.active = false
@ -46,17 +50,28 @@ Item {
anchors.fill: parent anchors.fill: parent
spacing: 16 spacing: 16
Item { RowLayout {
width: parent.width Layout.maximumWidth: root.headerWidth === 0 ? parent.width : (root.headerWidth + itemHeader.Layout.leftMargin)
Layout.preferredHeight: 56 Layout.preferredHeight: 56
Layout.leftMargin: 36
StatusBaseText { StatusBaseText {
anchors.verticalCenter: parent.verticalCenter id: itemHeader
Layout.leftMargin: 64
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
text: root.title text: root.title
color: Theme.palette.directColor1 color: Theme.palette.directColor1
font.pixelSize: 26 font.pixelSize: 26
font.bold: true font.bold: true
} }
StatusButton {
visible: root.headerButtonVisible
text: root.headerButtonText
Layout.preferredHeight: 44
Layout.alignment: Qt.AlignHCenter
onClicked: root.headerButtonClicked()
}
} }
Loader { Loader {
@ -64,7 +79,7 @@ Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 24 Layout.leftMargin: 64
Layout.rightMargin: 24 Layout.rightMargin: 24
sourceComponent: root.content sourceComponent: root.content

View File

@ -0,0 +1 @@
SettingsPageLayout 1.0 SettingsPageLayout.qml

View File

@ -1,11 +1,15 @@
import QtQuick 2.14 import QtQuick 2.14
import "../../layouts" import AppLayouts.Chat.layouts 1.0
import "../../views/communities" import AppLayouts.Chat.views.communities 1.0
import AppLayouts.Chat.stores 1.0
SettingsPageLayout { SettingsPageLayout {
id: root id: root
property var store: CommunitiesStore {}
property int viewWidth: 560 // by design
property string previousPageName property string previousPageName
function updateState() { function updateState() {
if (root.state === d.newPermissionViewState) { if (root.state === d.newPermissionViewState) {
@ -18,34 +22,69 @@ SettingsPageLayout {
readonly property string welcomeViewState: "WELCOME" readonly property string welcomeViewState: "WELCOME"
readonly property string newPermissionViewState: "NEWPERMISSION" readonly property string newPermissionViewState: "NEWPERMISSION"
readonly property string permissionsViewState: "PERMISSIONS"
} }
state: d.welcomeViewState // Initial state state: root.store.permissionsModel.count > 0 ? d.permissionsViewState : d.welcomeViewState
states: [ states: [
State { State {
name: d.welcomeViewState name: d.welcomeViewState
PropertyChanges {target: root; title: qsTr("Permissions")} PropertyChanges {target: root; title: qsTr("Permissions")}
PropertyChanges {target: root; previousPageName: ""} PropertyChanges {target: root; previousPageName: ""}
PropertyChanges {target: root; content: welcomeView} PropertyChanges {target: root; content: welcomeView}
PropertyChanges {target: root; headerButtonVisible: true}
PropertyChanges {target: root; headerButtonText: qsTr("Add new permission")}
PropertyChanges {target: root; headerWidth: root.viewWidth}
}, },
State { State {
name: d.newPermissionViewState name: d.newPermissionViewState
PropertyChanges {target: root; title: qsTr("New permission")} PropertyChanges {target: root; title: qsTr("New permission")}
PropertyChanges {target: root; previousPageName: qsTr("Permissions")} PropertyChanges {target: root; previousPageName: qsTr("Permissions")}
PropertyChanges {target: root; content: newPermissionView} PropertyChanges {target: root; content: newPermissionView}
PropertyChanges {target: root; headerButtonVisible: false}
PropertyChanges {target: root; headerWidth: 0}
},
State {
name: d.permissionsViewState
PropertyChanges {target: root; title: qsTr("Permissions")}
PropertyChanges {target: root; previousPageName: ""}
PropertyChanges {target: root; content: permissionsView}
PropertyChanges {target: root; headerButtonVisible: true}
PropertyChanges {target: root; headerButtonText: qsTr("Add new permission")}
PropertyChanges {target: root; headerWidth: root.viewWidth}
} }
] ]
onHeaderButtonClicked: {
if(root.state === d.welcomeViewState)
root.state = d.newPermissionViewState
else if (root.state === d.permissionsViewState)
root.state = d.newPermissionViewState
}
// Community Permissions possible view contents: // Community Permissions possible view contents:
Component { Component {
id: welcomeView id: welcomeView
CommunityWelcomePermissionsView { CommunityWelcomePermissionsView {
onAddPermission: root.state = d.newPermissionViewState viewWidth: root.viewWidth
} }
} }
Component { Component {
id: newPermissionView id: newPermissionView
CommunityNewPermissionView {} CommunityNewPermissionView {
viewWidth: root.viewWidth
store: root.store
onPermissionCreated: root.state = d.permissionsViewState
}
}
Component {
id: permissionsView
CommunityPermissionsView {
viewWidth: root.viewWidth
store: root.store
}
} }
} }

View File

@ -1,6 +1,13 @@
import QtQuick 2.0 import QtQuick 2.0
import AppLayouts.Chat.controls.community 1.0
import StatusQ.Core.Utils 0.1 as SQ
import utils 1.0
QtObject { QtObject {
id: root
property var permissionsModel: ListModel {} // Backend permissions list object model asignement. Please check the current expected data in qml defined in `createPermissions` method
// TODO: Replace to real data, now dummy model // TODO: Replace to real data, now dummy model
property var tokensModel: ListModel { property var tokensModel: ListModel {
@ -71,6 +78,12 @@ QtObject {
} }
} }
// TODO: Replace to real data, now dummy model
property var channelsModel: ListModel {
ListElement { key: "wellcome"; iconSource: "qrc:imports/assets/png/tokens/CUSTOM-TOKEN.png"; name: "#welcome"}
ListElement { key: "general"; iconSource: "qrc:imports/assets/png/tokens/CUSTOM-TOKEN.png"; name: "#general"}
}
readonly property QtObject _d: QtObject { readonly property QtObject _d: QtObject {
id: d id: d
@ -105,7 +118,73 @@ QtObject {
return null return null
} }
function createPermissions(permissions) { function createPermissions(holdings, permissions, isPrivate) {
console.log("TODO: Create permissions - backend call") console.log("TODO: Create permissions - backend call - Now dummy data shown")
// TO BE REMOVED: It shold just be a call to the backend sharing `holdings`, `permissions`, `channels` and `isPrivate` properties.
var permission = {
isPrivate: true,
holdingsListModel: [],
permissionsObjectModel: {
key: "",
text: "",
imageSource: ""
},
channelsListModel: []
};
// Setting HOLDINGS:
for (var i = 0; i < holdings.count; i++ ) {
var entry = holdings.get(i);
// roles: type, key, name, amount, imageSource, operator
permission.holdingsListModel.push({
operator: entry.operator,
type: entry.type,
key: entry.key,
name: entry.name,
amount: entry.amount,
imageSource: entry.imageSource
});
}
// Setting PERMISSIONS:
permission.permissionsObjectModel.key = permissions.key
permission.permissionsObjectModel.text = permissions.text
permission.permissionsObjectModel.imageSource = permissions.imageSource
// Setting PRIVATE permission property:
permission.isPrivate = isPrivate
// TODO: Set channels list. Now mocked data.
permission.channelsListModel = root.channelsModel
// Add into permission model:
root.permissionsModel.append(permission)
}
function setHoldingsTextFormat(type, name, amount) {
switch (type) {
case HoldingTypes.Type.Token:
case HoldingTypes.Type.Collectible:
return `${LocaleUtils.numberToLocaleString(amount)} ${name}`
case HoldingTypes.Type.Ens:
if (name)
return qsTr("ENS username on '%1' domain").arg(name)
else
return qsTr("Any ENS username")
default:
return ""
}
}
function editPermission(index) {
console.log("TODO: Edit permissions - backend call")
}
function duplicatePermission(index) {
console.log("TODO: Duplicate permissions - backend call")
}
function removePermission(index) {
console.log("TODO: Remove permissions - backend call")
} }
} }

View File

@ -158,11 +158,7 @@ StatusSectionLayout {
centerPanel: Loader { centerPanel: Loader {
id: centerPanelContentLoader id: centerPanelContentLoader
anchors.fill: parent anchors.fill: parent
//anchors.margins: 32 anchors.bottomMargin: 16
anchors {
leftMargin: 28
bottomMargin: 16
}
active: root.community active: root.community
sourceComponent: StackLayout { sourceComponent: StackLayout {
currentIndex: d.currentIndex currentIndex: d.currentIndex

View File

@ -5,7 +5,7 @@ import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1 import StatusQ.Components 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import StatusQ.Core.Utils 0.1 as SQ import StatusQ.Core.Utils 0.1
import utils 1.0 import utils 1.0
import shared.panels 1.0 import shared.panels 1.0
@ -13,25 +13,18 @@ import shared.panels 1.0
import SortFilterProxyModel 0.2 import SortFilterProxyModel 0.2
import "../../../Chat/controls/community" import "../../../Chat/controls/community"
import "../../stores"
Flickable { Flickable {
id: root id: root
property var store: CommunitiesStore {} property var store
property int viewWidth: 560 // by design
signal permissionCreated()
signal createPermission()
// TODO: Call this when permissions are stored in backend to start a new permissions flow
function clearPermissions() {
d.permissions.clear()
}
QtObject { QtObject {
id: d id: d
property bool isPrivate: false property bool isPrivate: false
property ListModel permissions: ListModel{}
property int permissionType: PermissionTypes.Type.None property int permissionType: PermissionTypes.Type.None
} }
@ -42,7 +35,7 @@ Flickable {
ColumnLayout { ColumnLayout {
id: mainLayout id: mainLayout
width: 560 // by design width: root.viewWidth
spacing: 0 spacing: 0
CurveSeparatorWithText { CurveSeparatorWithText {
Layout.alignment: Qt.AlignLeft Layout.alignment: Qt.AlignLeft
@ -55,8 +48,6 @@ Flickable {
icon: Style.svg("contact_verified") icon: Style.svg("contact_verified")
title: qsTr("Who holds") title: qsTr("Who holds")
defaultItemText: qsTr("Example: 10 SNT") defaultItemText: qsTr("Example: 10 SNT")
andOperatorText: qsTr("and")
orOperatorText: qsTr("or")
// roles: type, key, name, amount, imageSource, operator // roles: type, key, name, amount, imageSource, operator
ListModel { ListModel {
@ -64,28 +55,12 @@ Flickable {
} }
property int editedIndex property int editedIndex
function getText(type, name, amount) {
switch (type) {
case HoldingTypes.Type.Token:
case HoldingTypes.Type.Collectible:
return `${LocaleUtils.numberToLocaleString(amount)} ${name}`
case HoldingTypes.Type.Ens:
if (name)
return qsTr("ENS username on '%1' domain").arg(name)
else
return qsTr("Any ENS username")
default:
return ""
}
}
itemsModel: SortFilterProxyModel { itemsModel: SortFilterProxyModel {
sourceModel: holdingsModel sourceModel: holdingsModel
proxyRoles: ExpressionRole { proxyRoles: ExpressionRole {
name: "text" name: "text"
expression: tokensSelector.getText(model.type, model.name, model.amount) expression: root.store.setHoldingsTextFormat(model.type, model.name, model.amount)
} }
} }
@ -95,11 +70,10 @@ Flickable {
function addItem(type, item, amount, operator) { function addItem(type, item, amount, operator) {
const key = item.key const key = item.key
const name = item.name const name = item.shortName ? item.shortName : item.name
const imageSource = item.iconSource.toString() const imageSource = item.iconSource.toString()
holdingsModel.append({ type, key, name, amount, imageSource, operator }) holdingsModel.append({ type, key, name, amount, imageSource, operator })
d.permissions.append([{ key }, { operator }])
} }
onAddToken: { onAddToken: {
@ -120,13 +94,12 @@ Flickable {
const icon = Style.svg("ensUsernames") const icon = Style.svg("ensUsernames")
holdingsModel.append({type: HoldingTypes.Type.Ens, key, name, amount: 1, imageSource: icon, operator }) holdingsModel.append({type: HoldingTypes.Type.Ens, key, name, amount: 1, imageSource: icon, operator })
d.permissions.append([{ key }, { operator }])
dropdown.close() dropdown.close()
} }
onUpdateToken: { onUpdateToken: {
const modelItem = store.getTokenByKey(key) const modelItem = store.getTokenByKey(key)
const name = modelItem.name const name = modelItem.shortName ? modelItem.shortName : modelItem.name
const imageSource = modelItem.iconSource.toString() const imageSource = modelItem.iconSource.toString()
holdingsModel.set(tokensSelector.editedIndex, { type: HoldingTypes.Type.Token, key, name, amount, imageSource }) holdingsModel.set(tokensSelector.editedIndex, { type: HoldingTypes.Type.Token, key, name, amount, imageSource })
@ -155,7 +128,7 @@ Flickable {
holdingsModel.remove(tokensSelector.editedIndex) holdingsModel.remove(tokensSelector.editedIndex)
if (holdingsModel.count) { if (holdingsModel.count) {
holdingsModel.set(0, { operator: SQ.Utils.Operators.None}) holdingsModel.set(0, { operator: OperatorsUtils.Operators.None})
} }
dropdown.close() dropdown.close()
@ -229,7 +202,8 @@ Flickable {
value: QtObject { value: QtObject {
id: permissionsListObjectModel id: permissionsListObjectModel
readonly property int operator: SQ.Utils.Operators.None readonly property int operator: OperatorsUtils.Operators.None
property var key
property string text: "" property string text: ""
property string imageSource: "" property string imageSource: ""
} }
@ -244,6 +218,7 @@ Flickable {
onDone: { onDone: {
d.permissionType = permissionType d.permissionType = permissionType
permissionsListObjectModel.key = permissionType
permissionsListObjectModel.text = title permissionsListObjectModel.text = title
permissionsListObjectModel.imageSource = asset permissionsListObjectModel.imageSource = asset
permissionsDropdown.close() permissionsDropdown.close()
@ -321,13 +296,13 @@ Flickable {
StatusButton { StatusButton {
Layout.topMargin: 24 Layout.topMargin: 24
text: qsTr("Create permission") text: qsTr("Create permission")
enabled: d.permissions.count > 0 enabled: holdingsModel.count > 0 && permissionsListObjectModel.key !== undefined
Layout.preferredHeight: 44 Layout.preferredHeight: 44
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true Layout.fillWidth: true
onClicked: { onClicked: {
root.store.createPermissions(d.permissions) root.store.createPermissions(holdingsModel, permissionsListObjectModel, d.isPrivate)
root.clearPermissions() root.permissionCreated()
} }
} }
} }

View File

@ -0,0 +1,65 @@
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 SortFilterProxyModel 0.2
import utils 1.0
import AppLayouts.Chat.controls.community 1.0
Flickable {
id: root
property var store
property int viewWidth: 560 // by design
contentWidth: mainLayout.width
contentHeight: mainLayout.height + mainLayout.anchors.topMargin
clip: true
flickableDirection: Flickable.AutoFlickIfNeeded
ColumnLayout {
id: mainLayout
width: root.viewWidth
spacing: 24
Repeater {
model: root.store.permissionsModel
delegate: PermissionItem {
Layout.preferredWidth: root.viewWidth
holdingsListModel: SortFilterProxyModel {
sourceModel: model.holdingsListModel
proxyRoles: ExpressionRole {
name: "text"
expression: root.store.setHoldingsTextFormat(model.type, model.name, model.amount)
}
}
permissionName: model.permissionsObjectModel.text
permissionImageSource: model.permissionsObjectModel.imageSource
channelsListModel: SortFilterProxyModel {
sourceModel: model.channelsListModel
proxyRoles: [
ExpressionRole {
name: "text"
expression: model.name
},
ExpressionRole {
name: "imageSource"
expression: model.iconSource
}
]
}
isPrivate: model.isPrivate
onEditClicked: store.editPermission(model.index)
onDuplicateClicked: store.duplicatePermission(model.index)
onRemoveClicked: store.removePermission(model.index)
}
}
}
}

View File

@ -10,7 +10,7 @@ import utils 1.0
Flickable { Flickable {
id: root id: root
signal addPermission() property int viewWidth: 560 // by design
contentWidth: mainLayout.width contentWidth: mainLayout.width
contentHeight: mainLayout.height + mainLayout.anchors.topMargin contentHeight: mainLayout.height + mainLayout.anchors.topMargin
@ -19,7 +19,7 @@ Flickable {
ColumnLayout { ColumnLayout {
id: mainLayout id: mainLayout
width: 560 // by design width: root.viewWidth
spacing: 24 spacing: 24
Rectangle { Rectangle {
@ -127,13 +127,5 @@ Flickable {
} }
} }
} }
StatusButton {
text: qsTr("Add permission")
height: 44
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
onClicked: root.addPermission()
}
} }
} }

View File

@ -0,0 +1,3 @@
CommunityWelcomePermissionsView 1.0 CommunityWelcomePermissionsView.qml
CommunityNewPermissionView 1.0 CommunityNewPermissionView.qml
CommunityPermissionsView 1.0 CommunityPermissionsView.qml