refactor(community): use user model for the community member list

Fixes #4471
This commit is contained in:
Jonathan Rainville 2022-01-24 10:47:20 -05:00 committed by Sale Djenic
parent fb35f89336
commit c20554d987
17 changed files with 143 additions and 181 deletions

View File

@ -1,7 +1,8 @@
import NimQml
import io_interface
import ../io_interface as delegate_interface
import view, item, model, controller
import view, controller
import ../../../../shared_models/[user_model, user_item]
import ../../../../../global/global_singleton
import ../../../../../core/eventemitter
import ../../../../../../app_service/service/contacts/service as contact_service

View File

@ -1,5 +1,5 @@
import NimQml
import model
import ../../../../shared_models/user_model
import io_interface
QtObject:

View File

@ -5,6 +5,7 @@ import ./io_interface
import ../../../core/signals/types
import ../../../core/eventemitter
import ../../../../app_service/service/community/service as community_service
import ../../../../app_service/service/contacts/service as contacts_service
export controller_interface
@ -13,24 +14,24 @@ type
delegate: io_interface.AccessInterface
events: EventEmitter
communityService: community_service.Service
contactsService: contacts_service.Service
proc newController*(
delegate: io_interface.AccessInterface,
events: EventEmitter,
communityService: community_service.Service
communityService: community_service.Service,
contactsService: contacts_service.Service
): Controller =
result = Controller()
result.delegate = delegate
result.events = events
result.communityService = communityService
result.contactsService = contactsService
method delete*(self: Controller) =
discard
method init*(self: Controller) =
let communities = self.communityService.getAllCommunities()
self.delegate.setAllCommunities(communities)
self.events.on(SIGNAL_COMMUNITY_CREATED) do(e:Args):
let args = CommunityArgs(e)
self.delegate.addCommunity(args.community)
@ -63,6 +64,9 @@ method init*(self: Controller) =
let args = CommunityCategoryArgs(e)
# self.delegate.communityCategoryDeleted()
method getAllCommunities*(self: Controller): seq[CommunityDto] =
result = self.communityService.getAllCommunities()
method joinCommunity*(self: Controller, communityId: string): string =
self.communityService.joinCommunity(communityId)
@ -153,3 +157,10 @@ method removeUserFromCommunity*(self: Controller, communityId: string, pubKeys:
method banUserFromCommunity*(self: Controller, communityId: string, pubKey: string) =
self.communityService.removeUserFromCommunity(communityId, pubKey)
method setCommunityMuted*(self: Controller, communityId: string, muted: bool) =
self.communityService.setCommunityMuted(communityId, muted)
method getContactNameAndImage*(self: Controller, contactId: string):
tuple[name: string, image: string, isIdenticon: bool] =
return self.contactsService.getContactNameAndImage(contactId)

View File

@ -10,6 +10,9 @@ method delete*(self: AccessInterface) {.base.} =
method init*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method getAllCommunities*(self: AccessInterface): seq[CommunityDto] {.base.} =
raise newException(ValueError, "No implementation available")
method joinCommunity*(self: AccessInterface, communityId: string): string {.base.} =
raise newException(ValueError, "No implementation available")
@ -49,6 +52,13 @@ method removeUserFromCommunity*(self: AccessInterface, communityId: string, pubK
method banUserFromCommunity*(self: AccessInterface, communityId: string, pubKey: string) {.base.} =
raise newException(ValueError, "No implementation available")
method setCommunityMuted*(self: AccessInterface, communityId: string, muted: bool) {.base.} =
raise newException(ValueError, "No implementation available")
method getContactNameAndImage*(self: AccessInterface, contactId: string):
tuple[name: string, image: string, isIdenticon: bool] {.base.} =
raise newException(ValueError, "No implementation available")
type
## Abstract class (concept) which must be implemented by object/s used in this
## module.

View File

@ -21,12 +21,18 @@ QtObject:
self.items = @[]
self.QAbstractListModel.delete
proc newPendingRequestModel*(pendingRequestsToJoin: seq[PendingRequestItem]): PendingRequestModel =
proc newPendingRequestModel*(): PendingRequestModel =
new(result, delete)
result.items = pendingRequestsToJoin
result.setup
proc countChanged(self: PendingRequestModel) {.signal.}
proc setItems*(self: PendingRequestModel, items: seq[PendingRequestItem]) =
self.beginResetModel()
self.items = items
self.endResetModel()
self.countChanged()
proc getCount(self: PendingRequestModel): int {.slot.} =
self.items.len
QtProperty[int] count:

View File

@ -4,11 +4,11 @@ import ./io_interface
import ../io_interface as delegate_interface
import ./view, ./controller
import ../../shared_models/section_item
import ../../shared_models/member_item
import ../../shared_models/members_model
import ../../shared_models/[user_item, user_model]
import ../../../global/global_singleton
import ../../../core/eventemitter
import ../../../../app_service/service/community/service as community_service
import ../../../../app_service/service/contacts/service as contacts_service
export io_interface
@ -20,10 +20,14 @@ type
viewVariant: QVariant
moduleLoaded: bool
# Forward declaration
method setAllCommunities*(self: Module, communities: seq[CommunityDto])
proc newModule*(
delegate: delegate_interface.AccessInterface,
events: EventEmitter,
communityService: community_service.Service
communityService: community_service.Service,
contactsService: contacts_service.Service
): Module =
result = Module()
result.delegate = delegate
@ -32,7 +36,8 @@ proc newModule*(
result.controller = controller.newController(
result,
events,
communityService
communityService,
contactsService
)
result.moduleLoaded = false
@ -51,6 +56,9 @@ method isLoaded*(self: Module): bool =
method viewDidLoad*(self: Module) =
self.moduleLoaded = true
self.setAllCommunities(self.controller.getAllCommunities())
self.delegate.communitiesModuleDidLoad()
method getCommunityItem(self: Module, c: CommunityDto): SectionItem =
@ -74,7 +82,9 @@ method getCommunityItem(self: Module, c: CommunityDto): SectionItem =
c.isMember,
c.permissions.access,
c.permissions.ensOnly,
c.members.map(x => member_item.initItem(x.id, x.roles))
c.members.map(proc(member: Member): user_item.Item =
let (name, image, isIdenticon) = self.controller.getContactNameAndImage(member.id)
result = user_item.initItem(member.id, name, OnlineStatus.Offline, image, isIdenticon))
)
method setAllCommunities*(self: Module, communities: seq[CommunityDto]) =

View File

@ -126,6 +126,14 @@ method init*(self: Controller) =
var args = ResolvedContactArgs(e)
self.delegate.resolvedENS(args.pubkey, args.address, args.uuid)
self.events.on(SIGNAL_CONTACT_UPDATED) do(e: Args):
var args = ContactArgs(e)
self.delegate.contactUpdated(args.contactId)
self.events.on(SIGNAL_CONTACT_NICKNAME_CHANGED) do(e: Args):
var args = ContactArgs(e)
self.delegate.contactUpdated(args.contactId)
method getJoinedCommunities*(self: Controller): seq[CommunityDto] =
return self.communityService.getJoinedCommunities()

View File

@ -1,8 +1,8 @@
import NimQml, tables, json, sugar, sequtils
import io_interface, view, controller, ../shared_models/section_item,../shared_models/section_model
import ../shared_models/member_item, ../shared_models/members_model
import io_interface, view, controller
import ./communities/models/[pending_request_item, pending_request_model]
import ../shared_models/[user_item, user_model, section_item, section_model, active_section]
import ../../global/app_sections_config as conf
import ../../global/app_signals
import ../../global/global_singleton
@ -134,7 +134,7 @@ proc newModule*[T](
result.stickersModule = stickers_module.newModule(result, events, stickersService)
result.activityCenterModule = activity_center_module.newModule(result, events, activityCenterService, contactsService,
messageService)
result.communitiesModule = communities_module.newModule(result, events, communityService)
result.communitiesModule = communities_module.newModule(result, events, communityService, contactsService)
result.appSearchModule = app_search_module.newModule(result, events, contactsService, chatService, communityService,
messageService)
result.nodeSectionModule = node_section_module.newModule(result, events, settingsService, nodeService, nodeConfigurationService)
@ -180,7 +180,9 @@ proc createCommunityItem[T](self: Module[T], c: CommunityDto): SectionItem =
c.isMember,
c.permissions.access,
c.permissions.ensOnly,
c.members.map(x => member_item.initItem(x.id, x.roles)),
c.members.map(proc(member: Member): user_item.Item =
let (name, image, isIdenticon) = self.controller.getContactNameAndImage(member.id)
result = user_item.initItem(member.id, name, OnlineStatus.Offline, image, isIdenticon)),
c.pendingRequestsToJoin.map(x => pending_request_item.initItem(
x.id,
x.publicKey,
@ -585,4 +587,8 @@ method resolveENS*[T](self: Module[T], ensName: string, uuid: string) =
self.controller.resolveENS(ensName, uuid)
method resolvedENS*[T](self: Module[T], publicKey: string, address: string, uuid: string) =
self.view.emitResolvedENSSignal(publicKey, address, uuid)
self.view.emitResolvedENSSignal(publicKey, address, uuid)
method contactUpdated*[T](self: Module[T], publicKey: string) =
let (name, image, isIdenticon) = self.controller.getContactNameAndImage(publicKey)
self.view.activeSection().updateMember(publicKey, name, image, isIdenticon)

View File

@ -31,4 +31,7 @@ method communityLeft*(self: AccessInterface, communityId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method resolvedENS*(self: AccessInterface, publicKey: string, address: string, uuid: string) {.base.} =
raise newException(ValueError, "No implementation available")
raise newException(ValueError, "No implementation available")
method contactUpdated*(self: AccessInterface, publicKey: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -75,6 +75,9 @@ QtObject:
proc emitStoringPasswordSuccess*(self: View) =
self.storingPasswordSuccess()
proc activeSection*(self: View): ActiveSection =
return self.activeSection
proc getActiveSection(self: View): QVariant {.slot.} =
return self.activeSectionVariant

View File

@ -132,6 +132,14 @@ QtObject:
proc hasMember(self: ActiveSection, pubkey: string): bool {.slot.} =
return self.item.hasMember(pubkey)
proc updateMember*(
self: ActiveSection,
pubkey: string,
name: string,
image: string,
isIdenticon: bool) =
self.item.updateMember(pubkey, name, image, isIdenticon)
proc pendingRequestsToJoin(self: ActiveSection): QVariant {.slot.} =
if (self.item.id == ""):
# FIXME (Jo) I don't know why but the Item is sometimes empty and doing anything here crashes the app

View File

@ -1,27 +0,0 @@
import strformat
type
MemberItem* = ref object
id: string
roles*: seq[int]
proc initItem*(
id: string,
roles: seq[int]
): MemberItem =
result = MemberItem()
result.id = id
result.roles = roles
proc `$`*(self: MemberItem): string =
result = fmt"""MemberItem(
id: {self.id},
roles: {$self.roles}
]"""
proc id*(self: MemberItem): string {.inline.} =
self.id
proc roles*(self: MemberItem): seq[int] {.inline.} =
self.roles

View File

@ -1,109 +0,0 @@
import NimQml, Tables, strformat
import ./member_item
import ../../global/global_singleton
type
MembersRoles {.pure.} = enum
PubKey = UserRole + 1
# LastSeen = UserRole,
# StatusType = UserRole,
# Online = UserRole,
# SortKey = UserRole
QtObject:
type
MembersModel* = ref object of QAbstractListModel
members*: seq[MemberItem]
proc setup(self: MembersModel) = self.QAbstractListModel.setup
proc delete(self: MembersModel) =
self.QAbstractListModel.delete
proc newMembersModel*(members: seq[MemberItem]): MembersModel =
new(result, delete)
result.members = members
result.setup()
proc `$`*(self: MembersModel): string =
for i in 0 ..< self.members.len:
result &= fmt"""MembersModel:
[{i}]:({$self.members[i]})
"""
proc getIndexFromPubKey*(self: MembersModel, pubKey: string): int =
var i = 0
for member in self.members:
if (member.id == pubKey):
return i
i = i + 1
return -1
proc hasMember*(self: MembersModel, pubkey: string): bool =
for member in self.members:
if (member.id == pubkey):
return true
return false
proc removeMember*(self: MembersModel, pubKey: string) =
let memberIndex = self.getIndexFromPubKey(pubKey)
if (memberIndex == -1):
return
self.beginRemoveRows(newQModelIndex(), memberIndex, memberIndex)
self.members.delete(memberIndex)
self.endRemoveRows()
proc countChanged*(self: MembersModel) {.signal.}
proc count*(self: MembersModel): int {.slot.} =
self.members.len
QtProperty[int] count:
read = count
notify = countChanged
method rowCount(self: MembersModel, index: QModelIndex = nil): int =
self.members.len
# proc memberStatus(self: MembersModel, pk: string): int =
# if self.membersStatus.hasKey(pk):
# result = self.membersStatus[pk].statusType.int
# proc isOnline(self: MembersModel, pk: string): bool =
# if self.myPubKey == pk:
# return true
# if self.membersStatus.hasKey(pk):
# result = self.membersStatus[pk].statusType.int == StatusUpdateType.Online.int
# proc sortKey(self: MembersModel, pk: string): string =
# let name = self.userName(pk, self.alias(pk))
# if self.isOnline(pk):
# return "A" & name
# return "B" & name
method data(self: MembersModel, index: QModelIndex, role: int): QVariant =
if not index.isValid:
return
if index.row < 0 or index.row >= self.members.len:
return
let member = self.members[index.row]
let memberRole = role.MembersRoles
case memberRole:
of MembersRoles.PubKey: result = newQVariant(member.id)
# of MembersRoles.LastSeen: result = newQVariant(self.memberLastSeen(member.id))
# of MembersRoles.StatusType: result = newQVariant(self.memberStatus(member.id))
# of MembersRoles.Online: result = newQVariant(self.isOnline(member.id))
# of MembersRoles.SortKey: result = newQVariant(self.sortKey(member.id))
method roleNames(self: MembersModel): Table[int, string] =
{
MembersRoles.PubKey.int:"pubKey"
# MembersRoles.LastSeen.int:"lastSeen",
# MembersRoles.StatusType.int:"statusType",
# MembersRoles.Online.int:"online",
# MembersRoles.SortKey.int:"sortKey"
}.toTable
# proc triggerUpdate*(self: MembersModel) =
# self.beginResetModel()
# self.endResetModel()

View File

@ -1,5 +1,5 @@
import strformat
import ./members_model, ./member_item
import ./user_model, ./user_item
import ../main/communities/models/[pending_request_item, pending_request_model]
type
@ -33,7 +33,7 @@ type
canRequestAccess: bool
access: int
ensOnly: bool
membersModel: MembersModel
membersModel: user_model.Model
pendingRequestsToJoinModel: PendingRequestModel
proc initItem*(
@ -56,7 +56,7 @@ proc initItem*(
isMember = false,
access: int = 0,
ensOnly = false,
members: seq[MemberItem] = @[],
members: seq[user_item.Item] = @[],
pendingRequestsToJoin: seq[PendingRequestItem] = @[]
): SectionItem =
result.id = id
@ -78,8 +78,10 @@ proc initItem*(
result.isMember = isMember
result.access = access
result.ensOnly = ensOnly
result.membersModel = newMembersModel(members)
result.pendingRequestsToJoinModel = newPendingRequestModel(pendingRequestsToJoin)
result.membersModel = newModel()
result.membersModel.setItems(members)
result.pendingRequestsToJoinModel = newPendingRequestModel()
result.pendingRequestsToJoinModel.setItems(pendingRequestsToJoin)
proc isEmpty*(self: SectionItem): bool =
return self.id.len == 0
@ -177,11 +179,19 @@ proc access*(self: SectionItem): int {.inline.} =
proc ensOnly*(self: SectionItem): bool {.inline.} =
self.ensOnly
proc members*(self: SectionItem): MembersModel {.inline.} =
proc members*(self: SectionItem): user_model.Model {.inline.} =
self.membersModel
proc hasMember*(self: SectionItem, pubkey: string): bool =
self.membersModel.hasMember(pubkey)
self.membersModel.isContactWithIdAdded(pubkey)
proc updateMember*(
self: SectionItem,
pubkey: string,
name: string,
image: string,
isIdenticon: bool) =
self.membersModel.updateItem(pubkey, name, image, isIdenticon)
proc pendingRequestsToJoin*(self: SectionItem): PendingRequestModel {.inline.} =
self.pendingRequestsToJoinModel

View File

@ -1,3 +1,5 @@
import strformat
type
OnlineStatus* {.pure.} = enum
Offline = 0
@ -6,6 +8,7 @@ type
Idle
Invisible
# TODO add role when it is needed
type
Item* = ref object
id: string
@ -14,7 +17,13 @@ type
icon: string
isIdenticon: bool
proc initItem*(id: string, name: string, onlineStatus: OnlineStatus, icon: string, isidenticon: bool): Item =
proc initItem*(
id: string,
name: string,
onlineStatus: OnlineStatus,
icon: string,
isidenticon: bool
): Item =
result = Item()
result.id = id
result.name = name
@ -22,6 +31,15 @@ proc initItem*(id: string, name: string, onlineStatus: OnlineStatus, icon: strin
result.icon = icon
result.isIdenticon = isidenticon
proc `$`*(self: Item): string =
result = fmt"""User Item(
id: {self.id},
name: {self.name},
onlineStatus: {$self.onlineStatus.int},
icon: {self.icon},
isIdenticon: {$self.isIdenticon}
]"""
proc id*(self: Item): string {.inline.} =
self.id

View File

@ -1,6 +1,6 @@
import NimQml, Tables
import NimQml, Tables, strformat
import item
import user_item
type
ModelRole {.pure.} = enum
@ -27,6 +27,18 @@ QtObject:
result.setup
proc countChanged(self: Model) {.signal.}
proc setItems*(self: Model, items: seq[Item]) =
self.beginResetModel()
self.items = items
self.endResetModel()
self.countChanged()
proc `$`*(self: Model): string =
for i in 0 ..< self.items.len:
result &= fmt"""User Model:
[{i}]:({$self.items[i]})
"""
proc getCount(self: Model): int {.slot.} =
self.items.len
QtProperty[int] count:
@ -158,4 +170,4 @@ QtObject:
if(ind == -1):
return
self.removeItemWithIndex(ind)
self.removeItemWithIndex(ind)

View File

@ -127,27 +127,19 @@ Item {
id: memberList
model: root.community.members
delegate: StatusListItem {
id: memberItem
property var contactDetail: Utils.getContactDetailsAsJson(model.pubKey)
property string identicon: contactDetail.identicon || root.store.generateIdenticon(model.pubKey)
property string username: contactDetail.name || root.store.generateAlias(model.pubKey)
property string nickname: contactDetail.localNickname || ""
property string profileImage: Global.getProfileImage(model.pubKey) || ""
visible: !!!memberSearch.input.text ||
contactDetail.name.toLowerCase().includes(memberSearch.input.text.toLowerCase()) ||
nickname.toLowerCase().includes(memberSearch.input.text.toLowerCase())
model.name.toLowerCase().includes(memberSearch.input.text.toLowerCase())
anchors.horizontalCenter: parent.horizontalCenter
image.isIdenticon: !profileImage
image.source: profileImage || identicon
image.isIdenticon: model.isIdenticon
image.source: model.icon
title: {
if (menuButton.visible) {
return !username.endsWith(".eth") && !!nickname ?
nickname : Utils.removeStatusEns(username)
return !model.name.endsWith(".eth") ?
model.name : Utils.removeStatusEns(model.name)
}
//% "You"
return qsTrId("You")
@ -158,7 +150,7 @@ Item {
id: menuButton
width: 32
height: 32
visible: model.pubKey.toLowerCase() !== userProfile.pubKey.toLowerCase()
visible: model.id.toLowerCase() !== userProfile.pubKey.toLowerCase()
icon.name: "more"
type: StatusFlatRoundButton.Type.Secondary
onClicked: {
@ -178,7 +170,7 @@ Item {
//% "View Profile"
text: qsTrId("view-profile")
icon.name: "channel"
onTriggered: Global.openProfilePopup(model.pubKey)
onTriggered: Global.openProfilePopup(model.id)
}
StatusMenuSeparator {