fix(CommunityPortal): don't show PermissionsRow for free communities

- hide the permissions row and tokens when the community is free to join
- fix evaluating the `requirementsMet` property which affects the lock
icon state; that role was never part of the model
- add a helper C++ method `isTokenGatedCommunity`
- adjust the SB models, adding different variations of the
permissionsModel for the CommunitiesPortalLayoutPage

Fixes #14671
This commit is contained in:
Lukáš Tinkl 2024-05-10 16:55:20 +02:00 committed by Lukáš Tinkl
parent 94ca1ff22a
commit 2537cdc2f2
8 changed files with 94 additions and 39 deletions

View File

@ -3,6 +3,9 @@ import QtQuick 2.14
import Models 1.0
ListModel {
readonly property var emptyModel: ListModel {}
Component.onCompleted: append([
{
featured: true,
@ -97,8 +100,6 @@ ListModel {
]),
permissionsModel: PermissionsModel.moreThanTwoInitialShortPermissionsModel,
allTokenRequirementsMet: false
},
{
featured: false,
@ -136,7 +137,7 @@ ListModel {
popularity: 4,
available: true,
tags: JSON.stringify([]),
permissionsModel: PermissionsModel.threeShortPermissionsModelData,
permissionsModel: PermissionsModel.channelsOnlyPermissionsModelNotMet,
allTokenRequirementsMet: false
},
{
@ -183,7 +184,7 @@ ListModel {
popularity: 4,
available: true,
tags: JSON.stringify([]),
permissionsModel: PermissionsModel.threeShortPermissionsModel,
permissionsModel: PermissionsModel.channelsOnlyPermissionsModel,
allTokenRequirementsMet: false
},
{
@ -233,7 +234,8 @@ ListModel {
activeMembers: 0,
popularity: 4,
available: true,
tags: JSON.stringify([])
tags: JSON.stringify([]),
permissionsModel: emptyModel
}
])
}

View File

@ -32,9 +32,10 @@ SplitView {
SplitView.fillHeight: true
assetsModel: AssetsModel {}
collectiblesModel: CollectiblesModel {}
collectiblesModel: CollectiblesModel {}
communitiesStore: CommunitiesStore {
readonly property int unreadNotificationsCount: 42
readonly property bool createCommunityEnabled: true
readonly property string communityTags: ModelsData.communityTags
readonly property var curatedCommunitiesModel: SortFilterProxyModel {

View File

@ -92,7 +92,8 @@ QtObject {
channelsListModel: root.createChannelsModel2(),
permissionType: PermissionTypes.Type.Member,
permissionState: PermissionTypes.State.Approved,
isPrivate: false
isPrivate: false,
tokenCriteriaMet: false
}
]
@ -103,7 +104,8 @@ QtObject {
channelsListModel: root.createChannelsModel(),
permissionType: PermissionTypes.Type.Admin,
permissionState: PermissionTypes.State.Approved,
isPrivate: false
isPrivate: false,
tokenCriteriaMet: true
}
]
@ -113,21 +115,24 @@ QtObject {
channelsListModel: root.createChannelsModel2(),
permissionType: PermissionTypes.Type.Member,
permissionState: PermissionTypes.State.Approved,
isPrivate: false
isPrivate: false,
tokenCriteriaMet: false
},
{
holdingsListModel: root.createHoldingsModel2(),
channelsListModel: root.createChannelsModel2(),
permissionType: PermissionTypes.Type.Member,
permissionState: PermissionTypes.State.Approved,
isPrivate: false
isPrivate: false,
tokenCriteriaMet: true
},
{
holdingsListModel: root.createHoldingsModel1(),
channelsListModel: root.createChannelsModel2(),
permissionType: PermissionTypes.Type.Member,
permissionState: PermissionTypes.State.Approved,
isPrivate: false
isPrivate: false,
tokenCriteriaMet: false
}
]
@ -137,14 +142,16 @@ QtObject {
channelsListModel: root.createChannelsModel1(),
permissionType: PermissionTypes.Type.Admin,
permissionState: PermissionTypes.State.Approved,
isPrivate: true
isPrivate: true,
tokenCriteriaMet: false
},
{
holdingsListModel: root.createHoldingsModel2(),
channelsListModel: root.createChannelsModel2(),
permissionType: PermissionTypes.Type.Member,
permissionState: PermissionTypes.State.Approved,
isPrivate: false
isPrivate: false,
tokenCriteriaMet: true
}
]
@ -154,14 +161,16 @@ QtObject {
channelsListModel: root.createChannelsModel1(),
permissionType: PermissionTypes.Type.Admin,
permissionState: PermissionTypes.State.Approved,
isPrivate: true
isPrivate: true,
tokenCriteriaMet: true
},
{
holdingsListModel: root.createHoldingsModel4(),
channelsListModel: root.createChannelsModel2(),
permissionType: PermissionTypes.Type.Member,
permissionState: PermissionTypes.State.Approved,
isPrivate: false
isPrivate: false,
tokenCriteriaMet: false
}
]
@ -171,21 +180,24 @@ QtObject {
channelsListModel: root.createChannelsModel1(),
permissionType: PermissionTypes.Type.Admin,
permissionState: PermissionTypes.State.Approved,
isPrivate: true
isPrivate: true,
tokenCriteriaMet: false
},
{
holdingsListModel: root.createHoldingsModel1b(),
channelsListModel: root.createChannelsModel2(),
permissionType: PermissionTypes.Type.Member,
permissionState: PermissionTypes.State.Approved,
isPrivate: false
isPrivate: false,
tokenCriteriaMet: false
},
{
holdingsListModel: root.createHoldingsModel2(),
channelsListModel: root.createChannelsModel2(),
permissionType: PermissionTypes.Type.Member,
permissionState: PermissionTypes.State.Approved,
isPrivate: false
isPrivate: false,
tokenCriteriaMet: false
}
]
@ -195,28 +207,32 @@ QtObject {
channelsListModel: root.createChannelsModel1(),
permissionType: PermissionTypes.Type.Admin,
permissionState: PermissionTypes.State.Approved,
isPrivate: true
isPrivate: true,
tokenCriteriaMet: false
},
{
holdingsListModel: root.createHoldingsModel2(),
channelsListModel: root.createChannelsModel2(),
permissionType: PermissionTypes.Type.Member,
permissionState: PermissionTypes.State.Approved,
isPrivate: false
isPrivate: false,
tokenCriteriaMet: false
},
{
holdingsListModel: root.createHoldingsModel3(),
channelsListModel: root.createChannelsModel2(),
permissionType: PermissionTypes.Type.Member,
permissionState: PermissionTypes.State.Approved,
isPrivate: false
isPrivate: false,
tokenCriteriaMet: true
},
{
holdingsListModel: root.createHoldingsModel5(),
channelsListModel: root.createChannelsModel2(),
permissionType: PermissionTypes.Type.Member,
permissionState: PermissionTypes.State.Approved,
isPrivate: false
isPrivate: false,
tokenCriteriaMet: true
}
]

