fix: can't join an encrypted community
- fix the corner case and allow the user to join a community without an explicitely stated "Member" permission - enable/disable the Share/Join/Save buttons when the permission to join check is ongoing, or when the permission check failed - display tooltips over the disabled buttons explaining why it's disabled - always display the eligibility button floating on top of the (scrollable) contents Fixes #14473 Fixes #14299
This commit is contained in:
parent
78acdca225
commit
0c8231a6b6
|
@ -55,6 +55,7 @@ SplitView {
|
||||||
|
|
||||||
isInvitationPending: ctrlIsInvitationPending.checked
|
isInvitationPending: ctrlIsInvitationPending.checked
|
||||||
requirementsCheckPending: ctrlRequirementsCheckPending.checked
|
requirementsCheckPending: ctrlRequirementsCheckPending.checked
|
||||||
|
joinPermissionsCheckSuccessful: ctrlJoinPermissionsCheckSuccessful.checked
|
||||||
|
|
||||||
walletAccountsModel: WalletAccountsModel {}
|
walletAccountsModel: WalletAccountsModel {}
|
||||||
walletAssetsModel: root.walletAssetStore.groupedAccountAssetsModel
|
walletAssetsModel: root.walletAssetStore.groupedAccountAssetsModel
|
||||||
|
@ -80,7 +81,7 @@ SplitView {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
SplitView.fillWidth: true
|
SplitView.fillWidth: true
|
||||||
|
@ -218,6 +219,14 @@ Nemo enim 😋 ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||||
text: "Requirements check pending"
|
text: "Requirements check pending"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
Layout.leftMargin: 12
|
||||||
|
id: ctrlJoinPermissionsCheckSuccessful
|
||||||
|
visible: !ctrlIsInvitationPending.checked
|
||||||
|
text: "Join permission successful"
|
||||||
|
checked: true
|
||||||
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ ToolTip {
|
||||||
|
|
||||||
implicitWidth: Math.min(maxWidth, implicitContentWidth + 16)
|
implicitWidth: Math.min(maxWidth, implicitContentWidth + 16)
|
||||||
padding: 8
|
padding: 8
|
||||||
|
margins: 8
|
||||||
delay: 200
|
delay: 200
|
||||||
background: Item {
|
background: Item {
|
||||||
id: statusToolTipBackground
|
id: statusToolTipBackground
|
||||||
|
|
|
@ -21,10 +21,11 @@ Dialog {
|
||||||
\qmlproperty color backgroundColor
|
\qmlproperty color backgroundColor
|
||||||
This property decides the modal background color
|
This property decides the modal background color
|
||||||
*/
|
*/
|
||||||
property string backgroundColor: Theme.palette.statusModal.backgroundColor
|
property color backgroundColor: Theme.palette.statusModal.backgroundColor
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty closeHandler
|
\qmlproperty closeHandler
|
||||||
This property decides the action to be performed when the close button is clicked. It allows to define
|
This property decides the action to be performed when the close button is clicked. It allows to define
|
||||||
|
a custom function to be called when the popup is closed by the user.
|
||||||
*/
|
*/
|
||||||
property var closeHandler: root.close
|
property var closeHandler: root.close
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int roleByName(QAbstractItemModel* model, const QString &roleName)
|
constexpr int roleByName(QAbstractItemModel* model, const QString &roleName)
|
||||||
{
|
{
|
||||||
if (!model)
|
if (!model)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -161,18 +161,23 @@ int /*PermissionTypes::Type*/ PermissionUtilsInternal::isEligibleToJoinAs(QAbstr
|
||||||
}
|
}
|
||||||
|
|
||||||
QSet<PermissionTypes::Type> tmpRes;
|
QSet<PermissionTypes::Type> tmpRes;
|
||||||
bool hasAnyJoinPermission{false};
|
bool hasMemberPermission{false};
|
||||||
constexpr auto isJoinTypePermission = [](PermissionTypes::Type type) {
|
constexpr auto isJoinTypePermission = [](PermissionTypes::Type type) {
|
||||||
return type == PermissionTypes::Type::TokenMaster ||
|
return type == PermissionTypes::Type::TokenMaster ||
|
||||||
type == PermissionTypes::Type::Admin ||
|
type == PermissionTypes::Type::Admin ||
|
||||||
type == PermissionTypes::Type::Member;
|
type == PermissionTypes::Type::Member;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr auto isMemberPermission = [](PermissionTypes::Type type) {
|
||||||
|
return type == PermissionTypes::Type::Member;
|
||||||
|
};
|
||||||
|
|
||||||
const auto permissionsCount = permissionsModel->rowCount();
|
const auto permissionsCount = permissionsModel->rowCount();
|
||||||
for (int i = 0; i < permissionsCount; i++) {
|
for (int i = 0; i < permissionsCount; i++) {
|
||||||
const auto permissionType = static_cast<PermissionTypes::Type>(permissionsModel->data(permissionsModel->index(i, 0), permissionTypeRole).toInt());
|
const auto permissionType = static_cast<PermissionTypes::Type>(permissionsModel->data(permissionsModel->index(i, 0), permissionTypeRole).toInt());
|
||||||
if (isJoinTypePermission(permissionType)) {
|
if (isJoinTypePermission(permissionType)) {
|
||||||
hasAnyJoinPermission = true;
|
if (isMemberPermission(permissionType))
|
||||||
|
hasMemberPermission = true;
|
||||||
const auto tokenCriteriaMet = permissionsModel->data(permissionsModel->index(i, 0), tokenCriteriaMetRole).toBool();
|
const auto tokenCriteriaMet = permissionsModel->data(permissionsModel->index(i, 0), tokenCriteriaMetRole).toBool();
|
||||||
if (tokenCriteriaMet) {
|
if (tokenCriteriaMet) {
|
||||||
tmpRes.insert(permissionType);
|
tmpRes.insert(permissionType);
|
||||||
|
@ -180,16 +185,13 @@ int /*PermissionTypes::Type*/ PermissionUtilsInternal::isEligibleToJoinAs(QAbstr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasAnyJoinPermission)
|
|
||||||
return PermissionTypes::Type::Member;
|
|
||||||
|
|
||||||
if (tmpRes.contains(PermissionTypes::Type::TokenMaster))
|
if (tmpRes.contains(PermissionTypes::Type::TokenMaster))
|
||||||
return PermissionTypes::Type::TokenMaster;
|
return PermissionTypes::Type::TokenMaster;
|
||||||
|
|
||||||
if (tmpRes.contains(PermissionTypes::Type::Admin))
|
if (tmpRes.contains(PermissionTypes::Type::Admin))
|
||||||
return PermissionTypes::Type::Admin;
|
return PermissionTypes::Type::Admin;
|
||||||
|
|
||||||
if (tmpRes.contains(PermissionTypes::Type::Member))
|
if (tmpRes.contains(PermissionTypes::Type::Member) || !hasMemberPermission)
|
||||||
return PermissionTypes::Type::Member;
|
return PermissionTypes::Type::Member;
|
||||||
|
|
||||||
return PermissionTypes::Type::None;
|
return PermissionTypes::Type::None;
|
||||||
|
|
|
@ -621,6 +621,7 @@ QtObject {
|
||||||
readonly property string image: model.image
|
readonly property string image: model.image
|
||||||
readonly property bool joined: model.joined
|
readonly property bool joined: model.joined
|
||||||
readonly property bool amIBanned: model.amIBanned
|
readonly property bool amIBanned: model.amIBanned
|
||||||
|
readonly property string introMessage: model.introMessage
|
||||||
// add others when needed..
|
// add others when needed..
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ Control {
|
||||||
required property int /*PermissionTypes.Type*/ eligibleToJoinAs
|
required property int /*PermissionTypes.Type*/ eligibleToJoinAs
|
||||||
|
|
||||||
property bool requirementsCheckPending: false
|
property bool requirementsCheckPending: false
|
||||||
|
property bool joinPermissionsCheckSuccessful
|
||||||
|
|
||||||
required property string communityId
|
required property string communityId
|
||||||
required property string communityName
|
required property string communityName
|
||||||
|
@ -101,11 +102,27 @@ Control {
|
||||||
onClicked: root.close()
|
onClicked: root.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property var saveButton: StatusButton {
|
readonly property string tooltipText: {
|
||||||
enabled: d.dirty
|
if (root.requirementsCheckPending)
|
||||||
type: d.lostCommunityPermission || d.lostChannelPermissions ? StatusBaseButton.Type.Danger : StatusBaseButton.Type.Normal
|
return qsTr("Requirements check pending")
|
||||||
visible: root.isEditMode
|
|
||||||
|
|
||||||
|
if (!root.joinPermissionsCheckSuccessful)
|
||||||
|
return qsTr("Checking permissions to join failed")
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property var saveButton: StatusButton {
|
||||||
|
visible: root.isEditMode
|
||||||
|
interactive: d.dirty && !root.requirementsCheckPending && root.joinPermissionsCheckSuccessful
|
||||||
|
loading: root.requirementsCheckPending
|
||||||
|
type: d.lostCommunityPermission || d.lostChannelPermissions ? StatusBaseButton.Type.Danger : StatusBaseButton.Type.Normal
|
||||||
|
tooltip.text: {
|
||||||
|
if (interactive)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
return d.tooltipText
|
||||||
|
}
|
||||||
text: {
|
text: {
|
||||||
if (d.lostCommunityPermission) {
|
if (d.lostCommunityPermission) {
|
||||||
return qsTr("Save changes & leave %1").arg(root.communityName)
|
return qsTr("Save changes & leave %1").arg(root.communityName)
|
||||||
|
@ -147,7 +164,14 @@ Control {
|
||||||
|
|
||||||
readonly property var shareAddressesButton: StatusButton {
|
readonly property var shareAddressesButton: StatusButton {
|
||||||
visible: !root.isEditMode
|
visible: !root.isEditMode
|
||||||
enabled: root.eligibleToJoinAs !== PermissionTypes.Type.None
|
interactive: root.eligibleToJoinAs !== PermissionTypes.Type.None && root.joinPermissionsCheckSuccessful
|
||||||
|
loading: root.requirementsCheckPending
|
||||||
|
tooltip.text: {
|
||||||
|
if (interactive)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
return d.tooltipText
|
||||||
|
}
|
||||||
text: {
|
text: {
|
||||||
if (d.selectedSharedAddressesCount === root.totalNumOfAddressesForSharing) {
|
if (d.selectedSharedAddressesCount === root.totalNumOfAddressesForSharing) {
|
||||||
return qsTr("Share all addresses to join")
|
return qsTr("Share all addresses to join")
|
||||||
|
@ -306,6 +330,7 @@ Control {
|
||||||
assetsModel: root.assetsModel
|
assetsModel: root.assetsModel
|
||||||
collectiblesModel: root.collectiblesModel
|
collectiblesModel: root.collectiblesModel
|
||||||
requirementsCheckPending: root.requirementsCheckPending
|
requirementsCheckPending: root.requirementsCheckPending
|
||||||
|
joinPermissionsCheckSuccessful: root.joinPermissionsCheckSuccessful
|
||||||
communityName: root.communityName
|
communityName: root.communityName
|
||||||
communityIcon: root.communityIcon
|
communityIcon: root.communityIcon
|
||||||
eligibleToJoinAs: root.eligibleToJoinAs
|
eligibleToJoinAs: root.eligibleToJoinAs
|
||||||
|
|
|
@ -32,6 +32,7 @@ Rectangle {
|
||||||
property var collectiblesModel
|
property var collectiblesModel
|
||||||
|
|
||||||
property bool requirementsCheckPending
|
property bool requirementsCheckPending
|
||||||
|
property bool joinPermissionsCheckSuccessful
|
||||||
|
|
||||||
readonly property bool lostPermissionToJoin: d.lostPermissionToJoin
|
readonly property bool lostPermissionToJoin: d.lostPermissionToJoin
|
||||||
readonly property bool lostChannelPermissions: d.lostChannelPermissions
|
readonly property bool lostChannelPermissions: d.lostChannelPermissions
|
||||||
|
@ -256,6 +257,7 @@ Rectangle {
|
||||||
|
|
||||||
CommunityEligibilityTag {
|
CommunityEligibilityTag {
|
||||||
id: eligibilityHintBubble
|
id: eligibilityHintBubble
|
||||||
|
visible: !root.requirementsCheckPending && root.joinPermissionsCheckSuccessful
|
||||||
eligibleToJoinAs: root.eligibleToJoinAs
|
eligibleToJoinAs: root.eligibleToJoinAs
|
||||||
isEditMode: root.isEditMode
|
isEditMode: root.isEditMode
|
||||||
isDirty: root.isDirty
|
isDirty: root.isDirty
|
||||||
|
|
|
@ -18,6 +18,8 @@ QtObject {
|
||||||
property var communitiesModuleInst: communitiesModule
|
property var communitiesModuleInst: communitiesModule
|
||||||
property bool newVersionAvailable: false
|
property bool newVersionAvailable: false
|
||||||
readonly property bool requirementsCheckPending: communitiesModuleInst.requirementsCheckPending
|
readonly property bool requirementsCheckPending: communitiesModuleInst.requirementsCheckPending
|
||||||
|
readonly property bool joinPermissionsCheckSuccessful: communitiesModuleInst.joinPermissionsCheckSuccessful
|
||||||
|
readonly property bool channelsPermissionsCheckSuccessful: communitiesModuleInst.channelsPermissionsCheckSuccessful
|
||||||
property string latestVersion
|
property string latestVersion
|
||||||
property string downloadURL
|
property string downloadURL
|
||||||
|
|
||||||
|
|
|
@ -705,6 +705,7 @@ QtObject {
|
||||||
id: dialogRoot
|
id: dialogRoot
|
||||||
|
|
||||||
requirementsCheckPending: root.rootStore.requirementsCheckPending
|
requirementsCheckPending: root.rootStore.requirementsCheckPending
|
||||||
|
joinPermissionsCheckSuccessful: root.rootStore.joinPermissionsCheckSuccessful
|
||||||
|
|
||||||
walletAccountsModel: root.rootStore.walletAccountsModel
|
walletAccountsModel: root.rootStore.walletAccountsModel
|
||||||
walletCollectiblesModel: WalletStore.RootStore.collectiblesStore.allCollectiblesModel
|
walletCollectiblesModel: WalletStore.RootStore.collectiblesStore.allCollectiblesModel
|
||||||
|
@ -952,7 +953,9 @@ QtObject {
|
||||||
|
|
||||||
communityName: chatStore.sectionDetails.name
|
communityName: chatStore.sectionDetails.name
|
||||||
communityIcon: chatStore.sectionDetails.image
|
communityIcon: chatStore.sectionDetails.image
|
||||||
|
|
||||||
requirementsCheckPending: root.rootStore.requirementsCheckPending
|
requirementsCheckPending: root.rootStore.requirementsCheckPending
|
||||||
|
joinPermissionsCheckSuccessful: root.rootStore.joinPermissionsCheckSuccessful
|
||||||
|
|
||||||
introMessage: chatStore.sectionDetails.introMessage
|
introMessage: chatStore.sectionDetails.introMessage
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,8 @@ StatusStackModal {
|
||||||
required property string communityIcon
|
required property string communityIcon
|
||||||
required property bool requirementsCheckPending
|
required property bool requirementsCheckPending
|
||||||
|
|
||||||
|
property bool joinPermissionsCheckSuccessful
|
||||||
|
|
||||||
property string introMessage
|
property string introMessage
|
||||||
|
|
||||||
property bool isInvitationPending: false
|
property bool isInvitationPending: false
|
||||||
|
@ -84,12 +86,31 @@ StatusStackModal {
|
||||||
rightButtons: [d.shareButton, finishButton]
|
rightButtons: [d.shareButton, finishButton]
|
||||||
|
|
||||||
finishButton: StatusButton {
|
finishButton: StatusButton {
|
||||||
enabled: {
|
interactive: {
|
||||||
if (root.isInvitationPending || d.accessType !== Constants.communityChatOnRequestAccess)
|
if (root.isInvitationPending)
|
||||||
|
return true
|
||||||
|
|
||||||
|
if (root.requirementsCheckPending || !root.joinPermissionsCheckSuccessful)
|
||||||
|
return false
|
||||||
|
|
||||||
|
if (d.accessType !== Constants.communityChatOnRequestAccess)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
return d.eligibleToJoinAs !== PermissionTypes.Type.None
|
return d.eligibleToJoinAs !== PermissionTypes.Type.None
|
||||||
}
|
}
|
||||||
|
loading: root.requirementsCheckPending && !root.isInvitationPending
|
||||||
|
tooltip.text: {
|
||||||
|
if (interactive)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
if (root.requirementsCheckPending)
|
||||||
|
return qsTr("Requirements check pending")
|
||||||
|
|
||||||
|
if (!root.joinPermissionsCheckSuccessful)
|
||||||
|
return qsTr("Checking permissions to join failed")
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
text: {
|
text: {
|
||||||
if (root.isInvitationPending) {
|
if (root.isInvitationPending) {
|
||||||
return qsTr("Cancel Membership Request")
|
return qsTr("Cancel Membership Request")
|
||||||
|
@ -269,7 +290,7 @@ StatusStackModal {
|
||||||
d.selectedSharedAddressesMap = tmpMap
|
d.selectedSharedAddressesMap = tmpMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns an object containing all selected addresses and selected airdrop address.s
|
// Returns an object containing all selected addresses and selected airdrop address
|
||||||
function getSelectedAddresses() {
|
function getSelectedAddresses() {
|
||||||
const result = {addresses: [], airdropAddress: ""}
|
const result = {addresses: [], airdropAddress: ""}
|
||||||
for (const [key, value] of d.selectedSharedAddressesMap) {
|
for (const [key, value] of d.selectedSharedAddressesMap) {
|
||||||
|
@ -341,6 +362,7 @@ StatusStackModal {
|
||||||
communityName: root.communityName
|
communityName: root.communityName
|
||||||
communityIcon: root.communityIcon
|
communityIcon: root.communityIcon
|
||||||
requirementsCheckPending: root.requirementsCheckPending
|
requirementsCheckPending: root.requirementsCheckPending
|
||||||
|
joinPermissionsCheckSuccessful: root.joinPermissionsCheckSuccessful
|
||||||
|
|
||||||
walletAccountsModel: d.initialAddressesModel
|
walletAccountsModel: d.initialAddressesModel
|
||||||
|
|
||||||
|
@ -416,36 +438,47 @@ StatusStackModal {
|
||||||
}
|
}
|
||||||
|
|
||||||
stackItems: [
|
stackItems: [
|
||||||
StatusScrollView {
|
Item {
|
||||||
id: scrollView
|
implicitHeight: scrollView.contentHeight + scrollView.bottomPadding + eligibilityTag.anchors.bottomMargin
|
||||||
contentWidth: availableWidth
|
|
||||||
|
|
||||||
ColumnLayout {
|
StatusScrollView {
|
||||||
spacing: 24
|
id: scrollView
|
||||||
width: scrollView.availableWidth
|
anchors.fill: parent
|
||||||
|
contentWidth: availableWidth
|
||||||
|
bottomPadding: 80
|
||||||
|
|
||||||
StatusRoundedImage {
|
ColumnLayout {
|
||||||
Layout.alignment: Qt.AlignHCenter
|
spacing: Style.current.bigPadding
|
||||||
Layout.preferredWidth: 64
|
width: parent.width
|
||||||
Layout.preferredHeight: Layout.preferredWidth
|
|
||||||
visible: ((image.status == Image.Loading) ||
|
StatusRoundedImage {
|
||||||
(image.status == Image.Ready)) &&
|
Layout.alignment: Qt.AlignHCenter
|
||||||
!image.isError
|
Layout.preferredWidth: 64
|
||||||
image.source: root.communityIcon
|
Layout.preferredHeight: Layout.preferredWidth
|
||||||
|
visible: ((image.status == Image.Loading) ||
|
||||||
|
(image.status == Image.Ready)) &&
|
||||||
|
!image.isError
|
||||||
|
image.source: root.communityIcon
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: root.introMessage || qsTr("Community <b>%1</b> has no intro message...").arg(root.communityName)
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StatusBaseText {
|
CommunityEligibilityTag {
|
||||||
Layout.fillWidth: true
|
id: eligibilityTag
|
||||||
text: root.introMessage || qsTr("Community <b>%1</b> has no intro message...").arg(root.communityName)
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
color: Theme.palette.directColor1
|
anchors.bottom: parent.bottom
|
||||||
wrapMode: Text.WordWrap
|
anchors.bottomMargin: Style.current.bigPadding
|
||||||
}
|
eligibleToJoinAs: d.eligibleToJoinAs
|
||||||
|
isEditMode: root.isEditMode
|
||||||
CommunityEligibilityTag {
|
visible: !root.isInvitationPending && !root.requirementsCheckPending && root.joinPermissionsCheckSuccessful &&
|
||||||
Layout.alignment: Qt.AlignHCenter
|
d.accessType === Constants.communityChatOnRequestAccess
|
||||||
eligibleToJoinAs: d.eligibleToJoinAs
|
|
||||||
visible: !root.isInvitationPending && d.accessType === Constants.communityChatOnRequestAccess
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue