feat(Settings): Add communities settings

Closes: #4932
This commit is contained in:
Boris Melnik 2022-03-23 13:56:25 +03:00
parent 50a88eb83c
commit 49ca3e1c36
31 changed files with 529 additions and 39 deletions

View File

@ -58,6 +58,10 @@ proc init*(self: Controller) =
self.delegate.communityEdited(community)
self.delegate.curatedCommunityEdited(CuratedCommunity(communityId: community.id, available: true, community:community))
self.events.on(SIGNAL_COMMUNITY_MUTED) do(e:Args):
let args = CommunityMutedArgs(e)
self.delegate.communityMuted(args.communityId, args.muted)
proc getAllCommunities*(self: Controller): seq[CommunityDto] =
result = self.communityService.getAllCommunities()

View File

@ -99,3 +99,6 @@ method onImportCommunityErrorOccured*(self: AccessInterface, error: string) {.ba
method viewDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method communityMuted*(self: AccessInterface, communityId: string, muted: bool) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -93,6 +93,7 @@ method getCommunityItem(self: Module, c: CommunityDto): SectionItem =
c.isMember,
c.permissions.access,
c.permissions.ensOnly,
c.muted,
c.members.map(proc(member: Member): user_item.Item =
let contactDetails = self.controller.getContactDetails(member.id)
result = user_item.initItem(
@ -185,6 +186,9 @@ method reorderCommunityCategories*(self: Module, communityId: string, categoryId
# self.controller.reorderCommunityCategories(communityId, categoryId, position)
discard
method communityMuted*(self: Module, communityId: string, muted: bool) =
self.view.model().setMuted(communityId, muted)
method requestToJoinCommunity*(self: Module, communityId: string, ensName: string) =
self.controller.requestToJoinCommunity(communityId, ensName)

View File

@ -123,3 +123,9 @@ QtObject:
proc importingCommunityStateChanged*(self:View, state: int, errorMsg: string) {.signal.}
proc emitImportingCommunityStateChangedSignal*(self: View, state: int, errorMsg: string) =
self.importingCommunityStateChanged(state, errorMsg)
proc isMemberOfCommunity*(self: View, communityId: string, pubKey: string): bool {.slot.} =
let sectionItem = self.model.getItemById(communityId)
if (section_item.id == ""):
return false
return sectionItem.hasMember(pubKey)

View File

@ -152,7 +152,7 @@ proc newModule*[T](
result.profileSectionModule = profile_section_module.newModule(
result, events, accountsService, settingsService, stickersService,
profileService, contactsService, aboutService, languageService, privacyService, nodeConfigurationService,
devicesService, mailserversService, chatService, ensService, walletAccountService, generalService
devicesService, mailserversService, chatService, ensService, walletAccountService, generalService, communityService
)
result.stickersModule = stickers_module.newModule(result, events, stickersService, settingsService, walletAccountService)
result.activityCenterModule = activity_center_module.newModule(result, events, activityCenterService, contactsService,
@ -217,6 +217,7 @@ proc createChannelGroupItem[T](self: Module[T], c: ChannelGroupDto): SectionItem
if (isCommunity): communityDetails.isMember else: true,
c.permissions.access,
c.permissions.ensOnly,
c.muted,
c.members.map(proc(member: ChatMember): user_item.Item =
let contactDetails = self.controller.getContactDetails(member.id)
result = user_item.initItem(

View File

@ -0,0 +1,28 @@
import io_interface
import ../../../../../app_service/service/community/service as community_service
type
Controller* = ref object of RootObj
delegate: io_interface.AccessInterface
communityService: community_service.Service
proc newController*(delegate: io_interface.AccessInterface,
communityService: community_service.Service): Controller =
result = Controller()
result.delegate = delegate
result.communityService = communityService
proc delete*(self: Controller) =
discard
proc inviteUsersToCommunity*(self: Controller, communityID: string, pubKeys: string): string =
result = self.communityService.inviteUsersToCommunityById(communityID, pubKeys)
proc leaveCommunity*(self: Controller, communityID: string) =
self.communityService.leaveCommunity(communityID)
method setCommunityMuted*(self: Controller, communityID: string, muted: bool) =
self.communityService.setCommunityMuted(communityID, muted)

View File

@ -0,0 +1,33 @@
import NimQml
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
## Abstract class for any input/interaction with this module.
method delete*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method load*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method isLoaded*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getModuleAsVariant*(self: AccessInterface): QVariant {.base.} =
raise newException(ValueError, "No implementation available")
# View Delegate Interface
# Delegate for the view must be declared here due to use of QtObject and multi
# inheritance, which is not well supported in Nim.
method viewDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method inviteUsersToCommunity*(self: AccessInterface, communityID: string, pubKeysJSON: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method leaveCommunity*(self: AccessInterface, communityID: string) {.base.} =
raise newException(ValueError, "No implementation available")
method setCommunityMuted*(self: AccessInterface, communityID: string, muted: bool) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -0,0 +1,52 @@
import NimQml, chronicles
import ./io_interface, ./view, ./controller
import ../io_interface as delegate_interface
import ../../../../core/eventemitter
import ../../../../../app_service/service/community/service as community_service
export io_interface
type
Module* = ref object of io_interface.AccessInterface
delegate: delegate_interface.AccessInterface
controller: Controller
view: View
viewVariant: QVariant
moduleLoaded: bool
proc newModule*(delegate: delegate_interface.AccessInterface,
communityService: community_service.Service):
Module =
result = Module()
result.delegate = delegate
result.view = newView(result)
result.viewVariant = newQVariant(result.view)
result.controller = controller.newController(result, communityService)
result.moduleLoaded = false
method delete*(self: Module) =
self.view.delete
method load*(self: Module) =
self.view.load()
method isLoaded*(self: Module): bool =
return self.moduleLoaded
method viewDidLoad*(self: Module) =
self.moduleLoaded = true
self.delegate.communitiesModuleDidLoad()
method getModuleAsVariant*(self: Module): QVariant =
return self.viewVariant
method inviteUsersToCommunity*(self: Module, communityID: string, pubKeysJSON: string): string =
result = self.controller.inviteUsersToCommunity(communityID, pubKeysJSON)
method leaveCommunity*(self: Module, communityID: string) =
self.controller.leaveCommunity(communityID)
method setCommunityMuted*(self: Module, communityID: string, muted: bool) =
self.controller.setCommunityMuted(communityID, muted)

View File

@ -0,0 +1,29 @@
import NimQml
import ./io_interface
QtObject:
type
View* = ref object of QObject
delegate: io_interface.AccessInterface
proc delete*(self: View) =
self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface): View =
new(result, delete)
result.QObject.setup
result.delegate = delegate
proc load*(self: View) =
self.delegate.viewDidLoad()
method inviteUsersToCommunity*(self: View, communityID: string, pubKeysJSON: string): string {.slot.} =
result = self.delegate.inviteUsersToCommunity(communityID, pubKeysJSON)
method leaveCommunity*(self: View, communityID: string) {.slot.} =
self.delegate.leaveCommunity(communityID)
method setCommunityMuted*(self: View, communityID: string, muted: bool) {.slot.} =
self.delegate.setCommunityMuted(communityID, muted)

View File

@ -78,4 +78,10 @@ method ensUsernamesModuleDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method getEnsUsernamesModule*(self: AccessInterface): QVariant {.base.} =
raise newException(ValueError, "No implementation available")
raise newException(ValueError, "No implementation available")
method getCommunitiesModule*(self: AccessInterface): QVariant {.base.} =
raise newException(ValueError, "No implementation available")
method communitiesModuleDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -18,6 +18,8 @@ import ../../../../app_service/service/stickers/service as stickersService
import ../../../../app_service/service/ens/service as ens_service
import ../../../../app_service/service/wallet_account/service as wallet_account_service
import ../../../../app_service/service/general/service as general_service
import ../../../../app_service/service/community/service as community_service
import ./profile/module as profile_module
import ./contacts/module as contacts_module
@ -29,6 +31,7 @@ import ./devices/module as devices_module
import ./sync/module as sync_module
import ./notifications/module as notifications_module
import ./ens_usernames/module as ens_usernames_module
import ./communities/module as communities_module
export io_interface
@ -50,6 +53,7 @@ type
syncModule: sync_module.AccessInterface
notificationsModule: notifications_module.AccessInterface
ensUsernamesModule: ens_usernames_module.AccessInterface
communitiesModule: communities_module.AccessInterface
proc newModule*(delegate: delegate_interface.AccessInterface,
events: EventEmitter,
@ -67,7 +71,8 @@ proc newModule*(delegate: delegate_interface.AccessInterface,
chatService: chat_service.Service,
ensService: ens_service.Service,
walletAccountService: wallet_account_service.Service,
generalService: general_service.Service
generalService: general_service.Service,
communityService: community_service.Service
): Module =
result = Module()
result.delegate = delegate
@ -88,6 +93,7 @@ proc newModule*(delegate: delegate_interface.AccessInterface,
result.ensUsernamesModule = ens_usernames_module.newModule(
result, events, settingsService, ensService, walletAccountService
)
result.communitiesModule = communities_module.newModule(result, communityService)
singletonInstance.engine.setRootContextProperty("profileSectionModule", result.viewVariant)
@ -100,6 +106,7 @@ method delete*(self: Module) =
self.advancedModule.delete
self.devicesModule.delete
self.syncModule.delete
self.communitiesModule.delete
self.view.delete
self.viewVariant.delete
@ -117,6 +124,7 @@ method load*(self: Module) =
self.syncModule.load()
self.notificationsModule.load()
self.ensUsernamesModule.load()
self.communitiesModule.load()
method isLoaded*(self: Module): bool =
return self.moduleLoaded
@ -152,6 +160,9 @@ proc checkIfModuleDidLoad(self: Module) =
if(not self.ensUsernamesModule.isLoaded()):
return
if(not self.communitiesModule.isLoaded()):
return
self.moduleLoaded = true
self.delegate.profileSectionDidLoad()
@ -214,3 +225,9 @@ method ensUsernamesModuleDidLoad*(self: Module) =
method getEnsUsernamesModule*(self: Module): QVariant =
self.ensUsernamesModule.getModuleAsVariant()
method getCommunitiesModule*(self: Module): QVariant =
self.communitiesModule.getModuleAsVariant()
method communitiesModuleDidLoad*(self: Module) =
self.checkIfModuleDidLoad()

View File

@ -65,3 +65,8 @@ QtObject:
return self.delegate.getEnsUsernamesModule()
QtProperty[QVariant] ensUsernamesModule:
read = getEnsUsernamesModule
proc getCommunitiesModule(self: View): QVariant {.slot.} =
return self.delegate.getCommunitiesModule()
QtProperty[QVariant] communitiesModule:
read = getCommunitiesModule

View File

@ -34,6 +34,7 @@ type
canRequestAccess: bool
access: int
ensOnly: bool
muted: bool
membersModel: user_model.Model
pendingRequestsToJoinModel: PendingRequestModel
historyArchiveSupportEnabled: bool
@ -60,6 +61,7 @@ proc initItem*(
isMember = false,
access: int = 0,
ensOnly = false,
muted = false,
members: seq[user_item.Item] = @[],
pendingRequestsToJoin: seq[PendingRequestItem] = @[],
historyArchiveSupportEnabled = false,
@ -85,6 +87,7 @@ proc initItem*(
result.isMember = isMember
result.access = access
result.ensOnly = ensOnly
result.muted = muted
result.membersModel = newModel()
result.membersModel.setItems(members)
result.pendingRequestsToJoinModel = newPendingRequestModel()
@ -117,6 +120,7 @@ proc `$`*(self: SectionItem): string =
isMember:{self.isMember},
access:{self.access},
ensOnly:{self.ensOnly},
muted:{self.muted},
members:{self.membersModel},
historyArchiveSupportEnabled:{self.historyArchiveSupportEnabled},
pinMessageAllMembersEnabled:{self.pinMessageAllMembersEnabled},
@ -194,6 +198,12 @@ proc access*(self: SectionItem): int {.inline.} =
proc ensOnly*(self: SectionItem): bool {.inline.} =
self.ensOnly
proc muted*(self: SectionItem): bool {.inline.} =
self.muted
proc `muted=`*(self: var SectionItem, value: bool) {.inline.} =
self.muted = value
proc members*(self: SectionItem): user_model.Model {.inline.} =
self.membersModel

View File

@ -26,6 +26,7 @@ type
CanRequestAccess
Access
EnsOnly
Muted
MembersModel
PendingRequestsToJoinModel
HistoryArchiveSupportEnabled
@ -87,6 +88,7 @@ QtObject:
ModelRole.CanRequestAccess.int:"canRequestAccess",
ModelRole.Access.int:"access",
ModelRole.EnsOnly.int:"ensOnly",
ModelRole.Muted.int:"muted",
ModelRole.MembersModel.int:"members",
ModelRole.PendingRequestsToJoinModel.int:"pendingRequestsToJoin",
ModelRole.HistoryArchiveSupportEnabled.int:"historyArchiveSupportEnabled",
@ -144,6 +146,8 @@ QtObject:
result = newQVariant(item.access)
of ModelRole.EnsOnly:
result = newQVariant(item.ensOnly)
of ModelRole.Muted:
result = newQVariant(item.muted)
of ModelRole.MembersModel:
result = newQVariant(item.members)
of ModelRole.PendingRequestsToJoinModel:
@ -204,6 +208,31 @@ QtObject:
self.countChanged()
proc setMuted*(self: SectionModel, id: string, muted: bool) =
let index = self.getItemIndex(id)
if (index == -1):
return
self.items[index].muted = muted
let dataIndex = self.createIndex(index, 0, nil)
self.dataChanged(dataIndex, dataIndex, @[
ModelRole.Name.int,
ModelRole.Description.int,
ModelRole.Image.int,
ModelRole.Icon.int,
ModelRole.Color.int,
ModelRole.HasNotification.int,
ModelRole.NotificationsCount.int,
ModelRole.IsMember.int,
ModelRole.CanJoin.int,
ModelRole.Joined.int,
ModelRole.Muted.int,
ModelRole.MembersModel.int,
ModelRole.PendingRequestsToJoinModel.int,
ModelRole.HistoryArchiveSupportEnabled.int
])
proc editItem*(self: SectionModel, item: SectionItem) =
let index = self.getItemIndex(item.id)
if (index == -1):
@ -223,6 +252,7 @@ QtObject:
ModelRole.IsMember.int,
ModelRole.CanJoin.int,
ModelRole.Joined.int,
ModelRole.Muted.int,
ModelRole.MembersModel.int,
ModelRole.PendingRequestsToJoinModel.int,
ModelRole.HistoryArchiveSupportEnabled.int,

View File

@ -65,6 +65,10 @@ type
communityId*: string
pubKey*: string
CommunityMutedArgs* = ref object of Args
communityId*: string
muted*: bool
# Signals which may be emitted by this service:
const SIGNAL_COMMUNITY_JOINED* = "communityJoined"
const SIGNAL_COMMUNITY_MY_REQUEST_ADDED* = "communityMyRequestAdded"
@ -88,6 +92,7 @@ const SIGNAL_COMMUNITY_MEMBER_APPROVED* = "communityMemberApproved"
const SIGNAL_COMMUNITY_MEMBER_REMOVED* = "communityMemberRemoved"
const SIGNAL_NEW_REQUEST_TO_JOIN_COMMUNITY* = "newRequestToJoinCommunity"
const SIGNAL_CURATED_COMMUNITY_FOUND* = "curatedCommunityFound"
const SIGNAL_COMMUNITY_MUTED* = "communityMuted"
QtObject:
type
@ -1030,6 +1035,9 @@ QtObject:
proc setCommunityMuted*(self: Service, communityId: string, muted: bool) =
try:
discard status_go.setCommunityMuted(communityId, muted)
self.events.emit(SIGNAL_COMMUNITY_MUTED,
CommunityMutedArgs(communityId: communityId, muted: muted))
except Exception as e:
error "Error setting community un/muted", msg = e.msg

View File

@ -23,17 +23,6 @@ Column {
property var community
property alias contactListSearch: contactFieldAndList
function sendInvites(pubKeys) {
const error = communitySectionModule.inviteUsersToCommunity(JSON.stringify(pubKeys))
if (error) {
console.error('Error inviting', error)
contactFieldAndList.validationError = error
return
}
//% "Invite successfully sent"
contactFieldAndList.successMessage = qsTrId("invite-successfully-sent")
}
StatusDescriptionListItem {
//% "Share community"
title: qsTrId("share-community")
@ -66,6 +55,7 @@ Column {
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width - 32
contactsStore: root.contactsStore
communityModule: root.communitySectionModule
community: root.community
showCheckbox: true
hideCommunityMembers: true

View File

@ -21,6 +21,8 @@ StatusModal {
property var communitySectionModule
property bool hasAddedContacts
signal sendInvites(var pubKeys)
onOpened: {
contentItem.community = community;
@ -36,6 +38,16 @@ StatusModal {
//% "Invite friends"
header.title: qsTrId("invite-friends")
function proccesInviteResult(error) {
if (error) {
console.error('Error inviting', error)
contactFieldAndList.validationError = error
return
}
//% "Invite successfully sent"
popup.contentItem.contactListSearch.successMessage = qsTrId("invite-successfully-sent")
}
contentItem: CommunityProfilePopupInviteFriendsPanel {
id: contactFieldAndList
rootStore: popup.rootStore
@ -62,7 +74,7 @@ StatusModal {
//% "Invite"
text: qsTrId("invite-button")
onClicked : {
popup.contentItem.sendInvites(popup.contentItem.contactListSearch.pubKeys)
popup.sendInvites(popup.contentItem.contactListSearch.pubKeys)
}
}
]

View File

@ -5,6 +5,7 @@ import QtQuick.Layouts 1.13
import utils 1.0
import shared 1.0
import shared.popups 1.0
import "../panels"
import "../popups"
@ -329,7 +330,7 @@ Item {
Component {
id: importCommunitiesPopupComponent
AccessExistingCommunityPopup {
ImportCommunityPopup {
anchors.centerIn: parent
store: root.store
onClosed: {

View File

@ -213,6 +213,17 @@ StatusAppTwoPanelLayout {
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.about)
contentWidth: d.contentWidth
}
CommunitiesView {
Layout.fillWidth: true
Layout.fillHeight: true
profileSectionStore: profileView.store
rootStore: profileView.globalStore
contactStore: profileView.store.contactsStore
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.communitiesSettings)
contentWidth: d.contentWidth
}
}
}
}

View File

@ -0,0 +1,109 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import utils 1.0
ListView {
id: root
property var communitySectionModule
property var communityProfileModule
property bool hasAddedContacts: false
signal inviteFriends(var communityData)
interactive: false
implicitHeight: contentItem.childrenRect.height
spacing: 0
delegate: StatusListItem {
id: statusCommunityItem
width: parent.width
title: model.name
subTitle: model.description
tertiaryTitle: qsTr(model.members.count === 1 ?"%1 member"
:"%1 members").arg(model.members.count)
image.source: model.image
icon.isLetterIdenticon: !model.image
icon.background.color: model.color || Theme.palette.primaryColor1
visible: model.joined
height: visible ? implicitHeight: 0
sensor.hoverEnabled: false
components: [
StatusFlatButton {
size: StatusBaseButton.Size.Small
type: StatusBaseButton.Type.Danger
border.color: "transparent"
text: qsTrId("leave-community")
onClicked: {
Global.openPopup(leaveCommunityPopup, {
community: model.name,
communityId: model.id
})
}
},
StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Secondary
width: 44
height: 44
icon.source: model.muted ? Style.svg("communities/notifications-muted")
: Style.svg("communities/notifications")
onClicked: root.communityProfileModule.setCommunityMuted(model.id, !model.muted)
},
StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Secondary
width: 44
height: 44
icon.name: "invite-users"
onClicked: root.inviteFriends(model)
}
]
} // StatusListItem
property Component leaveCommunityPopup: StatusModal {
id: leavePopup
property string community: ""
property var communityId
anchors.centerIn: parent
header.title: qsTr("Leave %1").arg(community)
contentItem: Item {
implicitWidth: 368
implicitHeight: msg.implicitHeight + 32
StatusBaseText {
id: msg
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.margins: 16
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
text: qsTr("Are you sure you want to leave? Once you leave, you will have to request to rejoin if you change your mind.")
color: Theme.palette.directColor1
font.pixelSize: 15
}
}
rightButtons: [
StatusButton {
text: qsTr("Cancel")
onClicked: leavePopup.close()
},
StatusButton {
type: StatusBaseButton.Type.Danger
text: qsTr("Leave community")
onClicked: {
root.communityProfileModule.leaveCommunity(leavePopup.communityId)
leavePopup.close()
}
}
]
}
} // ListView

View File

@ -19,6 +19,8 @@ Column {
property bool browserMenuItemEnabled: false
property bool walletMenuItemEnabled: false
property bool appsMenuItemsEnabled: false
property bool communitiesMenuItemEnabled: false
signal menuItemClicked(var menu_item)
@ -63,9 +65,10 @@ Column {
selected: Global.settingsSubsection === model.subsection
onClicked: root.menuItemClicked(model)
visible: {
(model.subsection !== Constants.settingsSubsection.browserSettings && model.subsection !== Constants.settingsSubsection.wallet) ||
(model.subsection === Constants.settingsSubsection.browserSettings && root.browserMenuItemEnabled) ||
(model.subsection === Constants.settingsSubsection.wallet && root.walletMenuItemEnabled)
(model.subsection !== Constants.settingsSubsection.browserSettings && model.subsection !== Constants.settingsSubsection.wallet && model.subsection !== Constants.settingsSubsection.communitiesSettings) ||
(model.subsection === Constants.settingsSubsection.browserSettings && root.browserMenuItemEnabled) ||
(model.subsection === Constants.settingsSubsection.communitiesSettings && root.communitiesMenuItemEnabled) ||
(model.subsection === Constants.settingsSubsection.wallet && root.appsMenuItemsEnabled)
}
badge.value: {
switch (model.subsection) {

View File

@ -62,6 +62,12 @@ QtObject {
property bool browserMenuItemEnabled: localAccountSensitiveSettings.isBrowserEnabled
property bool walletMenuItemEnabled: localAccountSensitiveSettings.isWalletEnabled
property bool appsMenuItemsEnabled: localAccountSensitiveSettings.isWalletEnabled || localAccountSensitiveSettings.communitiesEnabled
property bool communitiesMenuItemEnabled: localAccountSensitiveSettings.communitiesEnabled
property var communitiesModuleInst: communitiesModule
property var communitiesList: communitiesModuleInst.model
property var communitiesProfileModule: profileSectionModuleInst.communitiesModule
property ListModel mainMenuItems: ListModel {
Component.onCompleted: {
@ -88,6 +94,9 @@ QtObject {
append({subsection: Constants.settingsSubsection.browserSettings,
text: qsTr("Browser"),
icon: "browser"})
append({subsection: Constants.settingsSubsection.communitiesSettings,
text: qsTr("Communities"),
icon: "communities"})
}
}
@ -125,6 +134,10 @@ QtObject {
}
}
function importCommunity(communityKey) {
root.communitiesModuleInst.importCommunity(communityKey);
}
function getCurrentVersion() {
return aboutModuleInst.getCurrentVersion()
}

View File

@ -0,0 +1,95 @@
import QtQuick 2.14
import QtQuick.Controls 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 1.0
import shared.panels 1.0
import shared.status 1.0
import shared.popups 1.0
import "../panels"
import "../../Chat/popups/community"
SettingsContentBase {
id: root
property var profileSectionStore
property var rootStore
property var contactStore
clip: true
titleRowComponentLoader.sourceComponent: StatusButton {
size: StatusBaseButton.Size.Small
text: qsTr("Import community")
onClicked: {
Global.openPopup(importCommunitiesPopupComponent)
}
}
Item {
id: rootItem
width: root.contentWidth
height: childrenRect.height
Column {
id: rootLayout
width: parent.width
anchors.top: parent.top
anchors.left: parent.left
StatusBaseText {
anchors.left: parent.left
anchors.leftMargin: Style.current.padding
color: Theme.palette.baseColor1
text: qsTr("Communities you've joined")
font.pixelSize: 15
}
CommunitiesListPanel {
width: parent.width
model: root.profileSectionStore.communitiesList
communitySectionModule: root.profileSectionStore.communitiesModuleInst
communityProfileModule: root.profileSectionStore.communitiesProfileModule
onInviteFriends: {
Global.openPopup(inviteFriendsToCommunityPopup, {
community: communityData,
hasAddedContacts: root.contactStore.myContactsModel.count > 0,
communitySectionModule: communityProfileModule
})
}
}
} // Column
} // Item
property Component importCommunitiesPopupComponent: ImportCommunityPopup {
anchors.centerIn: parent
store: root.profileSectionStore
onClosed: {
destroy()
}
}
property Component inviteFriendsToCommunityPopup: InviteFriendsToCommunityPopup {
anchors.centerIn: parent
rootStore: root.rootStore
contactsStore: root.contactStore
onClosed: {
destroy()
}
onSendInvites: {
const error = communitySectionModule.inviteUsersToCommunity(communty.id, JSON.stringify(pubKeys))
processInviteResult(error)
}
}
} // ScrollView

View File

@ -41,6 +41,9 @@ Item {
appsMenuItems: store.appsMenuItems
browserMenuItemEnabled: store.browserMenuItemEnabled
walletMenuItemEnabled: store.walletMenuItemEnabled
appsMenuItemsEnabled: store.appsMenuItemsEnabled
communitiesMenuItemEnabled: store.communitiesMenuItemEnabled
onMenuItemClicked: {
if (menu_item.subsection === Constants.settingsSubsection.backUpSeed) {
Global.openBackUpSeedPopup();

View File

@ -716,6 +716,11 @@ Item {
onClosed: {
destroy()
}
onSendInvites: {
const error = communitySectionModule.inviteUsersToCommunity(JSON.stringify(pubKeys))
processInviteResult(error)
}
}
}

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.7072 20.5058C2.31668 20.1153 2.31668 19.4821 2.7072 19.0916L19.6778 2.12102C20.0683 1.73049 20.7015 1.73049 21.092 2.12102C21.4825 2.51154 21.4825 3.14471 21.092 3.53523L4.12141 20.5058C3.73089 20.8963 3.09772 20.8963 2.7072 20.5058Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.64188 18.8138C8.57323 18.8825 8.62185 18.9999 8.71895 18.9999C9.05524 18.9999 9.29686 19.3278 9.26556 19.6626C9.25551 19.7701 9.25002 19.8826 9.25002 19.9999C9.25002 21.3888 10.4564 22.7499 12 22.7499C13.5437 22.7499 14.75 21.3888 14.75 19.9999C14.75 19.8826 14.7445 19.7701 14.7345 19.6626C14.7032 19.3278 14.9448 18.9999 15.2811 18.9999H18.4789C20.2152 18.9999 21.1267 16.9393 19.9588 15.6545L18.7819 14.36C18.2712 13.7982 17.9309 13.1026 17.8008 12.3546L17.6484 11.4783C17.5443 10.8797 16.8089 10.6468 16.3792 11.0765C16.2066 11.2491 16.1288 11.4949 16.1706 11.7353L16.323 12.6117C16.5019 13.6402 16.9698 14.5965 17.672 15.369L18.8489 16.6635C19.1409 16.9847 18.913 17.4999 18.4789 17.4999H10.2665C10.0676 17.4999 9.87682 17.5789 9.73616 17.7195L8.64188 18.8138ZM11.0391 19.0212L11.0341 19.0264L11.0373 19.0232L11.0391 19.0212ZM11.0841 18.9999C11.0682 18.9999 11.0526 19.0072 11.0416 19.0187C11.0387 19.022 11.0321 19.03 11.0219 19.0436C10.9989 19.0743 10.961 19.1299 10.9208 19.2103C10.8417 19.3686 10.75 19.6294 10.75 19.9999C10.75 20.6109 11.3345 21.2499 12 21.2499C12.6655 21.2499 13.25 20.6109 13.25 19.9999C13.25 19.6294 13.1583 19.3686 13.0792 19.2103C13.039 19.1299 13.0011 19.0743 12.9781 19.0436C12.968 19.03 12.9609 19.0216 12.958 19.0182C12.947 19.0067 12.9319 18.9999 12.916 18.9999H11.0841Z" fill="black"/>
<path d="M14.9585 4.01192C14.6582 4.31222 14.1705 4.29219 13.8183 4.05487C13.296 3.70287 12.6684 3.49986 12 3.49986C10.4172 3.49986 9.06368 4.63828 8.79247 6.19772L7.98687 10.8299C7.96582 10.9509 7.90792 11.0625 7.82107 11.1493L6.46566 12.5047C6.3638 12.6066 6.1745 12.4966 6.19918 12.3546L7.31465 5.94071C7.71081 3.66279 9.6879 1.99986 12 1.99986C13.0994 1.99986 14.1231 2.37584 14.937 3.01513C15.2532 3.26346 15.2428 3.72763 14.9585 4.01192Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -21,6 +21,7 @@ Item {
property var rootStore
property var contactsStore
property var community
property var communityModule
property string validationError: ""
property string successMessage: ""
@ -181,6 +182,7 @@ Item {
contactsStore: root.contactsStore
community: root.community
communityModule: root.communityModule
visible: showContactList
hideCommunityMembers: root.hideCommunityMembers
anchors.topMargin: this.height > 0 ? Style.current.halfPadding : 0

View File

@ -13,7 +13,7 @@ import StatusQ.Controls 0.1 as StatusQControls
StatusModal {
id: root
width: 400
width: 640
height: 400
property var store
@ -22,8 +22,8 @@ StatusModal {
return Utils.isPrivateKey(communityKey) && Utils.startsWith0x(communityKey)
}
//% "Access existing community"
header.title: qsTrId("access-existing-community")
//% "Import Community"
header.title: qsTrId("Import Community")
onClosed: {
root.destroy();
@ -37,12 +37,26 @@ StatusModal {
anchors.rightMargin: 16
height: childrenRect.height
StatusBaseText {
id: infoText1
anchors.top: parent.top
anchors.topMargin: Style.current.padding
//% "Entering a community key will grant you the ownership of that community. Please be responsible with it and dont share the key with people you dont trust."
text: qsTrId("entering-a-community-key-will-grant-you-the-ownership-of-that-community--please-be-responsible-with-it-and-don-t-share-the-key-with-people-you-don-t-trust-")
wrapMode: Text.WordWrap
width: parent.width
font.pixelSize: 13
color: Theme.palette.baseColor1
}
StyledTextArea {
id: keyInput
//% "Community private key"
label: qsTrId("community-key")
label: qsTrId("Community key")
placeholderText: "0x0..."
customHeight: 110
anchors.top: infoText1.bottom
anchors.topMargin: Style.current.bigPadding
anchors.left: parent.left
anchors.right: parent.right
@ -50,18 +64,6 @@ StatusModal {
importButton.enabled = root.validate(keyInput.text)
}
}
StatusBaseText {
id: infoText1
//% "Entering a community key will grant you the ownership of that community. Please be responsible with it and dont share the key with people you dont trust."
text: qsTrId("entering-a-community-key-will-grant-you-the-ownership-of-that-community--please-be-responsible-with-it-and-don-t-share-the-key-with-people-you-don-t-trust-")
anchors.top: keyInput.bottom
wrapMode: Text.WordWrap
anchors.topMargin: Style.current.bigPadding
width: parent.width
font.pixelSize: 13
color: Theme.palette.baseColor1
}
}
rightButtons: [

View File

@ -15,4 +15,5 @@ UserStatusContextMenu 1.0 UserStatusContextMenu.qml
SignTransactionModal 1.0 SignTransactionModal.qml
SelectAccountModal 1.0 SelectAccountModal.qml
ProfilePopup 1.0 ProfilePopup.qml
ImageCropWorkflow 1.0 ImageCropWorkflow.qml
ImageCropWorkflow 1.0 ImageCropWorkflow.qml
ImportCommunityPopup 1.0 ImportCommunityPopup.qml

View File

@ -16,6 +16,7 @@ Item {
property var contactsStore
property var community
property var communityModule
property string filterText: ""
property bool expanded: true
@ -56,7 +57,7 @@ Item {
model.name.toLowerCase().includes(root.filterText.toLowerCase()) ||
model.pubKey.toLowerCase().includes(root.filterText.toLowerCase())) &&
(!root.hideCommunityMembers ||
!root.community.hasMember(model.pubKey))
!root.communityModule.hasMember(commmunity.id, model.pubKey))
}
onContactClicked: function () {
root.contactClicked(model)

View File

@ -45,8 +45,9 @@ QtObject {
property int browserSettings: 10
property int advanced: 11
property int about: 12
property int signout: 13
property int backUpSeed: 14
property int communitiesSettings: 13
property int signout: 14
property int backUpSeed: 15
}
readonly property QtObject userStatus: QtObject{