refactor(@desktop/chat-communities): initial model for the chat/community sections
Model used for list of chats in case of Chat section and used for channels/categories/category channels is initially added. With an option for setting active chat/channel/category (which are an Item type) and setting active channel within a category (which is a SubItem type).
This commit is contained in:
parent
b15c348931
commit
d8dea2dc58
|
@ -0,0 +1,96 @@
|
|||
import NimQml
|
||||
import item, sub_item, active_sub_item
|
||||
|
||||
QtObject:
|
||||
type ActiveItem* = ref object of QObject
|
||||
item: Item
|
||||
activeSubItem: ActiveSubItem
|
||||
activeSubItemVariant: QVariant
|
||||
|
||||
proc setup(self: ActiveItem) =
|
||||
self.QObject.setup
|
||||
self.activeSubItem = newActiveSubItem()
|
||||
self.activeSubItemVariant = newQVariant(self.activeSubItem)
|
||||
|
||||
proc delete*(self: ActiveItem) =
|
||||
self.activeSubItem.delete
|
||||
self.activeSubItemVariant.delete
|
||||
self.QObject.delete
|
||||
|
||||
proc newActiveItem*(): ActiveItem =
|
||||
new(result, delete)
|
||||
result.setup
|
||||
|
||||
#################################################
|
||||
# Forward declaration section
|
||||
proc activeSubItemChanged(self: ActiveItem) {.signal.}
|
||||
|
||||
#################################################
|
||||
|
||||
proc setActiveItemData*(self: ActiveItem, item: Item, subItem: SubItem) =
|
||||
self.item = item
|
||||
self.activeSubItem.setActiveSubItemData(subItem)
|
||||
self.activeSubItemChanged()
|
||||
|
||||
proc getId(self: ActiveItem): string {.slot.} =
|
||||
return self.item.id
|
||||
|
||||
QtProperty[string] id:
|
||||
read = getId
|
||||
|
||||
proc getName(self: ActiveItem): string {.slot.} =
|
||||
return self.item.name
|
||||
|
||||
QtProperty[string] name:
|
||||
read = getName
|
||||
|
||||
proc getIcon(self: ActiveItem): string {.slot.} =
|
||||
return self.item.icon
|
||||
|
||||
QtProperty[string] icon:
|
||||
read = getIcon
|
||||
|
||||
proc getColor(self: ActiveItem): string {.slot.} =
|
||||
return self.item.color
|
||||
|
||||
QtProperty[string] color:
|
||||
read = getColor
|
||||
|
||||
proc getDescription(self: ActiveItem): string {.slot.} =
|
||||
return self.item.description
|
||||
|
||||
QtProperty[string] description:
|
||||
read = getDescription
|
||||
|
||||
proc getType(self: ActiveItem): int {.slot.} =
|
||||
return self.item.`type`
|
||||
|
||||
QtProperty[int] type:
|
||||
read = getType
|
||||
|
||||
proc getHasNotification(self: ActiveItem): bool {.slot.} =
|
||||
return self.item.hasNotification
|
||||
|
||||
QtProperty[bool] hasNotification:
|
||||
read = getHasNotification
|
||||
|
||||
proc getNotificationCount(self: ActiveItem): int {.slot.} =
|
||||
return self.item.notificationsCount
|
||||
|
||||
QtProperty[int] notificationCount:
|
||||
read = getNotificationCount
|
||||
|
||||
proc getMuted(self: ActiveItem): bool {.slot.} =
|
||||
return self.item.muted
|
||||
|
||||
QtProperty[bool] muted:
|
||||
read = getMuted
|
||||
|
||||
proc getActiveSubItem(self: ActiveItem): QVariant {.slot.} =
|
||||
return self.activeSubItemVariant
|
||||
|
||||
QtProperty[QVariant] activeSubItem:
|
||||
read = getActiveSubItem
|
||||
notify = activeSubItemChanged
|
||||
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
import NimQml
|
||||
import sub_item
|
||||
|
||||
QtObject:
|
||||
type ActiveSubItem* = ref object of QObject
|
||||
item: SubItem
|
||||
|
||||
proc setup(self: ActiveSubItem) =
|
||||
self.QObject.setup
|
||||
|
||||
proc delete*(self: ActiveSubItem) =
|
||||
self.QObject.delete
|
||||
|
||||
proc newActiveSubItem*(): ActiveSubItem =
|
||||
new(result, delete)
|
||||
result.setup
|
||||
|
||||
proc setActiveSubItemData*(self: ActiveSubItem, item: SubItem) =
|
||||
self.item = item
|
||||
|
||||
proc getId(self: ActiveSubItem): string {.slot.} =
|
||||
return self.item.id
|
||||
|
||||
QtProperty[string] id:
|
||||
read = getId
|
||||
|
||||
proc getName(self: ActiveSubItem): string {.slot.} =
|
||||
return self.item.name
|
||||
|
||||
QtProperty[string] name:
|
||||
read = getName
|
||||
|
||||
proc getIcon(self: ActiveSubItem): string {.slot.} =
|
||||
return self.item.icon
|
||||
|
||||
QtProperty[string] icon:
|
||||
read = getIcon
|
||||
|
||||
proc getColor(self: ActiveSubItem): string {.slot.} =
|
||||
return self.item.color
|
||||
|
||||
QtProperty[string] color:
|
||||
read = getColor
|
||||
|
||||
proc getDescription(self: ActiveSubItem): string {.slot.} =
|
||||
return self.item.description
|
||||
|
||||
QtProperty[string] description:
|
||||
read = getDescription
|
||||
|
||||
proc getHasNotification(self: ActiveSubItem): bool {.slot.} =
|
||||
return self.item.hasNotification
|
||||
|
||||
QtProperty[bool] hasNotification:
|
||||
read = getHasNotification
|
||||
|
||||
proc getNotificationCount(self: ActiveSubItem): int {.slot.} =
|
||||
return self.item.notificationsCount
|
||||
|
||||
QtProperty[int] notificationCount:
|
||||
read = getNotificationCount
|
||||
|
||||
proc getMuted(self: ActiveSubItem): bool {.slot.} =
|
||||
return self.item.muted
|
||||
|
||||
QtProperty[bool] muted:
|
||||
read = getMuted
|
||||
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
type
|
||||
BaseItem* {.pure inheritable.} = ref object of RootObj
|
||||
id: string
|
||||
name: string
|
||||
icon: string
|
||||
color: string
|
||||
description: string
|
||||
hasNotification: bool
|
||||
notificationsCount: int
|
||||
muted: bool
|
||||
active: bool
|
||||
|
||||
proc setup*(self: BaseItem, id, name, icon, color, description: string, hasNotification: bool, notificationsCount: int,
|
||||
muted, active: bool) =
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.icon = icon
|
||||
self.color = color
|
||||
self.description = description
|
||||
self.hasNotification = hasNotification
|
||||
self.notificationsCount = notificationsCount
|
||||
self.muted = muted
|
||||
self.active = active
|
||||
|
||||
proc initBaseItem*(id, name, icon, color, description: string, hasNotification: bool, notificationsCount: int,
|
||||
muted, active: bool): BaseItem =
|
||||
result = BaseItem()
|
||||
result.setup(id, name, icon, color, description, hasNotification, notificationsCount, muted, active)
|
||||
|
||||
proc delete*(self: BaseItem) =
|
||||
discard
|
||||
|
||||
method id*(self: BaseItem): string {.inline base.} =
|
||||
self.id
|
||||
|
||||
method name*(self: BaseItem): string {.inline base.} =
|
||||
self.name
|
||||
|
||||
method icon*(self: BaseItem): string {.inline base.} =
|
||||
self.icon
|
||||
|
||||
method color*(self: BaseItem): string {.inline base.} =
|
||||
self.color
|
||||
|
||||
method description*(self: BaseItem): string {.inline base.} =
|
||||
self.description
|
||||
|
||||
method hasNotification*(self: BaseItem): bool {.inline base.} =
|
||||
self.hasNotification
|
||||
|
||||
method `hasNotification=`*(self: var BaseItem, value: bool) {.inline base.} =
|
||||
self.hasNotification = value
|
||||
|
||||
method notificationsCount*(self: BaseItem): int {.inline base.} =
|
||||
self.notificationsCount
|
||||
|
||||
method `notificationsCount=`*(self: var BaseItem, value: int) {.inline base.} =
|
||||
self.notificationsCount = value
|
||||
|
||||
method muted*(self: BaseItem): bool {.inline base.} =
|
||||
self.muted
|
||||
|
||||
method `muted=`*(self: var BaseItem, value: bool) {.inline base.} =
|
||||
self.muted = value
|
||||
|
||||
method active*(self: BaseItem): bool {.inline base.} =
|
||||
self.active
|
||||
|
||||
method `active=`*(self: var BaseItem, value: bool) {.inline base.} =
|
||||
self.active = value
|
|
@ -3,6 +3,7 @@ import Tables
|
|||
import controller_interface
|
||||
import io_interface
|
||||
|
||||
import ../../../../app_service/service/chat/service as chat_service
|
||||
import ../../../../app_service/service/community/service as community_service
|
||||
|
||||
export controller_interface
|
||||
|
@ -12,16 +13,19 @@ type
|
|||
delegate: io_interface.AccessInterface
|
||||
id: string
|
||||
isCommunityModule: bool
|
||||
activeItemId: string
|
||||
activeSubItemId: string
|
||||
chatService: chat_service.ServiceInterface
|
||||
communityService: community_service.ServiceInterface
|
||||
|
||||
proc newController*(delegate: io_interface.AccessInterface,
|
||||
id: string, isCommunity: bool,
|
||||
communityService: community_service.ServiceInterface):
|
||||
Controller =
|
||||
proc newController*(delegate: io_interface.AccessInterface, id: string, isCommunity: bool,
|
||||
chatService: chat_service.ServiceInterface,
|
||||
communityService: community_service.ServiceInterface): Controller =
|
||||
result = Controller()
|
||||
result.delegate = delegate
|
||||
result.id = id
|
||||
result.isCommunityModule = isCommunity
|
||||
result.chatService = chatService
|
||||
result.communityService = communityService
|
||||
|
||||
method delete*(self: Controller) =
|
||||
|
@ -36,5 +40,26 @@ method getId*(self: Controller): string =
|
|||
method isCommunity*(self: Controller): bool =
|
||||
return self.isCommunityModule
|
||||
|
||||
method getCommunities*(self: Controller): seq[community_service.CommunityDto] =
|
||||
return self.communityService.getCommunities()
|
||||
method getCommunityIds*(self: Controller): seq[string] =
|
||||
return self.communityService.getCommunityIds()
|
||||
|
||||
method getCategories*(self: Controller, communityId: string): seq[Category] =
|
||||
return self.communityService.getCategories(communityId)
|
||||
|
||||
method getChats*(self: Controller, communityId: string, categoryId: string): seq[Chat] =
|
||||
return self.communityService.getChats(communityId, categoryId)
|
||||
|
||||
method getChatDetails*(self: Controller, communityId, chatId: string): ChatDto =
|
||||
let fullId = communityId & chatId
|
||||
return self.chatService.getChatById(fullId)
|
||||
|
||||
method getChatDetailsForChatTypes*(self: Controller, types: seq[ChatType]): seq[ChatDto] =
|
||||
return self.chatService.getChatsOfChatTypes(types)
|
||||
|
||||
method setActiveItemSubItem*(self: Controller, itemId: string, subItemId: string) =
|
||||
self.activeItemId = itemId
|
||||
self.activeSubItemId = subItemId
|
||||
|
||||
# We need to take other actions here like notify status go that unviewed mentions count is updated and so...
|
||||
|
||||
self.delegate.activeItemSubItemSet(self.activeItemId, self.activeSubItemId)
|
|
@ -1,3 +1,4 @@
|
|||
import ../../../../app_service/service/chat/service_interface as chat_service
|
||||
import ../../../../app_service/service/community/service_interface as community_service
|
||||
|
||||
type
|
||||
|
@ -16,7 +17,20 @@ method getId*(self: AccessInterface): string {.base.} =
|
|||
method isCommunity*(self: AccessInterface): bool {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getCommunities*(self: AccessInterface):
|
||||
seq[community_service.CommunityDto] {.base.} =
|
||||
method getCommunityIds*(self: AccessInterface): seq[string] {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
|
||||
method getCategories*(self: AccessInterface, communityId: string): seq[Category] {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getChats*(self: AccessInterface, communityId: string, categoryId: string): seq[Chat] {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getChatDetails*(self: AccessInterface, communityId, chatId: string): ChatDto {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getChatDetailsForChatTypes*(self: AccessInterface, types: seq[ChatType]): seq[ChatDto] {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method setActiveItemSubItem*(self: AccessInterface, itemId: string, subItemId: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
|
@ -0,0 +1,33 @@
|
|||
import controller_interface
|
||||
import io_interface
|
||||
|
||||
import ../../../../../app_service/service/community/service as community_service
|
||||
|
||||
export controller_interface
|
||||
|
||||
type
|
||||
Controller* = ref object of controller_interface.AccessInterface
|
||||
delegate: io_interface.AccessInterface
|
||||
id: string
|
||||
isCommunityModule: bool
|
||||
communityService: community_service.ServiceInterface
|
||||
|
||||
proc newController*(delegate: io_interface.AccessInterface, id: string, isCommunity: bool,
|
||||
communityService: community_service.ServiceInterface): Controller =
|
||||
result = Controller()
|
||||
result.delegate = delegate
|
||||
result.id = id
|
||||
result.isCommunityModule = isCommunity
|
||||
result.communityService = communityService
|
||||
|
||||
method delete*(self: Controller) =
|
||||
discard
|
||||
|
||||
method init*(self: Controller) =
|
||||
discard
|
||||
|
||||
method getId*(self: Controller): string =
|
||||
return self.id
|
||||
|
||||
method isCommunity*(self: Controller): bool =
|
||||
return self.isCommunityModule
|
|
@ -0,0 +1,19 @@
|
|||
import ../../../../../app_service/service/community/service_interface as community_service
|
||||
|
||||
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 init*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getId*(self: AccessInterface): string {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method isCommunity*(self: AccessInterface): bool {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# Defines how parent module accesses this module
|
||||
include ./private_interfaces/module_base_interface
|
||||
include ./private_interfaces/module_access_interface
|
||||
|
||||
# Defines how this module view communicates with this module
|
||||
include ./private_interfaces/module_view_delegate_interface
|
||||
|
||||
# Defines how this controller communicates with this module
|
||||
include ./private_interfaces/module_controller_delegate_interface
|
||||
|
||||
# Defines how submodules of this module communicate with this module
|
||||
# will be added if needed
|
|
@ -0,0 +1,21 @@
|
|||
import NimQml
|
||||
|
||||
QtObject:
|
||||
type
|
||||
Item* = ref object of QObject
|
||||
|
||||
proc setup(self: Item) =
|
||||
self.QObject.setup
|
||||
|
||||
proc delete*(self: Item) =
|
||||
self.QObject.delete
|
||||
|
||||
proc newItem*(): Item =
|
||||
new(result, delete)
|
||||
result.setup()
|
||||
|
||||
proc id*(self: Item): string {.slot.} =
|
||||
self.id
|
||||
|
||||
QtProperty[string] id:
|
||||
read = id
|
|
@ -0,0 +1,17 @@
|
|||
import NimQml
|
||||
import item
|
||||
|
||||
QtObject:
|
||||
type
|
||||
Model* = ref object of QAbstractListModel
|
||||
sections: seq[Item]
|
||||
|
||||
proc setup(self: Model) =
|
||||
self.QAbstractListModel.setup
|
||||
|
||||
proc delete*(self: Model) =
|
||||
self.QAbstractListModel.delete
|
||||
|
||||
proc newModel*(): Model =
|
||||
new(result, delete)
|
||||
result.setup
|
|
@ -0,0 +1,46 @@
|
|||
import NimQml
|
||||
import io_interface
|
||||
import ../io_interface as delegate_interface
|
||||
import view, controller
|
||||
import ../../../../core/global_singleton
|
||||
|
||||
import ../../../../../app_service/service/chat/service as chat_service
|
||||
import ../../../../../app_service/service/community/service as community_service
|
||||
|
||||
export io_interface
|
||||
|
||||
type
|
||||
Module* = ref object of io_interface.AccessInterface
|
||||
delegate: delegate_interface.AccessInterface
|
||||
view: View
|
||||
viewVariant: QVariant
|
||||
controller: controller.AccessInterface
|
||||
moduleLoaded: bool
|
||||
|
||||
proc newModule*(delegate: delegate_interface.AccessInterface, id: string, isCommunity: bool,
|
||||
chatService: chat_service.Service, communityService: community_service.Service):
|
||||
Module =
|
||||
result = Module()
|
||||
result.delegate = delegate
|
||||
result.view = view.newView(result)
|
||||
result.viewVariant = newQVariant(result.view)
|
||||
result.controller = controller.newController(result, id, isCommunity, communityService)
|
||||
result.moduleLoaded = false
|
||||
|
||||
method delete*(self: Module) =
|
||||
self.view.delete
|
||||
self.viewVariant.delete
|
||||
self.controller.delete
|
||||
|
||||
method load*(self: Module) =
|
||||
singletonInstance.engine.setRootContextProperty("inputAreaModule", self.viewVariant)
|
||||
|
||||
self.controller.init()
|
||||
self.view.load()
|
||||
|
||||
method isLoaded*(self: Module): bool =
|
||||
return self.moduleLoaded
|
||||
|
||||
method viewDidLoad*(self: Module) =
|
||||
self.moduleLoaded = true
|
||||
self.delegate.inputAreaDidLoad()
|
|
@ -0,0 +1,8 @@
|
|||
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")
|
|
@ -0,0 +1,5 @@
|
|||
type
|
||||
AccessInterface* {.pure inheritable.} = ref object of RootObj
|
||||
|
||||
# Since nim doesn't support using concepts in second level nested types we
|
||||
# define delegate interfaces within access interface.
|
|
@ -0,0 +1,2 @@
|
|||
method viewDidLoad*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
|
@ -0,0 +1,22 @@
|
|||
import NimQml
|
||||
import model
|
||||
import io_interface
|
||||
|
||||
QtObject:
|
||||
type
|
||||
View* = ref object of QObject
|
||||
delegate: io_interface.AccessInterface
|
||||
model: Model
|
||||
|
||||
proc delete*(self: View) =
|
||||
self.model.delete
|
||||
self.QObject.delete
|
||||
|
||||
proc newView*(delegate: io_interface.AccessInterface): View =
|
||||
new(result, delete)
|
||||
result.QObject.setup
|
||||
result.delegate = delegate
|
||||
result.model = newModel()
|
||||
|
||||
proc load*(self: View) =
|
||||
self.delegate.viewDidLoad()
|
|
@ -9,4 +9,6 @@ include ./private_interfaces/module_view_delegate_interface
|
|||
include ./private_interfaces/module_controller_delegate_interface
|
||||
|
||||
# Defines how submodules of this module communicate with this module
|
||||
# will be added if needed
|
||||
include ./private_interfaces/module_input_area_delegate_interface
|
||||
include ./private_interfaces/module_messages_delegate_interface
|
||||
include ./private_interfaces/module_users_delegate_interface
|
|
@ -1,21 +1,55 @@
|
|||
import NimQml
|
||||
import strformat
|
||||
import base_item, sub_model, sub_item
|
||||
|
||||
QtObject:
|
||||
type
|
||||
Item* = ref object of QObject
|
||||
|
||||
proc setup(self: Item) =
|
||||
self.QObject.setup
|
||||
type
|
||||
Item* = ref object of BaseItem
|
||||
`type`: int
|
||||
subItems: SubModel
|
||||
|
||||
proc delete*(self: Item) =
|
||||
self.QObject.delete
|
||||
proc initItem*(id, name, icon, color, description: string, `type`: int, hasNotification: bool, notificationsCount: int,
|
||||
muted, active: bool): Item =
|
||||
result = Item()
|
||||
result.setup(id, name, icon, color, description, hasNotification, notificationsCount, muted, active)
|
||||
result.`type` = `type`
|
||||
result.subItems = newSubModel()
|
||||
|
||||
proc newItem*(): Item =
|
||||
new(result, delete)
|
||||
result.setup()
|
||||
proc delete*(self: Item) =
|
||||
self.subItems.delete
|
||||
self.BaseItem.delete
|
||||
|
||||
proc id*(self: Item): string {.slot.} =
|
||||
self.id
|
||||
proc subItems*(self: Item): SubModel {.inline.} =
|
||||
self.subItems
|
||||
|
||||
QtProperty[string] id:
|
||||
read = id
|
||||
proc type*(self: Item): int {.inline.} =
|
||||
self.`type`
|
||||
|
||||
proc `$`*(self: Item): string =
|
||||
result = fmt"""ChatSectionItem(
|
||||
id: {self.id},
|
||||
name: {self.name},
|
||||
icon: {self.icon},
|
||||
color: {self.color},
|
||||
description: {self.description},
|
||||
type: {self.`type`},
|
||||
hasNotification: {self.hasNotification},
|
||||
notificationsCount: {self.notificationsCount},
|
||||
muted: {self.muted},
|
||||
active: {self.active},
|
||||
subItems:[
|
||||
{$self.subItems}
|
||||
]"""
|
||||
|
||||
proc appendSubItems*(self: Item, items: seq[SubItem]) =
|
||||
self.subItems.appendItems(items)
|
||||
|
||||
proc appendSubItem*(self: Item, item: SubItem) =
|
||||
self.subItems.appendItem(item)
|
||||
|
||||
proc prependSubItems*(self: Item, items: seq[SubItem]) =
|
||||
self.subItems.prependItems(items)
|
||||
|
||||
proc prependSubItem*(self: Item, item: SubItem) =
|
||||
self.subItems.prependItem(item)
|
||||
|
||||
proc setActiveSubItem*(self: Item, subItemId: string) =
|
||||
self.subItems.setActiveItem(subItemId)
|
|
@ -0,0 +1,33 @@
|
|||
import controller_interface
|
||||
import io_interface
|
||||
|
||||
import ../../../../../app_service/service/community/service as community_service
|
||||
|
||||
export controller_interface
|
||||
|
||||
type
|
||||
Controller* = ref object of controller_interface.AccessInterface
|
||||
delegate: io_interface.AccessInterface
|
||||
id: string
|
||||
isCommunityModule: bool
|
||||
communityService: community_service.ServiceInterface
|
||||
|
||||
proc newController*(delegate: io_interface.AccessInterface, id: string, isCommunity: bool,
|
||||
communityService: community_service.ServiceInterface): Controller =
|
||||
result = Controller()
|
||||
result.delegate = delegate
|
||||
result.id = id
|
||||
result.isCommunityModule = isCommunity
|
||||
result.communityService = communityService
|
||||
|
||||
method delete*(self: Controller) =
|
||||
discard
|
||||
|
||||
method init*(self: Controller) =
|
||||
discard
|
||||
|
||||
method getId*(self: Controller): string =
|
||||
return self.id
|
||||
|
||||
method isCommunity*(self: Controller): bool =
|
||||
return self.isCommunityModule
|
|
@ -0,0 +1,19 @@
|
|||
import ../../../../../app_service/service/community/service_interface as community_service
|
||||
|
||||
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 init*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getId*(self: AccessInterface): string {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method isCommunity*(self: AccessInterface): bool {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# Defines how parent module accesses this module
|
||||
include ./private_interfaces/module_base_interface
|
||||
include ./private_interfaces/module_access_interface
|
||||
|
||||
# Defines how this module view communicates with this module
|
||||
include ./private_interfaces/module_view_delegate_interface
|
||||
|
||||
# Defines how this controller communicates with this module
|
||||
include ./private_interfaces/module_controller_delegate_interface
|
||||
|
||||
# Defines how submodules of this module communicate with this module
|
||||
# will be added if needed
|
|
@ -0,0 +1,21 @@
|
|||
import NimQml
|
||||
|
||||
QtObject:
|
||||
type
|
||||
Item* = ref object of QObject
|
||||
|
||||
proc setup(self: Item) =
|
||||
self.QObject.setup
|
||||
|
||||
proc delete*(self: Item) =
|
||||
self.QObject.delete
|
||||
|
||||
proc newItem*(): Item =
|
||||
new(result, delete)
|
||||
result.setup()
|
||||
|
||||
proc id*(self: Item): string {.slot.} =
|
||||
self.id
|
||||
|
||||
QtProperty[string] id:
|
||||
read = id
|
|
@ -0,0 +1,17 @@
|
|||
import NimQml
|
||||
import item
|
||||
|
||||
QtObject:
|
||||
type
|
||||
Model* = ref object of QAbstractListModel
|
||||
sections: seq[Item]
|
||||
|
||||
proc setup(self: Model) =
|
||||
self.QAbstractListModel.setup
|
||||
|
||||
proc delete*(self: Model) =
|
||||
self.QAbstractListModel.delete
|
||||
|
||||
proc newModel*(): Model =
|
||||
new(result, delete)
|
||||
result.setup
|
|
@ -0,0 +1,46 @@
|
|||
import NimQml
|
||||
import io_interface
|
||||
import ../io_interface as delegate_interface
|
||||
import view, controller
|
||||
import ../../../../core/global_singleton
|
||||
|
||||
import ../../../../../app_service/service/chat/service as chat_service
|
||||
import ../../../../../app_service/service/community/service as community_service
|
||||
|
||||
export io_interface
|
||||
|
||||
type
|
||||
Module* = ref object of io_interface.AccessInterface
|
||||
delegate: delegate_interface.AccessInterface
|
||||
view: View
|
||||
viewVariant: QVariant
|
||||
controller: controller.AccessInterface
|
||||
moduleLoaded: bool
|
||||
|
||||
proc newModule*(delegate: delegate_interface.AccessInterface, id: string, isCommunity: bool,
|
||||
chatService: chat_service.Service, communityService: community_service.Service):
|
||||
Module =
|
||||
result = Module()
|
||||
result.delegate = delegate
|
||||
result.view = view.newView(result)
|
||||
result.viewVariant = newQVariant(result.view)
|
||||
result.controller = controller.newController(result, id, isCommunity, communityService)
|
||||
result.moduleLoaded = false
|
||||
|
||||
method delete*(self: Module) =
|
||||
self.view.delete
|
||||
self.viewVariant.delete
|
||||
self.controller.delete
|
||||
|
||||
method load*(self: Module) =
|
||||
singletonInstance.engine.setRootContextProperty("messagesModule", self.viewVariant)
|
||||
|
||||
self.controller.init()
|
||||
self.view.load()
|
||||
|
||||
method isLoaded*(self: Module): bool =
|
||||
return self.moduleLoaded
|
||||
|
||||
method viewDidLoad*(self: Module) =
|
||||
self.moduleLoaded = true
|
||||
self.delegate.messagesDidLoad()
|
|
@ -0,0 +1,8 @@
|
|||
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")
|
|
@ -0,0 +1,5 @@
|
|||
type
|
||||
AccessInterface* {.pure inheritable.} = ref object of RootObj
|
||||
|
||||
# Since nim doesn't support using concepts in second level nested types we
|
||||
# define delegate interfaces within access interface.
|
|
@ -0,0 +1,2 @@
|
|||
method viewDidLoad*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
|
@ -0,0 +1,22 @@
|
|||
import NimQml
|
||||
import model
|
||||
import io_interface
|
||||
|
||||
QtObject:
|
||||
type
|
||||
View* = ref object of QObject
|
||||
delegate: io_interface.AccessInterface
|
||||
model: Model
|
||||
|
||||
proc delete*(self: View) =
|
||||
self.model.delete
|
||||
self.QObject.delete
|
||||
|
||||
proc newView*(delegate: io_interface.AccessInterface): View =
|
||||
new(result, delete)
|
||||
result.QObject.setup
|
||||
result.delegate = delegate
|
||||
result.model = newModel()
|
||||
|
||||
proc load*(self: View) =
|
||||
self.delegate.viewDidLoad()
|
|
@ -1,17 +1,142 @@
|
|||
import NimQml
|
||||
import item
|
||||
import NimQml, Tables, strutils, strformat
|
||||
|
||||
import item, base_item
|
||||
|
||||
type
|
||||
ModelRole {.pure.} = enum
|
||||
Id = UserRole + 1
|
||||
Name
|
||||
Icon
|
||||
Color
|
||||
Description
|
||||
Type
|
||||
HasNotification
|
||||
NotificationsCount
|
||||
Muted
|
||||
Active
|
||||
SubItems
|
||||
|
||||
QtObject:
|
||||
type
|
||||
type
|
||||
Model* = ref object of QAbstractListModel
|
||||
sections: seq[Item]
|
||||
|
||||
proc setup(self: Model) =
|
||||
self.QAbstractListModel.setup
|
||||
items: seq[Item]
|
||||
|
||||
proc delete*(self: Model) =
|
||||
for i in 0 ..< self.items.len:
|
||||
self.items[i].delete
|
||||
|
||||
self.items = @[]
|
||||
self.QAbstractListModel.delete
|
||||
|
||||
proc setup(self: Model) =
|
||||
self.QAbstractListModel.setup
|
||||
|
||||
proc newModel*(): Model =
|
||||
new(result, delete)
|
||||
result.setup
|
||||
result.setup
|
||||
|
||||
proc `$`*(self: Model): string =
|
||||
for i in 0 ..< self.items.len:
|
||||
result &= fmt"""
|
||||
[{i}]:({$self.items[i]})
|
||||
"""
|
||||
|
||||
proc countChanged(self: Model) {.signal.}
|
||||
|
||||
proc getCount(self: Model): int {.slot.} =
|
||||
self.items.len
|
||||
|
||||
QtProperty[int] count:
|
||||
read = getCount
|
||||
notify = countChanged
|
||||
|
||||
method rowCount(self: Model, index: QModelIndex = nil): int =
|
||||
return self.items.len
|
||||
|
||||
method roleNames(self: Model): Table[int, string] =
|
||||
{
|
||||
ModelRole.Id.int:"id",
|
||||
ModelRole.Name.int:"name",
|
||||
ModelRole.Icon.int:"icon",
|
||||
ModelRole.Color.int:"color",
|
||||
ModelRole.Description.int:"description",
|
||||
ModelRole.Type.int:"type",
|
||||
ModelRole.HasNotification.int:"hasNotification",
|
||||
ModelRole.NotificationsCount.int:"notificationsCount",
|
||||
ModelRole.Muted.int:"muted",
|
||||
ModelRole.Active.int:"active",
|
||||
ModelRole.SubItems.int:"subItems",
|
||||
}.toTable
|
||||
|
||||
method data(self: Model, index: QModelIndex, role: int): QVariant =
|
||||
if (not index.isValid):
|
||||
return
|
||||
|
||||
if (index.row < 0 or index.row >= self.items.len):
|
||||
return
|
||||
|
||||
let item = self.items[index.row]
|
||||
let enumRole = role.ModelRole
|
||||
|
||||
case enumRole:
|
||||
of ModelRole.Id:
|
||||
result = newQVariant(item.id)
|
||||
of ModelRole.Name:
|
||||
result = newQVariant(item.name)
|
||||
of ModelRole.Icon:
|
||||
result = newQVariant(item.icon)
|
||||
of ModelRole.Color:
|
||||
result = newQVariant(item.color)
|
||||
of ModelRole.Description:
|
||||
result = newQVariant(item.description)
|
||||
of ModelRole.Type:
|
||||
result = newQVariant(item.`type`)
|
||||
of ModelRole.HasNotification:
|
||||
result = newQVariant(item.hasNotification)
|
||||
of ModelRole.NotificationsCount:
|
||||
result = newQVariant(item.notificationsCount)
|
||||
of ModelRole.Muted:
|
||||
result = newQVariant(item.muted)
|
||||
of ModelRole.Active:
|
||||
result = newQVariant(item.active)
|
||||
of ModelRole.SubItems:
|
||||
result = newQVariant(item.subItems)
|
||||
|
||||
proc appendItem*(self: Model, item: Item) =
|
||||
let parentModelIndex = newQModelIndex()
|
||||
defer: parentModelIndex.delete
|
||||
|
||||
self.beginInsertRows(parentModelIndex, self.items.len, self.items.len)
|
||||
self.items.add(item)
|
||||
self.endInsertRows()
|
||||
|
||||
self.countChanged()
|
||||
|
||||
proc prependItem*(self: Model, item: Item) =
|
||||
let parentModelIndex = newQModelIndex()
|
||||
defer: parentModelIndex.delete
|
||||
|
||||
self.beginInsertRows(parentModelIndex, 0, 0)
|
||||
self.items = item & self.items
|
||||
self.endInsertRows()
|
||||
|
||||
self.countChanged()
|
||||
|
||||
proc getItemById*(self: Model, id: string): Item =
|
||||
for it in self.items:
|
||||
if(it.id == id):
|
||||
return it
|
||||
|
||||
proc setActiveItemSubItem*(self: Model, id: string, subItemId: string) =
|
||||
for i in 0 ..< self.items.len:
|
||||
self.items[i].setActiveSubItem(subItemId)
|
||||
|
||||
if(self.items[i].active):
|
||||
let index = self.createIndex(i, 0, nil)
|
||||
self.items[i].BaseItem.active = false
|
||||
self.dataChanged(index, index, @[ModelRole.Active.int])
|
||||
|
||||
if(self.items[i].id == id):
|
||||
let index = self.createIndex(i, 0, nil)
|
||||
self.items[i].BaseItem.active = true
|
||||
self.dataChanged(index, index, @[ModelRole.Active.int])
|
|
@ -1,56 +1,187 @@
|
|||
import NimQml
|
||||
import NimQml, chronicles
|
||||
import io_interface
|
||||
import ../io_interface as delegate_interface
|
||||
import view, controller
|
||||
import view, controller, item, sub_item, model, sub_model
|
||||
import ../../../core/global_singleton
|
||||
|
||||
import input_area/module as input_area_module
|
||||
import messages/module as messages_module
|
||||
import users/module as users_module
|
||||
|
||||
import ../../../../app_service/service/chat/service as chat_service
|
||||
import ../../../../app_service/service/community/service as community_service
|
||||
|
||||
export io_interface
|
||||
|
||||
logScope:
|
||||
topics = "chat-section-module"
|
||||
|
||||
type
|
||||
Module* = ref object of io_interface.AccessInterface
|
||||
delegate: delegate_interface.AccessInterface
|
||||
view: View
|
||||
viewVariant: QVariant
|
||||
controller: controller.AccessInterface
|
||||
inputAreaModule: input_area_module.AccessInterface
|
||||
messagesModule: messages_module.AccessInterface
|
||||
usersModule: users_module.AccessInterface
|
||||
moduleLoaded: bool
|
||||
|
||||
proc newModule*(delegate: delegate_interface.AccessInterface, id: string,
|
||||
isCommunity: bool, chatService: chat_service.Service,
|
||||
communityService: community_service.Service):
|
||||
proc newModule*(delegate: delegate_interface.AccessInterface, id: string, isCommunity: bool,
|
||||
chatService: chat_service.Service, communityService: community_service.Service):
|
||||
Module =
|
||||
result = Module()
|
||||
result.delegate = delegate
|
||||
result.view = view.newView(result)
|
||||
result.viewVariant = newQVariant(result.view)
|
||||
result.controller = controller.newController(result, id, isCommunity,
|
||||
communityService)
|
||||
result.controller = controller.newController(result, id, isCommunity, chatService, communityService)
|
||||
result.moduleLoaded = false
|
||||
|
||||
result.inputAreaModule = input_area_module.newModule(result, id, isCommunity, chatService, communityService)
|
||||
result.messagesModule = messages_module.newModule(result, id, isCommunity, chatService, communityService)
|
||||
result.usersModule = users_module.newModule(result, id, isCommunity, chatService, communityService)
|
||||
|
||||
method delete*(self: Module) =
|
||||
self.view.delete
|
||||
self.viewVariant.delete
|
||||
self.controller.delete
|
||||
|
||||
proc buildChatUI(self: Module) =
|
||||
let types = @[ChatType.OneToOne, ChatType.Public, ChatType.PrivateGroupChat, ChatType.Profile]
|
||||
let chats = self.controller.getChatDetailsForChatTypes(types)
|
||||
|
||||
var selectedItemId = ""
|
||||
for c in chats:
|
||||
let hasNotification = c.unviewedMessagesCount > 0 or c.unviewedMentionsCount > 0
|
||||
let notificationsCount = c.unviewedMentionsCount
|
||||
let item = initItem(c.id, if c.alias.len > 0: c.alias else: c.name, c.identicon, c.color, c.description,
|
||||
c.chatType.int, hasNotification, notificationsCount, c.muted, false)
|
||||
self.view.appendItem(item)
|
||||
|
||||
# make the first chat active when load the app
|
||||
if(selectedItemId.len == 0):
|
||||
selectedItemId = item.id
|
||||
|
||||
self.controller.setActiveItemSubItem(selectedItemId, "")
|
||||
|
||||
proc buildCommunityUI(self: Module) =
|
||||
var selectedItemId = ""
|
||||
var selectedSubItemId = ""
|
||||
let communityIds = self.controller.getCommunityIds()
|
||||
for cId in communityIds:
|
||||
# handle channels which don't belong to any category
|
||||
let chats = self.controller.getChats(cId, "")
|
||||
for c in chats:
|
||||
let chatDto = self.controller.getChatDetails(cId, c.id)
|
||||
|
||||
let hasNotification = chatDto.unviewedMessagesCount > 0 or chatDto.unviewedMentionsCount > 0
|
||||
let notificationsCount = chatDto.unviewedMentionsCount
|
||||
let channelItem = initItem(chatDto.id, if chatDto.alias.len > 0: chatDto.alias else: chatDto.name,
|
||||
chatDto.identicon, chatDto.color, chatDto.description, chatDto.chatType.int, hasNotification, notificationsCount,
|
||||
chatDto.muted, false)
|
||||
self.view.appendItem(channelItem)
|
||||
|
||||
# make the first channel which doesn't belong to any category active when load the app
|
||||
if(selectedItemId.len == 0):
|
||||
selectedItemId = channelItem.id
|
||||
|
||||
# handle categories and channels for each category
|
||||
let categories = self.controller.getCategories(cId)
|
||||
for cat in categories:
|
||||
var hasNotificationPerCategory = false
|
||||
var notificationsCountPerCategory = 0
|
||||
var categoryChannels: seq[SubItem]
|
||||
|
||||
let categoryChats = self.controller.getChats(cId, cat.id)
|
||||
for c in categoryChats:
|
||||
let chatDto = self.controller.getChatDetails(cId, c.id)
|
||||
|
||||
let hasNotification = chatDto.unviewedMessagesCount > 0 or chatDto.unviewedMentionsCount > 0
|
||||
let notificationsCount = chatDto.unviewedMentionsCount
|
||||
|
||||
hasNotificationPerCategory = hasNotificationPerCategory or hasNotification
|
||||
notificationsCountPerCategory += notificationsCount
|
||||
|
||||
let channelItem = initSubItem(chatDto.id, if chatDto.alias.len > 0: chatDto.alias else: chatDto.name,
|
||||
chatDto.identicon, chatDto.color, chatDto.description, hasNotification, notificationsCount, chatDto.muted,
|
||||
false)
|
||||
categoryChannels.add(channelItem)
|
||||
|
||||
# in case there is no channels beyond categories,
|
||||
# make the first channel of the first category active when load the app
|
||||
if(selectedItemId.len == 0):
|
||||
selectedItemId = cat.id
|
||||
selectedSubItemId = channelItem.id
|
||||
|
||||
var categoryItem = initItem(cat.id, cat.name, "", "", "", ChatType.Unknown.int, hasNotificationPerCategory,
|
||||
notificationsCountPerCategory, false, false)
|
||||
categoryItem.prependSubItems(categoryChannels)
|
||||
self.view.appendItem(categoryItem)
|
||||
|
||||
self.setActiveItemSubItem(selectedItemId, selectedSubItemId)
|
||||
|
||||
method load*(self: Module) =
|
||||
if(self.controller.isCommunity()):
|
||||
singletonInstance.engine.setRootContextProperty("communitySectionModule",
|
||||
self.viewVariant)
|
||||
else:
|
||||
singletonInstance.engine.setRootContextProperty("chatSectionModule",
|
||||
self.viewVariant)
|
||||
|
||||
self.controller.init()
|
||||
self.view.load()
|
||||
|
||||
if(self.controller.isCommunity()):
|
||||
singletonInstance.engine.setRootContextProperty("communitySectionModule", self.viewVariant)
|
||||
self.buildCommunityUI()
|
||||
else:
|
||||
singletonInstance.engine.setRootContextProperty("chatSectionModule", self.viewVariant)
|
||||
self.buildChatUI()
|
||||
|
||||
self.inputAreaModule.load()
|
||||
self.messagesModule.load()
|
||||
self.usersModule.load()
|
||||
|
||||
proc checkIfModuleDidLoad(self: Module) =
|
||||
if self.moduleLoaded:
|
||||
return
|
||||
|
||||
if(not self.inputAreaModule.isLoaded()):
|
||||
return
|
||||
|
||||
if (not self.messagesModule.isLoaded()):
|
||||
return
|
||||
|
||||
if (not self.usersModule.isLoaded()):
|
||||
return
|
||||
|
||||
self.moduleLoaded = true
|
||||
if(self.controller.isCommunity()):
|
||||
self.delegate.communitySectionDidLoad()
|
||||
else:
|
||||
self.delegate.chatSectionDidLoad()
|
||||
|
||||
method isLoaded*(self: Module): bool =
|
||||
return self.moduleLoaded
|
||||
|
||||
method viewDidLoad*(self: Module) =
|
||||
self.moduleLoaded = true
|
||||
if(self.controller.isCommunity()):
|
||||
self.delegate.communitySectionDidLoad()
|
||||
else:
|
||||
self.delegate.chatSectionDidLoad()
|
||||
self.checkIfModuleDidLoad()
|
||||
|
||||
method inputAreaDidLoad*(self: Module) =
|
||||
self.checkIfModuleDidLoad()
|
||||
|
||||
method messagesDidLoad*(self: Module) =
|
||||
self.checkIfModuleDidLoad()
|
||||
|
||||
method usersDidLoad*(self: Module) =
|
||||
self.checkIfModuleDidLoad()
|
||||
|
||||
method setActiveItemSubItem*(self: Module, itemId: string, subItemId: string) =
|
||||
self.controller.setActiveItemSubItem(itemId, subItemId)
|
||||
|
||||
method activeItemSubItemSet*(self: Module, itemId: string, subItemId: string) =
|
||||
let item = self.view.model().getItemById(itemId)
|
||||
if(item.isNil):
|
||||
# Should never be here
|
||||
error "chat-view unexisting item id: ", itemId
|
||||
return
|
||||
|
||||
# Chats from Chat section and chats from Community section which don't belong
|
||||
# to any category have empty `subItemId`
|
||||
let subItem = item.subItems.getItemById(subItemId)
|
||||
|
||||
self.view.model().setActiveItemSubItem(itemId, subItemId)
|
||||
self.view.activeItemSubItemSet(item, subItem)
|
|
@ -0,0 +1,2 @@
|
|||
method activeItemSubItemSet*(self: AccessInterface, itemId: string, subItemId: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
|
@ -0,0 +1,2 @@
|
|||
method inputAreaDidLoad*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
|
@ -0,0 +1,2 @@
|
|||
method messagesDidLoad*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
|
@ -0,0 +1,2 @@
|
|||
method usersDidLoad*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
|
@ -1,2 +1,5 @@
|
|||
method viewDidLoad*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method setActiveItemSubItem*(self: AccessInterface, itemId: string, subItemId: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
|
@ -0,0 +1,28 @@
|
|||
import strformat
|
||||
import base_item
|
||||
|
||||
export base_item
|
||||
|
||||
type
|
||||
SubItem* = ref object of BaseItem
|
||||
|
||||
proc initSubItem*(id, name, icon, color, description: string, hasNotification: bool, notificationsCount: int,
|
||||
muted, active: bool): SubItem =
|
||||
result = SubItem()
|
||||
result.setup(id, name, icon, color, description, hasNotification, notificationsCount, muted, active)
|
||||
|
||||
proc delete*(self: SubItem) =
|
||||
self.BaseItem.delete
|
||||
|
||||
proc `$`*(self: SubItem): string =
|
||||
result = fmt"""ChatSectionSubItem(
|
||||
id: {self.id},
|
||||
name: {self.name},
|
||||
icon: {self.icon},
|
||||
color: {self.color},
|
||||
description: {self.description},
|
||||
hasNotification: {self.hasNotification},
|
||||
notificationsCount: {self.notificationsCount},
|
||||
muted: {self.muted},
|
||||
active: {self.active}
|
||||
]"""
|
|
@ -0,0 +1,156 @@
|
|||
import NimQml, Tables, strformat
|
||||
|
||||
import sub_item
|
||||
|
||||
type
|
||||
ModelRole {.pure.} = enum
|
||||
Id = UserRole + 1
|
||||
Name
|
||||
Icon
|
||||
Color
|
||||
Description
|
||||
HasNotification
|
||||
NotificationsCount
|
||||
Muted
|
||||
Active
|
||||
|
||||
QtObject:
|
||||
type
|
||||
SubModel* = ref object of QAbstractListModel
|
||||
items: seq[SubItem]
|
||||
|
||||
proc delete*(self: SubModel) =
|
||||
for i in 0 ..< self.items.len:
|
||||
self.items[i].delete
|
||||
|
||||
self.items = @[]
|
||||
self.QAbstractListModel.delete
|
||||
|
||||
proc setup(self: SubModel) =
|
||||
self.QAbstractListModel.setup
|
||||
|
||||
proc newSubModel*(): SubModel =
|
||||
new(result, delete)
|
||||
result.setup
|
||||
|
||||
proc `$`*(self: SubModel): string =
|
||||
for i in 0 ..< self.items.len:
|
||||
result &= fmt"""
|
||||
[{i}]:({$self.items[i]})
|
||||
"""
|
||||
|
||||
proc countChanged(self: SubModel) {.signal.}
|
||||
|
||||
proc getCount(self: SubModel): int {.slot.} =
|
||||
self.items.len
|
||||
|
||||
QtProperty[int] count:
|
||||
read = getCount
|
||||
notify = countChanged
|
||||
|
||||
method rowCount(self: SubModel, index: QModelIndex = nil): int =
|
||||
return self.items.len
|
||||
|
||||
method roleNames(self: SubModel): Table[int, string] =
|
||||
{
|
||||
ModelRole.Id.int:"id",
|
||||
ModelRole.Name.int:"name",
|
||||
ModelRole.Icon.int:"icon",
|
||||
ModelRole.Color.int:"color",
|
||||
ModelRole.Description.int:"description",
|
||||
ModelRole.HasNotification.int:"hasNotification",
|
||||
ModelRole.NotificationsCount.int:"notificationsCount",
|
||||
ModelRole.Muted.int:"muted",
|
||||
ModelRole.Active.int:"active"
|
||||
}.toTable
|
||||
|
||||
method data(self: SubModel, index: QModelIndex, role: int): QVariant =
|
||||
if (not index.isValid):
|
||||
return
|
||||
|
||||
if (index.row < 0 or index.row >= self.items.len):
|
||||
return
|
||||
|
||||
let item = self.items[index.row]
|
||||
let enumRole = role.ModelRole
|
||||
|
||||
case enumRole:
|
||||
of ModelRole.Id:
|
||||
result = newQVariant(item.id)
|
||||
of ModelRole.Name:
|
||||
result = newQVariant(item.name)
|
||||
of ModelRole.Icon:
|
||||
result = newQVariant(item.icon)
|
||||
of ModelRole.Color:
|
||||
result = newQVariant(item.color)
|
||||
of ModelRole.Description:
|
||||
result = newQVariant(item.description)
|
||||
of ModelRole.HasNotification:
|
||||
result = newQVariant(item.hasNotification)
|
||||
of ModelRole.NotificationsCount:
|
||||
result = newQVariant(item.notificationsCount)
|
||||
of ModelRole.Muted:
|
||||
result = newQVariant(item.muted)
|
||||
of ModelRole.Active:
|
||||
result = newQVariant(item.active)
|
||||
|
||||
proc appendItems*(self: SubModel, items: seq[SubItem]) =
|
||||
let parentModelIndex = newQModelIndex()
|
||||
defer: parentModelIndex.delete
|
||||
|
||||
let first = self.items.len
|
||||
let last = first + items.len - 1
|
||||
self.beginInsertRows(parentModelIndex, first, last)
|
||||
self.items.add(items)
|
||||
self.endInsertRows()
|
||||
|
||||
self.countChanged()
|
||||
|
||||
proc appendItem*(self: SubModel, item: SubItem) =
|
||||
let parentModelIndex = newQModelIndex()
|
||||
defer: parentModelIndex.delete
|
||||
|
||||
self.beginInsertRows(parentModelIndex, self.items.len, self.items.len)
|
||||
self.items.add(item)
|
||||
self.endInsertRows()
|
||||
|
||||
self.countChanged()
|
||||
|
||||
proc prependItems*(self: SubModel, items: seq[SubItem]) =
|
||||
let parentModelIndex = newQModelIndex()
|
||||
defer: parentModelIndex.delete
|
||||
|
||||
let first = 0
|
||||
let last = items.len - 1
|
||||
self.beginInsertRows(parentModelIndex, first, last)
|
||||
self.items = items & self.items
|
||||
self.endInsertRows()
|
||||
|
||||
self.countChanged()
|
||||
|
||||
proc prependItem*(self: SubModel, item: SubItem) =
|
||||
let parentModelIndex = newQModelIndex()
|
||||
defer: parentModelIndex.delete
|
||||
|
||||
self.beginInsertRows(parentModelIndex, 0, 0)
|
||||
self.items = item & self.items
|
||||
self.endInsertRows()
|
||||
|
||||
self.countChanged()
|
||||
|
||||
proc getItemById*(self: SubModel, id: string): SubItem =
|
||||
for it in self.items:
|
||||
if(it.id == id):
|
||||
return it
|
||||
|
||||
proc setActiveItem*(self: SubModel, id: string) =
|
||||
for i in 0 ..< self.items.len:
|
||||
if(self.items[i].active):
|
||||
let index = self.createIndex(i, 0, nil)
|
||||
self.items[i].BaseItem.active = false
|
||||
self.dataChanged(index, index, @[ModelRole.Active.int])
|
||||
|
||||
if(self.items[i].id == id):
|
||||
let index = self.createIndex(i, 0, nil)
|
||||
self.items[i].BaseItem.active= true
|
||||
self.dataChanged(index, index, @[ModelRole.Active.int])
|
|
@ -0,0 +1,33 @@
|
|||
import controller_interface
|
||||
import io_interface
|
||||
|
||||
import ../../../../../app_service/service/community/service as community_service
|
||||
|
||||
export controller_interface
|
||||
|
||||
type
|
||||
Controller* = ref object of controller_interface.AccessInterface
|
||||
delegate: io_interface.AccessInterface
|
||||
id: string
|
||||
isCommunityModule: bool
|
||||
communityService: community_service.ServiceInterface
|
||||
|
||||
proc newController*(delegate: io_interface.AccessInterface, id: string, isCommunity: bool,
|
||||
communityService: community_service.ServiceInterface): Controller =
|
||||
result = Controller()
|
||||
result.delegate = delegate
|
||||
result.id = id
|
||||
result.isCommunityModule = isCommunity
|
||||
result.communityService = communityService
|
||||
|
||||
method delete*(self: Controller) =
|
||||
discard
|
||||
|
||||
method init*(self: Controller) =
|
||||
discard
|
||||
|
||||
method getId*(self: Controller): string =
|
||||
return self.id
|
||||
|
||||
method isCommunity*(self: Controller): bool =
|
||||
return self.isCommunityModule
|
|
@ -0,0 +1,19 @@
|
|||
import ../../../../../app_service/service/community/service_interface as community_service
|
||||
|
||||
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 init*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getId*(self: AccessInterface): string {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method isCommunity*(self: AccessInterface): bool {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# Defines how parent module accesses this module
|
||||
include ./private_interfaces/module_base_interface
|
||||
include ./private_interfaces/module_access_interface
|
||||
|
||||
# Defines how this module view communicates with this module
|
||||
include ./private_interfaces/module_view_delegate_interface
|
||||
|
||||
# Defines how this controller communicates with this module
|
||||
include ./private_interfaces/module_controller_delegate_interface
|
||||
|
||||
# Defines how submodules of this module communicate with this module
|
||||
# will be added if needed
|
|
@ -0,0 +1,21 @@
|
|||
import NimQml
|
||||
|
||||
QtObject:
|
||||
type
|
||||
Item* = ref object of QObject
|
||||
|
||||
proc setup(self: Item) =
|
||||
self.QObject.setup
|
||||
|
||||
proc delete*(self: Item) =
|
||||
self.QObject.delete
|
||||
|
||||
proc newItem*(): Item =
|
||||
new(result, delete)
|
||||
result.setup()
|
||||
|
||||
proc id*(self: Item): string {.slot.} =
|
||||
self.id
|
||||
|
||||
QtProperty[string] id:
|
||||
read = id
|
|
@ -0,0 +1,17 @@
|
|||
import NimQml
|
||||
import item
|
||||
|
||||
QtObject:
|
||||
type
|
||||
Model* = ref object of QAbstractListModel
|
||||
sections: seq[Item]
|
||||
|
||||
proc setup(self: Model) =
|
||||
self.QAbstractListModel.setup
|
||||
|
||||
proc delete*(self: Model) =
|
||||
self.QAbstractListModel.delete
|
||||
|
||||
proc newModel*(): Model =
|
||||
new(result, delete)
|
||||
result.setup
|
|
@ -0,0 +1,46 @@
|
|||
import NimQml
|
||||
import io_interface
|
||||
import ../io_interface as delegate_interface
|
||||
import view, controller
|
||||
import ../../../../core/global_singleton
|
||||
|
||||
import ../../../../../app_service/service/chat/service as chat_service
|
||||
import ../../../../../app_service/service/community/service as community_service
|
||||
|
||||
export io_interface
|
||||
|
||||
type
|
||||
Module* = ref object of io_interface.AccessInterface
|
||||
delegate: delegate_interface.AccessInterface
|
||||
view: View
|
||||
viewVariant: QVariant
|
||||
controller: controller.AccessInterface
|
||||
moduleLoaded: bool
|
||||
|
||||
proc newModule*(delegate: delegate_interface.AccessInterface, id: string, isCommunity: bool,
|
||||
chatService: chat_service.Service, communityService: community_service.Service):
|
||||
Module =
|
||||
result = Module()
|
||||
result.delegate = delegate
|
||||
result.view = view.newView(result)
|
||||
result.viewVariant = newQVariant(result.view)
|
||||
result.controller = controller.newController(result, id, isCommunity, communityService)
|
||||
result.moduleLoaded = false
|
||||
|
||||
method delete*(self: Module) =
|
||||
self.view.delete
|
||||
self.viewVariant.delete
|
||||
self.controller.delete
|
||||
|
||||
method load*(self: Module) =
|
||||
singletonInstance.engine.setRootContextProperty("usersModule", self.viewVariant)
|
||||
|
||||
self.controller.init()
|
||||
self.view.load()
|
||||
|
||||
method isLoaded*(self: Module): bool =
|
||||
return self.moduleLoaded
|
||||
|
||||
method viewDidLoad*(self: Module) =
|
||||
self.moduleLoaded = true
|
||||
self.delegate.usersDidLoad()
|
|
@ -0,0 +1,8 @@
|
|||
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")
|
|
@ -0,0 +1,5 @@
|
|||
type
|
||||
AccessInterface* {.pure inheritable.} = ref object of RootObj
|
||||
|
||||
# Since nim doesn't support using concepts in second level nested types we
|
||||
# define delegate interfaces within access interface.
|
|
@ -0,0 +1,2 @@
|
|||
method viewDidLoad*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
|
@ -0,0 +1,22 @@
|
|||
import NimQml
|
||||
import model
|
||||
import io_interface
|
||||
|
||||
QtObject:
|
||||
type
|
||||
View* = ref object of QObject
|
||||
delegate: io_interface.AccessInterface
|
||||
model: Model
|
||||
|
||||
proc delete*(self: View) =
|
||||
self.model.delete
|
||||
self.QObject.delete
|
||||
|
||||
proc newView*(delegate: io_interface.AccessInterface): View =
|
||||
new(result, delete)
|
||||
result.QObject.setup
|
||||
result.delegate = delegate
|
||||
result.model = newModel()
|
||||
|
||||
proc load*(self: View) =
|
||||
self.delegate.viewDidLoad()
|
|
@ -1,5 +1,5 @@
|
|||
import NimQml
|
||||
import model
|
||||
import model, item, sub_item, active_item
|
||||
import io_interface
|
||||
|
||||
QtObject:
|
||||
|
@ -7,9 +7,15 @@ QtObject:
|
|||
View* = ref object of QObject
|
||||
delegate: io_interface.AccessInterface
|
||||
model: Model
|
||||
modelVariant: QVariant
|
||||
activeItem: ActiveItem
|
||||
activeItemVariant: QVariant
|
||||
|
||||
proc delete*(self: View) =
|
||||
self.model.delete
|
||||
self.modelVariant.delete
|
||||
self.activeItem.delete
|
||||
self.activeItemVariant.delete
|
||||
self.QObject.delete
|
||||
|
||||
proc newView*(delegate: io_interface.AccessInterface): View =
|
||||
|
@ -17,6 +23,43 @@ QtObject:
|
|||
result.QObject.setup
|
||||
result.delegate = delegate
|
||||
result.model = newModel()
|
||||
result.modelVariant = newQVariant(result.model)
|
||||
result.activeItem = newActiveItem()
|
||||
result.activeItemVariant = newQVariant(result.activeItem)
|
||||
|
||||
proc load*(self: View) =
|
||||
self.delegate.viewDidLoad()
|
||||
self.delegate.viewDidLoad()
|
||||
|
||||
proc model*(self: View): Model =
|
||||
return self.model
|
||||
|
||||
proc modelChanged*(self: View) {.signal.}
|
||||
|
||||
proc getModel(self: View): QVariant {.slot.} =
|
||||
return self.modelVariant
|
||||
|
||||
QtProperty[QVariant] model:
|
||||
read = getModel
|
||||
notify = modelChanged
|
||||
|
||||
proc appendItem*(self: View, item: Item) =
|
||||
self.model.appendItem(item)
|
||||
|
||||
proc prependItem*(self: View, item: Item) =
|
||||
self.model.prependItem(item)
|
||||
|
||||
proc activeItemChanged*(self:View) {.signal.}
|
||||
|
||||
proc getActiveItem(self: View): QVariant {.slot.} =
|
||||
return self.activeItemVariant
|
||||
|
||||
QtProperty[QVariant] activeItem:
|
||||
read = getActiveItem
|
||||
notify = activeItemChanged
|
||||
|
||||
method activeItemSubItemSet*(self: View, item: Item, subItem: SubItem) =
|
||||
self.activeItem.setActiveItemData(item, subItem)
|
||||
self.activeItemChanged()
|
||||
|
||||
proc setActiveItem*(self: View, itemId: string, subItemId: string = "") {.slot.} =
|
||||
self.delegate.setActiveItemSubItem(itemId, subItemId)
|
|
@ -37,3 +37,12 @@ method init*(self: Service) =
|
|||
method getAllChats*(self: Service): seq[ChatDto] =
|
||||
return toSeq(self.chats.values)
|
||||
|
||||
method getChatsOfChatTypes*(self: Service, types: seq[ChatType]): seq[ChatDto] =
|
||||
return self.getAllChats().filterIt(it.chatType in types)
|
||||
|
||||
method getChatById*(self: Service, chatId: string): ChatDto =
|
||||
if(not self.chats.contains(chatId)):
|
||||
error "trying to get chat data for an unexisting chat id"
|
||||
return
|
||||
|
||||
return self.chats[chatId]
|
|
@ -15,3 +15,8 @@ method init*(self: ServiceInterface) {.base.} =
|
|||
method getAllChats*(self: ServiceInterface): seq[ChatDto] {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getChatsOfChatTypes*(self: ServiceInterface, types: seq[ChatType]): seq[ChatDto] {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getChatById*(self: ServiceInterface, chatId: string): ChatDto {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
|
@ -1,4 +1,4 @@
|
|||
import Tables, json, sequtils, strformat, chronicles
|
||||
import Tables, json, sequtils, std/algorithm, strformat, chronicles
|
||||
|
||||
import service_interface, ./dto/community
|
||||
|
||||
|
@ -40,4 +40,50 @@ method init*(self: Service) =
|
|||
return
|
||||
|
||||
method getCommunities*(self: Service): seq[CommunityDto] =
|
||||
return toSeq(self.communities.values)
|
||||
return toSeq(self.communities.values)
|
||||
|
||||
method getCommunityIds*(self: Service): seq[string] =
|
||||
return toSeq(self.communities.keys)
|
||||
|
||||
proc sortAsc[T](t1, t2: T): int =
|
||||
if(t1.position > t2.position):
|
||||
return 1
|
||||
elif (t1.position < t2.position):
|
||||
return -1
|
||||
else:
|
||||
return 0
|
||||
|
||||
proc sortDesc[T](t1, t2: T): int =
|
||||
if(t1.position < t2.position):
|
||||
return 1
|
||||
elif (t1.position > t2.position):
|
||||
return -1
|
||||
else:
|
||||
return 0
|
||||
|
||||
method getCategories*(self: Service, communityId: string, order: SortOrder = SortOrder.Ascending): seq[Category] =
|
||||
if(not self.communities.contains(communityId)):
|
||||
error "trying to get community for an unexisting community id"
|
||||
return
|
||||
|
||||
result = self.communities[communityId].categories
|
||||
if(order == SortOrder.Ascending):
|
||||
result.sort(sortAsc[Category])
|
||||
else:
|
||||
result.sort(sortDesc[Category])
|
||||
|
||||
method getChats*(self: Service, communityId: string, categoryId = "", order = SortOrder.Ascending): seq[Chat] =
|
||||
if(not self.communities.contains(communityId)):
|
||||
error "trying to get community for an unexisting community id"
|
||||
return
|
||||
|
||||
for chat in self.communities[communityId].chats:
|
||||
if(chat.categoryId != categoryId):
|
||||
continue
|
||||
|
||||
result.add(chat)
|
||||
|
||||
if(order == SortOrder.Ascending):
|
||||
result.sort(sortAsc[Chat])
|
||||
else:
|
||||
result.sort(sortDesc[Chat])
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import std/algorithm
|
||||
import ./dto/community as community_dto
|
||||
|
||||
export community_dto
|
||||
|
@ -14,3 +15,14 @@ method init*(self: ServiceInterface) {.base.} =
|
|||
|
||||
method getCommunities*(self: ServiceInterface): seq[CommunityDto] {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getCommunityIds*(self: ServiceInterface): seq[string] {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getCategories*(self: ServiceInterface, communityId: string, order: SortOrder = SortOrder.Ascending): seq[Category]
|
||||
{.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getChats*(self: ServiceInterface, communityId: string, categoryId = "", order = SortOrder.Ascending): seq[Chat]
|
||||
{.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
Loading…
Reference in New Issue