View File

@ -3,6 +3,8 @@
#include <QObject>
#include <QJsonArray>
#include <optional>
class QAbstractItemModel;
namespace PermissionTypes {
@ -27,9 +29,15 @@ public:
//!< Check whether the user can join the community and under which (highest possible) role
//!< @return either:
//! - `NoPermissions` if the permissionsModel is empty or malformed
//! - `Member` if no such join permission(s) exist in the permissionsModel (e.g. when it has channel only permissions)
//! - `NoPermissions` if the permissionsModel is empty or malformed, or has no join type permissions
//! - if satisfied: `TokenMaster`, `Admin`, or `Member`, in this order of relevance
//! - `Member` if no such join permission(s) exist in the permissionsModel (e.g. when it has channel only permissions)
//! - `None` if no permission to join is satisfied (user can't join at all)
Q_INVOKABLE int /*PermissionTypes::Type*/ isEligibleToJoinAs(QAbstractItemModel *permissionsModel) const;
//!< @return true when the @p permissionsModel contains some kind of "join" permission; false when the community is free to join
Q_INVOKABLE bool isTokenGatedCommunity(QAbstractItemModel *permissionsModel) const;
private:
std::optional<PermissionTypes::Type> isEligibleToJoinAsInternal(QAbstractItemModel *permissionsModel) const;
};

View File

@ -143,7 +143,8 @@ QJsonArray PermissionUtilsInternal::getUniquePermissionChannels(QAbstractItemMod
return result;
}
int /*PermissionTypes::Type*/ PermissionUtilsInternal::isEligibleToJoinAs(QAbstractItemModel *permissionsModel) const
std::optional<PermissionTypes::Type> PermissionUtilsInternal::isEligibleToJoinAsInternal(
QAbstractItemModel *permissionsModel) const
{
if (!permissionsModel)
return PermissionTypes::Type::NoPermissions;
@ -160,8 +161,6 @@ int /*PermissionTypes::Type*/ PermissionUtilsInternal::isEligibleToJoinAs(QAbstr
return PermissionTypes::Type::NoPermissions;
}
QSet<PermissionTypes::Type> tmpRes;
bool hasMemberPermission{false};
constexpr auto isJoinTypePermission = [](PermissionTypes::Type type) {
return type == PermissionTypes::Type::TokenMaster ||
type == PermissionTypes::Type::Admin ||
@ -173,6 +172,8 @@ int /*PermissionTypes::Type*/ PermissionUtilsInternal::isEligibleToJoinAs(QAbstr
};
const auto permissionsCount = permissionsModel->rowCount();
bool hasMemberPermission{false};
QSet<PermissionTypes::Type> tmpRes;
for (int i = 0; i < permissionsCount; i++) {
const auto permissionType = static_cast<PermissionTypes::Type>(permissionsModel->data(permissionsModel->index(i, 0), permissionTypeRole).toInt());
if (isJoinTypePermission(permissionType)) {
@ -191,10 +192,24 @@ int /*PermissionTypes::Type*/ PermissionUtilsInternal::isEligibleToJoinAs(QAbstr
if (tmpRes.contains(PermissionTypes::Type::Admin))
return PermissionTypes::Type::Admin;
if (tmpRes.contains(PermissionTypes::Type::Member) || !hasMemberPermission)
if (tmpRes.contains(PermissionTypes::Type::Member))
return PermissionTypes::Type::Member;
return PermissionTypes::Type::None;
if (!hasMemberPermission)
return {}; // no join permissions -> free to join
return PermissionTypes::Type::None; // not allowed to join due to permissions not satisfied
}
int /*PermissionTypes::Type*/ PermissionUtilsInternal::isEligibleToJoinAs(QAbstractItemModel *permissionsModel) const
{
return isEligibleToJoinAsInternal(permissionsModel).value_or(PermissionTypes::Type::Member);
}
bool PermissionUtilsInternal::isTokenGatedCommunity(QAbstractItemModel *permissionsModel) const
{
const auto result = isEligibleToJoinAsInternal(permissionsModel);
return result && *result > PermissionTypes::Type::NoPermissions;
}
QVariantMap PermissionUtilsInternal::getTokenByKey(QAbstractItemModel *model,

View File

@ -194,7 +194,6 @@ StatusSectionLayout {
visible: (d.searchMode && filteredCommunitiesModel.count === 0) || communitiesGrid.isEmpty
text: qsTr("No communities found")
color: Theme.palette.baseColor1
font.pixelSize: 15
}
}
}

View File

@ -63,6 +63,10 @@ QtObject {
return Internal.PermissionUtils.isEligibleToJoinAs(model)
}
function isTokenGatedCommunity(model) {
return Internal.PermissionUtils.isTokenGatedCommunity(model)
}
function setHoldingsTextFormat(type, name, amount, decimals) {
if (typeof amount === "string") {
amount = AmountsArithmetic.toNumber(AmountsArithmetic.fromString(amount), decimals)

View File

@ -11,6 +11,7 @@ import utils 1.0
import SortFilterProxyModel 0.2
import AppLayouts.Communities.controls 1.0
import AppLayouts.Communities.helpers 1.0
StatusScrollView {
id: root
@ -65,7 +66,7 @@ StatusScrollView {
readonly property string tags: model.tags
readonly property var permissionsList: model.permissionsModel
readonly property bool requirementsMet: !!model.allTokenRequirementsMet ? model.allTokenRequirementsMet : false
readonly property bool isTokenGatedCommunity: PermissionsHelpers.isTokenGatedCommunity(permissionsList)
JSONListModel {
id: tagsJson
@ -85,15 +86,24 @@ StatusScrollView {
categories: tagsJson.model
memberCountVisible: model.joined || !model.encrypted
// Community restrictions
rigthHeaderComponent: PermissionsRow {
visible: !!card.permissionsList && card.permissionsList.count > 0
assetsModel: root.assetsModel
collectiblesModel: root.collectiblesModel
model: card.permissionsList
requirementsMet: card.requirementsMet
overlappingBorder: 0
Binding {
target: card
property: "rigthHeaderComponent"
when: card.isTokenGatedCommunity
value: Component {
PermissionsRow {
readonly property int eligibleToJoinAs: PermissionsHelpers.isEligibleToJoinAs(card.permissionsList)
assetsModel: root.assetsModel
collectiblesModel: root.collectiblesModel
model: card.permissionsList
requirementsMet: eligibleToJoinAs === PermissionTypes.Type.Member
|| eligibleToJoinAs === PermissionTypes.Type.Admin
|| eligibleToJoinAs === PermissionTypes.Type.Owner
overlappingBorder: 0
}
}
}
onClicked: root.cardClicked(communityId)