A base structure for new architecture added

Initial structure for MainModule containing ChatSectionModule and
CommunitySectionModule is added, as well as initial structure for
StartupModule containing OnboardingModule and LoginModule.

Order of execution is updated and adapted to the current app state.
Main module gets loaded once a user is successfully logged in.
This commit is contained in:
Sale Djenic 2021-10-06 22:05:13 +02:00 committed by Iuri Matias
parent 69656cfef5
commit 9f4eeffdea
56 changed files with 1972 additions and 59 deletions

View File

@ -0,0 +1,110 @@
import NimQml
import ../../app_service/service/contacts/service as contact_service
import ../../app_service/service/chat/service as chat_service
import ../../app_service/service/community/service as community_service
import ../modules/startup/module as startup_module
import ../modules/main/module as main_module
import global_singleton
# This will be removed later:
import status/status
import ../../app_service/[main]
# This to will be adapted to appropriate modules later:
import ../onboarding/core as onboarding
import ../login/core as login
import status/types/[account]
type
AppController* = ref object of RootObj
# Services
contactService: contact_service.Service
chatService: chat_service.Service
communityService: community_service.Service
# Modules
startupModule: startup_module.AccessInterface
mainModule: main_module.AccessInterface
# This to will be adapted to appropriate modules later:
status: Status
appService: AppService
login: LoginController
onboarding: OnboardingController
accountArgs: AccountArgs
#################################################
# Forward declaration section
proc load*(self: AppController)
# Startup Module Delegate Interface
proc startupDidLoad*(self: AppController)
# Main Module Delegate Interface
proc mainDidLoad*(self: AppController)
#################################################
proc connect(self: AppController) =
self.status.events.once("login") do(a: Args):
self.accountArgs = AccountArgs(a)
self.load()
self.status.events.once("nodeStopped") do(a: Args):
self.login.reset()
self.onboarding.reset()
proc newAppController*(status: Status, appService: AppService): AppController =
result = AppController()
# Services
result.contactService = contact_service.newService()
result.chatService = chat_service.newService()
result.communityService = community_service.newService()
# Modules
result.startupModule = startup_module.newModule[AppController](result)
result.mainModule = main_module.newModule[AppController](result, result.communityService)
# Adding status and appService here now is just because of having a controll
# over order of execution while we integrating this refactoring architecture
# into the current app state.
# Once we complete refactoring process we will get rid of "status" part/lib.
#
# This to will be adapted to appropriate modules later:
result.status = status
result.appService = appService
result.login = login.newController(status, appService)
result.onboarding = onboarding.newController(status)
singletonInstance.engine.setRootContextProperty("loginModel", result.login.variant)
singletonInstance.engine.setRootContextProperty("onboardingModel", result.onboarding.variant)
result.connect()
proc delete*(self: AppController) =
self.startupModule.delete
self.mainModule.delete
self.login.delete
self.onboarding.delete
proc startupDidLoad*(self: AppController) =
discard
proc mainDidLoad*(self: AppController) =
# This to will be adapted to appropriate modules later:
self.appService.onLoggedIn()
# Reset login and onboarding to remove any mnemonic that would have been saved in the accounts list
self.login.reset()
self.onboarding.reset()
self.login.moveToAppState()
self.onboarding.moveToAppState()
self.status.events.emit("loginCompleted", self.accountArgs)
proc start*(self: AppController) =
self.login.init()
self.onboarding.init()
proc load*(self: AppController) =
self.contactService.init()
self.chatService.init()
self.communityService.init()
self.startupModule.load()
self.mainModule.load()

View File

@ -0,0 +1,18 @@
import NimQml
type
GlobalSingleton = object
# Don't export GlobalSingleton type.
# Other global things like local/global settings will be added here.
var singletonInstance* = GlobalSingleton()
proc engine*(self: GlobalSingleton): QQmlApplicationEngine =
var qmlEngine {.global.}: QQmlApplicationEngine
if (qmlEngine.isNil):
qmlEngine = newQQmlApplicationEngine()
return qmlEngine
proc delete*(self: GlobalSingleton) =
self.engine.delete()

View File

@ -0,0 +1,18 @@
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")
type
## Abstract class (concept) which must be implemented by object/s used in this
## module.
DelegateInterface* = concept c
c.chatSectionDidLoad()

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,25 @@
import io_interface, view
export io_interface
type
Module* [T: DelegateInterface] = ref object of AccessInterface
delegate: T
view: View
moduleLoaded: bool
proc newModule*[T](delegate: T): Module[T] =
result = Module[T]()
result.delegate = delegate
result.view = newView()
result.moduleLoaded = false
method delete*[T](self: Module[T]) =
self.view.delete
method load*[T](self: Module[T]) =
self.moduleLoaded = true
self.delegate.chatSectionDidLoad()
method isLoaded*[T](self: Module[T]): bool =
return self.moduleLoaded

View File

@ -0,0 +1,19 @@
import NimQml
import model
QtObject:
type
View* = ref object of QObject
model: Model
proc setup(self: View) =
self.QObject.setup
self.model = newModel()
proc delete*(self: View) =
self.model.delete
self.QObject.delete
proc newView*(): View =
new(result, delete)
result.setup()

View File

@ -0,0 +1,35 @@
import Tables
import controller_interface
import ../../../../app_service/service/community/service as community_service
export controller_interface
type
Controller*[T: controller_interface.DelegateInterface] =
ref object of controller_interface.AccessInterface
delegate: T
id: string
communityService: community_service.ServiceInterface
proc newController*[T](delegate: T,
id: string,
communityService: community_service.ServiceInterface):
Controller[T] =
result = Controller[T]()
result.delegate = delegate
result.id = id
result.communityService = communityService
method delete*[T](self: Controller[T]) =
discard
method init*[T](self: Controller[T]) =
discard
method getId*(self: Controller): string =
return self.id
method getCommunities*(self: Controller): seq[community_service.Dto] =
return self.communityService.getCommunities()

View File

@ -0,0 +1,24 @@
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 getCommunities*(self: AccessInterface): seq[community_service.Dto] {.base.} =
raise newException(ValueError, "No implementation available")
type
## Abstract class (concept) which must be implemented by object/s used in this
## module.
DelegateInterface* = concept c

View File

@ -0,0 +1,24 @@
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")
# 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")
type
## Abstract class (concept) which must be implemented by object/s used in this
## module.
DelegateInterface* = concept c
c.communitySectionDidLoad()

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,39 @@
import NimQml
import io_interface, view, controller
import ../../../../app_service/service/community/service as community_service
export io_interface
type
Module* [T: io_interface.DelegateInterface] = ref object of io_interface.AccessInterface
delegate: T
view: View
viewVariant: QVariant
controller: controller.AccessInterface
moduleLoaded: bool
proc newModule*[T](delegate: T, id: string,
communityService: community_service.Service):
Module[T] =
result = Module[T]()
result.delegate = delegate
result.view = view.newView(result)
result.viewVariant = newQVariant(result.view)
result.controller = controller.newController[Module[T]](result, id, communityService)
result.moduleLoaded = false
method delete*[T](self: Module[T]) =
self.view.delete
self.viewVariant.delete
self.controller.delete
method load*[T](self: Module[T]) =
self.moduleLoaded = true
self.delegate.communitySectionDidLoad()
method isLoaded*[T](self: Module[T]): bool =
return self.moduleLoaded
method viewDidLoad*(self: Module) =
discard

View File

@ -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()

View File

@ -0,0 +1,29 @@
import Tables
import controller_interface
import ../../../app_service/service/community/service as community_service
export controller_interface
type
Controller*[T: controller_interface.DelegateInterface] =
ref object of controller_interface.AccessInterface
delegate: T
communityService: community_service.ServiceInterface
proc newController*[T](delegate: T,
communityService: community_service.ServiceInterface):
Controller[T] =
result = Controller[T]()
result.delegate = delegate
result.communityService = communityService
method delete*[T](self: Controller[T]) =
discard
method init*[T](self: Controller[T]) =
discard
method getCommunities*[T](self: Controller[T]): seq[community_service.Dto] =
return self.communityService.getCommunities()

View File

@ -0,0 +1,21 @@
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 getCommunities*(self: AccessInterface): seq[community_service.Dto] {.base.} =
raise newException(ValueError, "No implementation available")
type
## Abstract class (concept) which must be implemented by object/s used in this
## module.
DelegateInterface* = concept c

View File

@ -0,0 +1,22 @@
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")
# 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")
type
## Abstract class (concept) which must be implemented by object/s used in this
## module.
DelegateInterface* = concept c
c.mainDidLoad()

View File

@ -0,0 +1,53 @@
import json, strformat
type
Item* = object
id: string
name: string
image: string
icon: string
color: string
mentionsCount: int
unviewedMessagesCount: int
proc initItem*(id, name, image, icon, color: string,
mentionsCount, unviewedMessagesCount: int): Item =
result.id = id
result.name = name
result.image = image
result.icon = icon
result.color = color
result.mentionsCount = mentionsCount
result.unviewedMessagesCount = unviewedMessagesCount
proc `$`*(self: Item): string =
result = fmt"""MainModuleItem(
id: {self.id},
name: {self.name},
image: {self.image},
icon: {self.icon},
color: {self.color},
mentionsCount: {self.mentionsCount},
unviewedMessagesCount:{self.unviewedMessagesCount}
]"""
proc getId*(self: Item): string =
return self.id
proc getName*(self: Item): string =
return self.name
proc getImage*(self: Item): string =
return self.image
proc getIcon*(self: Item): string =
return self.icon
proc getColor*(self: Item): string =
return self.color
proc getMentionsCount*(self: Item): int =
return self.mentionsCount
proc getUnviewedMessagesCount*(self: Item): int =
return self.unviewedMessagesCount

View File

@ -0,0 +1,94 @@
import NimQml, Tables, strutils, strformat
import item
type
ModelRole {.pure.} = enum
Id = UserRole + 1
Name
Image
Icon
Color
MentionsCount
UnviewedMessagesCount
QtObject:
type
Model* = ref object of QAbstractListModel
items: seq[Item]
proc delete(self: Model) =
self.items = @[]
self.QAbstractListModel.delete
proc setup(self: Model) =
self.QAbstractListModel.setup
proc newModel*(): Model =
new(result, delete)
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.Image.int:"image",
ModelRole.Icon.int:"icon",
ModelRole.Color.int:"color",
ModelRole.MentionsCount.int:"mentionsCount",
ModelRole.UnviewedMessagesCount.int:"unviewedMessagesCount"
}.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.getId())
of ModelRole.Name:
result = newQVariant(item.getName())
of ModelRole.Image:
result = newQVariant(item.getImage())
of ModelRole.Icon:
result = newQVariant(item.getIcon())
of ModelRole.Color:
result = newQVariant(item.getColor())
of ModelRole.MentionsCount:
result = newQVariant(item.getMentionsCount())
of ModelRole.UnviewedMessagesCount:
result = newQVariant(item.getUnviewedMessagesCount())
proc addItem*(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()

View File

@ -0,0 +1,97 @@
import NimQml, Tables
import io_interface, view, controller, item
import ../../../app/boot/global_singleton
import chat_section/module as chat_section_module
import community_section/module as community_section_module
import ../../../app_service/service/community/service as community_service
export io_interface
type
Module*[T: io_interface.DelegateInterface] = ref object of io_interface.AccessInterface
delegate: T
view: View
viewVariant: QVariant
controller: controller.AccessInterface
chatSectionModule: chat_section_module.AccessInterface
communitySectionsModule: OrderedTable[string, community_section_module.AccessInterface]
#################################################
# Forward declaration section
# Controller Delegate Interface
# Chat Section Module Delegate Interface
proc chatSectionDidLoad*[T](self: Module[T])
# Community Section Module Delegate Interface
proc communitySectionDidLoad*[T](self: Module[T])
#################################################
proc newModule*[T](delegate: T,
communityService: community_service.Service):
Module[T] =
result = Module[T]()
result.delegate = delegate
result.view = view.newView(result)
result.viewVariant = newQVariant(result.view)
result.controller = controller.newController[Module[T]](result, communityService)
singletonInstance.engine.setRootContextProperty("mainModule", result.viewVariant)
# Submodules
result.chatSectionModule = chat_section_module.newModule[Module[T]](result)
result.communitySectionsModule = initOrderedTable[string, community_section_module.AccessInterface]()
let communities = result.controller.getCommunities()
for c in communities:
result.communitySectionsModule[c.id] = community_section_module.newModule[Module[T]](result,
c.id, communityService)
method delete*[T](self: Module[T]) =
self.chatSectionModule.delete
for cModule in self.communitySectionsModule.values:
cModule.delete
self.communitySectionsModule.clear
self.view.delete
self.viewVariant.delete
self.controller.delete
method load*[T](self: Module[T]) =
self.view.load()
let chatSectionItem = initItem("chat", "Chat", "", "chat", "", 0, 0)
self.view.addItem(chatSectionItem)
let communities = self.controller.getCommunities()
for c in communities:
self.view.addItem(initItem(c.id, c.name,
if not c.images.isNil: c.images.thumbnail else: "",
"", c.color, 0, 0))
self.chatSectionModule.load()
for cModule in self.communitySectionsModule.values:
cModule.load()
proc checkIfModuleDidLoad [T](self: Module[T]) =
if(not self.chatSectionModule.isLoaded()):
return
for cModule in self.communitySectionsModule.values:
if(not cModule.isLoaded()):
return
self.delegate.mainDidLoad()
proc chatSectionDidLoad*[T](self: Module[T]) =
self.checkIfModuleDidLoad()
proc communitySectionDidLoad*[T](self: Module[T]) =
self.checkIfModuleDidLoad()
method viewDidLoad*[T](self: Module[T]) =
discard

View File

@ -0,0 +1,38 @@
import NimQml
import model, item
import io_interface
QtObject:
type
View* = ref object of QObject
delegate: io_interface.AccessInterface
model: Model
modelVariant: QVariant
proc delete*(self: View) =
self.model.delete
self.modelVariant.delete
self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface): View =
new(result, delete)
result.QObject.setup
result.delegate = delegate
result.model = newModel()
result.modelVariant = newQVariant(result.model)
proc load*(self: View) =
# In some point, here, we will setup some exposed main module related things.
self.delegate.viewDidLoad()
proc addItem*(self: View, item: Item) =
self.model.addItem(item)
proc modelChanged*(self: View) {.signal.}
proc getModel(self: View): QVariant {.slot.} =
return self.modelVariant
QtProperty[QVariant] sectionsModel:
read = getModel
notify = modelChanged

View File

@ -0,0 +1,22 @@
import Tables
import controller_interface
export controller_interface
type
Controller*[T: controller_interface.DelegateInterface] =
ref object of controller_interface.AccessInterface
delegate: T
proc newController*[T](delegate: T):
Controller[T] =
result = Controller[T]()
result.delegate = delegate
method delete*[T](self: Controller[T]) =
discard
method init*[T](self: Controller[T]) =
discard

View File

@ -0,0 +1,16 @@
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")
type
## Abstract class (concept) which must be implemented by object/s used in this
## module.
DelegateInterface* = concept c

View File

@ -0,0 +1,22 @@
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")
# 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")
type
## Abstract class (concept) which must be implemented by object/s used in this
## module.
DelegateInterface* = concept c
c.startupDidLoad()

View File

@ -0,0 +1,53 @@
import json, strformat
type
Item* = object
id: string
name: string
image: string
icon: string
color: string
mentionsCount: int
unviewedMessagesCount: int
proc initItem*(id, name, image, icon, color: string,
mentionsCount, unviewedMessagesCount: int): Item =
result.id = id
result.name = name
result.image = image
result.icon = icon
result.color = color
result.mentionsCount = mentionsCount
result.unviewedMessagesCount = unviewedMessagesCount
proc `$`*(self: Item): string =
result = fmt"""MainModuleItem(
id: {self.id},
name: {self.name},
image: {self.image},
icon: {self.icon},
color: {self.color},
mentionsCount: {self.mentionsCount},
unviewedMessagesCount:{self.unviewedMessagesCount}
]"""
proc getId*(self: Item): string =
return self.id
proc getName*(self: Item): string =
return self.name
proc getImage*(self: Item): string =
return self.image
proc getIcon*(self: Item): string =
return self.icon
proc getColor*(self: Item): string =
return self.color
proc getMentionsCount*(self: Item): int =
return self.mentionsCount
proc getUnviewedMessagesCount*(self: Item): int =
return self.unviewedMessagesCount

View File

@ -0,0 +1,24 @@
import Tables
import controller_interface
#import ../../../../app_service/service/community/service as community_service
export controller_interface
type
Controller*[T: controller_interface.DelegateInterface] =
ref object of controller_interface.AccessInterface
delegate: T
#communityService: community_service.ServiceInterface
proc newController*[T](delegate: T):
Controller[T] =
result = Controller[T]()
result.delegate = delegate
method delete*[T](self: Controller[T]) =
discard
method init*[T](self: Controller[T]) =
discard

View File

@ -0,0 +1,18 @@
#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")
type
## Abstract class (concept) which must be implemented by object/s used in this
## module.
DelegateInterface* = concept c

View File

@ -0,0 +1,24 @@
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")
# 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")
type
## Abstract class (concept) which must be implemented by object/s used in this
## module.
DelegateInterface* = concept c
c.loginDidLoad()

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,38 @@
import NimQml
import io_interface, view, controller
#import ../../../../app_service/service/community/service as community_service
export io_interface
type
Module* [T: io_interface.DelegateInterface] = ref object of io_interface.AccessInterface
delegate: T
view: View
viewVariant: QVariant
controller: controller.AccessInterface
moduleLoaded: bool
proc newModule*[T](delegate: T):
Module[T] =
result = Module[T]()
result.delegate = delegate
result.view = view.newView(result)
result.viewVariant = newQVariant(result.view)
result.controller = controller.newController[Module[T]](result)
result.moduleLoaded = false
method delete*[T](self: Module[T]) =
self.view.delete
self.viewVariant.delete
self.controller.delete
method load*[T](self: Module[T]) =
self.moduleLoaded = true
self.delegate.loginDidLoad()
method isLoaded*[T](self: Module[T]): bool =
return self.moduleLoaded
method viewDidLoad*(self: Module) =
discard

View File

@ -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()

View File

@ -0,0 +1,94 @@
import NimQml, Tables, strutils, strformat
import item
type
ModelRole {.pure.} = enum
Id = UserRole + 1
Name
Image
Icon
Color
MentionsCount
UnviewedMessagesCount
QtObject:
type
Model* = ref object of QAbstractListModel
items: seq[Item]
proc delete(self: Model) =
self.items = @[]
self.QAbstractListModel.delete
proc setup(self: Model) =
self.QAbstractListModel.setup
proc newModel*(): Model =
new(result, delete)
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.Image.int:"image",
ModelRole.Icon.int:"icon",
ModelRole.Color.int:"color",
ModelRole.MentionsCount.int:"mentionsCount",
ModelRole.UnviewedMessagesCount.int:"unviewedMessagesCount"
}.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.getId())
of ModelRole.Name:
result = newQVariant(item.getName())
of ModelRole.Image:
result = newQVariant(item.getImage())
of ModelRole.Icon:
result = newQVariant(item.getIcon())
of ModelRole.Color:
result = newQVariant(item.getColor())
of ModelRole.MentionsCount:
result = newQVariant(item.getMentionsCount())
of ModelRole.UnviewedMessagesCount:
result = newQVariant(item.getUnviewedMessagesCount())
proc addItem*(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()

View File

@ -0,0 +1,76 @@
import NimQml
import io_interface, view, controller
import ../../../app/boot/global_singleton
import onboarding/module as onboarding_module
import login/module as login_module
#import ../../../app_service/service/community/service as community_service
export io_interface
type
Module*[T: io_interface.DelegateInterface] = ref object of io_interface.AccessInterface
delegate: T
view: View
viewVariant: QVariant
controller: controller.AccessInterface
onboardingModule: onboarding_module.AccessInterface
loginModule: login_module.AccessInterface
#################################################
# Forward declaration section
# Controller Delegate Interface
# Onboarding Module Delegate Interface
proc onboardingDidLoad*[T](self: Module[T])
# Login Module Delegate Interface
proc loginDidLoad*[T](self: Module[T])
#################################################
proc newModule*[T](delegate: T):
Module[T] =
result = Module[T]()
result.delegate = delegate
result.view = view.newView(result)
result.viewVariant = newQVariant(result.view)
result.controller = controller.newController[Module[T]](result)
singletonInstance.engine.setRootContextProperty("startupModule", result.viewVariant)
# Submodules
result.onboardingModule = onboarding_module.newModule[Module[T]](result)
result.loginModule = login_module.newModule[Module[T]](result)
method delete*[T](self: Module[T]) =
self.onboardingModule.delete
self.loginModule.delete
self.view.delete
self.viewVariant.delete
self.controller.delete
method load*[T](self: Module[T]) =
self.view.load()
method viewDidLoad*[T](self: Module[T]) =
discard
proc checkIfModuleDidLoad[T](self: Module[T]) =
if(not self.onboardingModule.isLoaded()):
return
if(not self.loginModule.isLoaded()):
return
self.delegate.startupDidLoad()
proc onboardingDidLoad*[T](self: Module[T]) =
self.checkIfModuleDidLoad()
proc loginDidLoad*[T](self: Module[T]) =
self.checkIfModuleDidLoad()

View File

@ -0,0 +1,24 @@
import Tables
import controller_interface
#import ../../../../app_service/service/community/service as community_service
export controller_interface
type
Controller*[T: controller_interface.DelegateInterface] =
ref object of controller_interface.AccessInterface
delegate: T
#communityService: community_service.ServiceInterface
proc newController*[T](delegate: T):
Controller[T] =
result = Controller[T]()
result.delegate = delegate
method delete*[T](self: Controller[T]) =
discard
method init*[T](self: Controller[T]) =
discard

View File

@ -0,0 +1,18 @@
#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")
type
## Abstract class (concept) which must be implemented by object/s used in this
## module.
DelegateInterface* = concept c

View File

@ -0,0 +1,24 @@
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")
# 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")
type
## Abstract class (concept) which must be implemented by object/s used in this
## module.
DelegateInterface* = concept c
c.onboardingDidLoad()

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,38 @@
import NimQml
import io_interface, view, controller
#import ../../../../app_service/service/community/service as community_service
export io_interface
type
Module* [T: io_interface.DelegateInterface] = ref object of io_interface.AccessInterface
delegate: T
view: View
viewVariant: QVariant
controller: controller.AccessInterface
moduleLoaded: bool
proc newModule*[T](delegate: T):
Module[T] =
result = Module[T]()
result.delegate = delegate
result.view = view.newView(result)
result.viewVariant = newQVariant(result.view)
result.controller = controller.newController[Module[T]](result)
result.moduleLoaded = false
method delete*[T](self: Module[T]) =
self.view.delete
self.viewVariant.delete
self.controller.delete
method load*[T](self: Module[T]) =
self.moduleLoaded = true
self.delegate.onboardingDidLoad()
method isLoaded*[T](self: Module[T]): bool =
return self.moduleLoaded
method viewDidLoad*(self: Module) =
discard

View File

@ -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()

View File

@ -0,0 +1,26 @@
import NimQml
import model, item
import io_interface
QtObject:
type
View* = ref object of QObject
delegate: io_interface.AccessInterface
model: Model
modelVariant: QVariant
proc delete*(self: View) =
self.model.delete
self.modelVariant.delete
self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface): View =
new(result, delete)
result.QObject.setup
result.delegate = delegate
result.model = newModel()
result.modelVariant = newQVariant(result.model)
proc load*(self: View) =
# In some point, here, we will setup some exposed main module related things.
self.delegate.viewDidLoad()

View File

@ -0,0 +1,49 @@
import json
template getProp(obj: JsonNode, prop: string, value: var typedesc[int]): bool =
var success = false
if (obj.kind == JObject and obj.contains(prop)):
value = obj[prop].getInt
success = true
success
template getProp(obj: JsonNode, prop: string, value: var typedesc[int64]): bool =
var success = false
if (obj.kind == JObject and obj.contains(prop)):
value = obj[prop].getBiggestInt
success = true
success
template getProp(obj: JsonNode, prop: string, value: var typedesc[string]): bool =
var success = false
if (obj.kind == JObject and obj.contains(prop)):
value = obj[prop].getStr
success = true
success
template getProp(obj: JsonNode, prop: string, value: var typedesc[float]): bool =
var success = false
if (obj.kind == JObject and obj.contains(prop)):
value = obj[prop].getFloat
success = true
success
template getProp(obj: JsonNode, prop: string, value: var typedesc[bool]): bool =
var success = false
if (obj.kind == JObject and obj.contains(prop)):
value = obj[prop].getBool
success = true
success
template getProp(obj: JsonNode, prop: string, value: var typedesc[JsonNode]): bool =
var success = false
if (obj.kind == JObject and obj.contains(prop)):
value = obj[prop]
success = true
success

View File

@ -0,0 +1,95 @@
{.used.}
import json, strformat
include ../../common/json_utils
type ChatType* {.pure.}= enum
Unknown = 0,
OneToOne = 1,
Public = 2,
PrivateGroupChat = 3,
Profile = 4,
Timeline = 5
CommunityChat = 6
type Dto* = ref object
id*: string # ID is the id of the chat, for public chats it is the name e.g. status,
# for one-to-one is the hex encoded public key and for group chats is a random
# uuid appended with the hex encoded pk of the creator of the chat
name*: string
description*: string
color*: string
emoji*: string # not sure why do we receive this at all?
active*: bool # indicates whether the chat has been soft deleted
chatType*: ChatType
timestamp*: int64 # indicates the last time this chat has received/sent a message
lastClockValue*: int64 # indicates the last clock value to be used when sending messages
deletedAtClockValue*: int64 # indicates the clock value at time of deletion,
# messages with lower clock value of this should be discarded
unviewedMessagesCount*: int
unviewedMentionsCount*: int
#lastMessage*: Message ???? It's a question why do we need it here within this context ????
#members*: seq[ChatMember] ???? It's always null and a question why do we need it here within this context ????
#membershipUpdateEvents*: seq[ChatMembershipEvent] ???? It's always null and a question why do we need it here within this context ????
alias*: string
identicon*: string
muted*: bool
communityId*: string #set if chat belongs to a community
profile*: string
joined*: int64 # indicates when the user joined the chat last time
syncedTo*: int64
syncedFrom*: int64
proc `$`*(self: Dto): string =
result = fmt"""ChatDto(
id: {self.id},
name: {self.name},
description: {self.description},
color: {self.color},
emoji: {self.emoji},
active: {self.active},
chatType: {self.chatType},
timestamp: {self.timestamp},
lastClockValue: {self.lastClockValue},
deletedAtClockValue: {self.deletedAtClockValue},
unviewedMessagesCount: {self.unviewedMessagesCount},
unviewedMentionsCount: {self.unviewedMentionsCount},
alias: {self.alias},
identicon: {self.identicon},
muted: {self.muted},
communityId: {self.communityId},
profile: {self.profile},
joined: {self.joined},
syncedTo: {self.syncedTo},
syncedFrom: {self.syncedFrom}
)"""
proc toDto*(jsonObj: JsonNode): Dto =
result = Dto()
discard jsonObj.getProp("id", result.id)
discard jsonObj.getProp("name", result.name)
discard jsonObj.getProp("description", result.description)
discard jsonObj.getProp("color", result.color)
discard jsonObj.getProp("emoji", result.emoji)
discard jsonObj.getProp("active", result.active)
result.chatType = ChatType.Unknown
var chatTypeInt: int
if (jsonObj.getProp("chatType", chatTypeInt) and
(chatTypeInt >= ord(low(ChatType)) or chatTypeInt <= ord(high(ChatType)))):
result.chatType = ChatType(chatTypeInt)
discard jsonObj.getProp("timestamp", result.timestamp)
discard jsonObj.getProp("lastClockValue", result.lastClockValue)
discard jsonObj.getProp("deletedAtClockValue", result.deletedAtClockValue)
discard jsonObj.getProp("unviewedMessagesCount", result.unviewedMessagesCount)
discard jsonObj.getProp("unviewedMentionsCount", result.unviewedMentionsCount)
discard jsonObj.getProp("alias", result.alias)
discard jsonObj.getProp("identicon", result.identicon)
discard jsonObj.getProp("muted", result.muted)
discard jsonObj.getProp("communityId", result.communityId)
discard jsonObj.getProp("profile", result.profile)
discard jsonObj.getProp("joined", result.joined)
discard jsonObj.getProp("syncedTo", result.syncedTo)
discard jsonObj.getProp("syncedFrom", result.syncedFrom)

View File

@ -0,0 +1,36 @@
import Tables, json, sequtils, strformat, chronicles
import service_interface, dto
import status/statusgo_backend_new/chat as status_go
export service_interface
logScope:
topics = "chat-service"
type
Service* = ref object of ServiceInterface
chats: Table[string, Dto] # [chat_id, Dto]
method delete*(self: Service) =
discard
proc newService*(): Service =
result = Service()
result.chats = initTable[string, Dto]()
method init*(self: Service) =
try:
let response = status_go.getChats()
let chats = map(response.result.getElems(),
proc(x: JsonNode): Dto = x.toDto())
for chat in chats:
if chat.active and chat.chatType != ChatType.Unknown:
self.chats[chat.id] = chat
except Exception as e:
let errDesription = e.msg
error "error: ", errDesription
return

View File

@ -0,0 +1,13 @@
import dto
export dto
type
ServiceInterface* {.pure inheritable.} = ref object of RootObj
## Abstract class for this service access.
method delete*(self: ServiceInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method init*(self: ServiceInterface) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -0,0 +1,142 @@
{.used.}
import json, strformat
include ../../common/json_utils
type
Permission* = ref object
access*: int
type
Images* = ref object
thumbnail*: string
large*: string
type Chat* = ref object
id*: string
name*: string
color*: string
emoji*: string
description*: string
#members*: seq[ChatMember] ???? It's always null and a question why do we need it here within this context ????
permissions*: Permission
canPost*: bool
position*: int
categoryId*: string
type Category* = ref object
id*: string
name*: string
position*: int
type Member* = ref object
id*: string
roles*: seq[int]
type Dto* = ref object
id*: string
admin*: bool
verified*: bool
joined*: bool
requestedAccessAt: int64
name*: string
description*: string
chats*: seq[Chat]
categories*: seq[Category]
images*: Images
permissions*: Permission
members*: seq[Member]
canRequestAccess*: bool
canManageUsers*: bool
canJoin*: bool
color*: string
requestedToJoinAt*: int64
isMember*: bool
muted*: bool
proc toPermission(jsonObj: JsonNode): Permission =
result = Permission()
discard jsonObj.getProp("access", result.access)
proc toImages(jsonObj: JsonNode): Images =
result = Images()
var largeObj: JsonNode
if(jsonObj.getProp("large", largeObj)):
discard largeObj.getProp("uri", result.large)
var thumbnailObj: JsonNode
if(jsonObj.getProp("thumbnail", thumbnailObj)):
discard thumbnailObj.getProp("uri", result.thumbnail)
proc toChat(jsonObj: JsonNode): Chat =
result = Chat()
discard jsonObj.getProp("id", result.id)
discard jsonObj.getProp("name", result.name)
discard jsonObj.getProp("color", result.color)
discard jsonObj.getProp("emoji", result.emoji)
discard jsonObj.getProp("description", result.description)
var permissionObj: JsonNode
if(jsonObj.getProp("permissions", permissionObj)):
result.permissions = toPermission(permissionObj)
discard jsonObj.getProp("canPost", result.canPost)
discard jsonObj.getProp("position", result.position)
discard jsonObj.getProp("categoryId", result.categoryId)
proc toCategory(jsonObj: JsonNode): Category =
result = Category()
discard jsonObj.getProp("id", result.id)
discard jsonObj.getProp("name", result.name)
discard jsonObj.getProp("position", result.position)
proc toMember(jsonObj: JsonNode, memberId: string): Member =
# Mapping this DTO is not strightforward since only keys are used for id. We
# handle it a bit different.
result = Member()
result.id = memberId
var rolesObj: JsonNode
if(jsonObj.getProp("roles", rolesObj)):
for roleObj in rolesObj:
result.roles.add(roleObj.getInt)
proc toDto*(jsonObj: JsonNode): Dto =
result = Dto()
discard jsonObj.getProp("id", result.id)
discard jsonObj.getProp("admin", result.admin)
discard jsonObj.getProp("verified", result.verified)
discard jsonObj.getProp("joined", result.joined)
discard jsonObj.getProp("requestedAccessAt", result.requestedAccessAt)
discard jsonObj.getProp("name", result.name)
discard jsonObj.getProp("description", result.description)
var chatsObj: JsonNode
if(jsonObj.getProp("chats", chatsObj)):
for _, chatObj in chatsObj:
result.chats.add(toChat(chatObj))
var categoriesObj: JsonNode
if(jsonObj.getProp("categories", categoriesObj)):
for _, categoryObj in categoriesObj:
result.categories.add(toCategory(categoryObj))
var imagesObj: JsonNode
if(jsonObj.getProp("images", imagesObj)):
result.images = toImages(imagesObj)
var permissionObj: JsonNode
if(jsonObj.getProp("permissions", permissionObj)):
result.permissions = toPermission(permissionObj)
var membersObj: JsonNode
if(jsonObj.getProp("members", membersObj)):
for memberId, memberObj in membersObj:
result.members.add(toMember(memberObj, memberId))
discard jsonObj.getProp("canRequestAccess", result.canRequestAccess)
discard jsonObj.getProp("canManageUsers", result.canManageUsers)
discard jsonObj.getProp("canJoin", result.canJoin)
discard jsonObj.getProp("color", result.color)
discard jsonObj.getProp("requestedToJoinAt", result.requestedToJoinAt)
discard jsonObj.getProp("isMember", result.isMember)
discard jsonObj.getProp("muted", result.muted)

View File

@ -0,0 +1,38 @@
import Tables, json, sequtils, strformat, chronicles
import service_interface, dto
import status/statusgo_backend_new/communities as status_go
export service_interface
logScope:
topics = "community-service"
type
Service* = ref object of ServiceInterface
communities: Table[string, Dto] # [community_id, Dto]
method delete*(self: Service) =
discard
proc newService*(): Service =
result = Service()
result.communities = initTable[string, Dto]()
method init*(self: Service) =
try:
let response = status_go.getJoinedComunities()
let communities = map(response.result.getElems(),
proc(x: JsonNode): Dto = x.toDto())
for community in communities:
self.communities[community.id] = community
except Exception as e:
let errDesription = e.msg
error "error: ", errDesription
return
method getCommunities*(self: Service): seq[Dto] =
return toSeq(self.communities.values)

View File

@ -0,0 +1,16 @@
import dto
export dto
type
ServiceInterface* {.pure inheritable.} = ref object of RootObj
## Abstract class for this service access.
method delete*(self: ServiceInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method init*(self: ServiceInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method getCommunities*(self: ServiceInterface): seq[Dto] {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -0,0 +1,78 @@
{.used.}
import json, strformat
include ../../common/json_utils
type
Images* = ref object
thumbnail*: string
large*: string
type Dto* = ref object
id*: string
name*: string
ensVerified*: bool
alias: string
identicon*: string
lastUpdated*: int64
image*: Images
added*: bool
blocked*: bool
hasAddedUs*: bool
isSyncing*: bool
removed: bool
proc `$`(self: Images): string =
result = fmt"""Images(
thumbnail: {self.thumbnail},
large: {self.large},
]"""
proc `$`*(self: Dto): string =
result = fmt"""ContactDto(
id: {self.id},
name: {self.name},
ensVerified: {self.ensVerified},
alias: {self.alias},
identicon: {self.identicon},
lastUpdated: {self.lastUpdated},
image:[
{$self.image}
],
added:{self.added}
blocked:{self.blocked}
hasAddedUs:{self.hasAddedUs}
isSyncing:{self.isSyncing}
removed:{self.removed}
)"""
proc toImages(jsonObj: JsonNode): Images =
result = Images()
var largeObj: JsonNode
if(jsonObj.getProp("large", largeObj)):
discard jsonObj.getProp("uri", result.large)
var thumbnailObj: JsonNode
if(jsonObj.getProp("thumbnail", thumbnailObj)):
discard jsonObj.getProp("uri", result.thumbnail)
proc toDto*(jsonObj: JsonNode): Dto =
result = Dto()
discard jsonObj.getProp("id", result.id)
discard jsonObj.getProp("name", result.name)
discard jsonObj.getProp("ensVerified", result.ensVerified)
discard jsonObj.getProp("alias", result.alias)
discard jsonObj.getProp("identicon", result.identicon)
discard jsonObj.getProp("lastUpdated", result.lastUpdated)
var imageObj: JsonNode
if(jsonObj.getProp("images", imageObj)):
result.image = toImages(imageObj)
discard jsonObj.getProp("added", result.added)
discard jsonObj.getProp("blocked", result.blocked)
discard jsonObj.getProp("hasAddedUs", result.hasAddedUs)
discard jsonObj.getProp("IsSyncing", result.isSyncing)
discard jsonObj.getProp("Removed", result.removed)

View File

@ -0,0 +1,35 @@
import Tables, json, sequtils, strformat, chronicles
import service_interface, dto
import status/statusgo_backend_new/contacts as status_go
export service_interface
logScope:
topics = "contacts-service"
type
Service* = ref object of ServiceInterface
contacts: Table[string, Dto] # [contact_id, Dto]
method delete*(self: Service) =
discard
proc newService*(): Service =
result = Service()
result.contacts = initTable[string, Dto]()
method init*(self: Service) =
try:
let response = status_go.getContacts()
let contacts = map(response.result.getElems(),
proc(x: JsonNode): Dto = x.toDto())
for contact in contacts:
self.contacts[contact.id] = contact
except Exception as e:
let errDesription = e.msg
error "error: ", errDesription
return

View File

@ -0,0 +1,13 @@
import dto
export dto
type
ServiceInterface* {.pure inheritable.} = ref object of RootObj
## Abstract class for this service access.
method delete*(self: ServiceInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method init*(self: ServiceInterface) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -8,8 +8,6 @@ import app/utilsView/core as utilsView
import app/browser/core as browserView
import app/profile/core as profile
import app/profile/view
import app/onboarding/core as onboarding
import app/login/core as login
import app/provider/core as provider
import app/keycard/core as keycard
import status/types/[account]
@ -21,6 +19,10 @@ import app_service/tasks/marathon/mailserver/worker as mailserver_worker
import app_service/main
import constants
import app/boot/global_singleton
import app/boot/app_controller
var signalsQObjPointer: pointer
logScope:
@ -58,6 +60,9 @@ proc mainProc() =
let app = newQGuiApplication()
defer: app.delete()
let appController = newAppController(status, appService)
defer: appController.delete()
let resources =
if defined(windows) and defined(production):
"/../resources/resources.rcc"
@ -103,22 +108,23 @@ proc mainProc() =
let networkAccessFactory = newQNetworkAccessManagerFactory(TMPDIR & "netcache")
let engine = newQQmlApplicationEngine()
defer: engine.delete()
engine.addImportPath("qrc:/./StatusQ/src")
engine.addImportPath("qrc:/./imports")
engine.setNetworkAccessManagerFactory(networkAccessFactory)
engine.setRootContextProperty("uiScaleFilePath", newQVariant(uiScaleFilePath))
#let engine = newQQmlApplicationEngine()
#defer: engine.delete()
singletonInstance.engine.addImportPath("qrc:/./StatusQ/src")
singletonInstance.engine.addImportPath("qrc:/./imports")
singletonInstance.engine.setNetworkAccessManagerFactory(networkAccessFactory)
singletonInstance.engine.setRootContextProperty("uiScaleFilePath", newQVariant(uiScaleFilePath))
# Register events objects
let dockShowAppEvent = newStatusDockShowAppEventObject(engine)
let dockShowAppEvent = newStatusDockShowAppEventObject(singletonInstance.engine)
defer: dockShowAppEvent.delete()
let osThemeEvent = newStatusOSThemeEventObject(engine)
let osThemeEvent = newStatusOSThemeEventObject(singletonInstance.engine)
defer: osThemeEvent.delete()
app.installEventFilter(dockShowAppEvent)
app.installEventFilter(osThemeEvent)
let netAccMgr = newQNetworkAccessManager(engine.getNetworkAccessManager())
let netAccMgr = newQNetworkAccessManager(singletonInstance.engine.getNetworkAccessManager())
status.events.on("network:connected") do(e: Args):
# This is a workaround for Qt bug https://bugreports.qt.io/browse/QTBUG-55180
@ -152,47 +158,43 @@ proc mainProc() =
var wallet = wallet.newController(status, appService)
defer: wallet.delete()
engine.setRootContextProperty("walletModel", wallet.variant)
singletonInstance.engine.setRootContextProperty("walletModel", wallet.variant)
var wallet2 = walletV2.newController(status, appService)
defer: wallet2.delete()
engine.setRootContextProperty("walletV2Model", wallet2.variant)
singletonInstance.engine.setRootContextProperty("walletV2Model", wallet2.variant)
var chat = chat.newController(status, appService, OPENURI)
defer: chat.delete()
engine.setRootContextProperty("chatsModel", chat.variant)
singletonInstance.engine.setRootContextProperty("chatsModel", chat.variant)
var node = node.newController(status, appService, netAccMgr)
defer: node.delete()
engine.setRootContextProperty("nodeModel", node.variant)
singletonInstance.engine.setRootContextProperty("nodeModel", node.variant)
var utilsController = utilsView.newController(status, appService)
defer: utilsController.delete()
engine.setRootContextProperty("utilsModel", utilsController.variant)
singletonInstance.engine.setRootContextProperty("utilsModel", utilsController.variant)
var browserController = browserView.newController(status)
defer: browserController.delete()
engine.setRootContextProperty("browserModel", browserController.variant)
singletonInstance.engine.setRootContextProperty("browserModel", browserController.variant)
proc changeLanguage(locale: string) =
if (locale == currentLanguageCode):
return
currentLanguageCode = locale
let shouldRetranslate = not defined(linux)
engine.setTranslationPackage(joinPath(i18nPath, fmt"qml_{locale}.qm"), shouldRetranslate)
singletonInstance.engine.setTranslationPackage(joinPath(i18nPath, fmt"qml_{locale}.qm"), shouldRetranslate)
var profile = profile.newController(status, appService, changeLanguage)
defer: profile.delete()
engine.setRootContextProperty("profileModel", profile.variant)
singletonInstance.engine.setRootContextProperty("profileModel", profile.variant)
var provider = provider.newController(status)
defer: provider.delete()
engine.setRootContextProperty("web3Provider", provider.variant)
singletonInstance.engine.setRootContextProperty("web3Provider", provider.variant)
var login = login.newController(status, appService)
defer: login.delete()
var onboarding = onboarding.newController(status)
defer: onboarding.delete()
var keycard = keycard.newController(status)
defer: keycard.delete()
@ -203,18 +205,6 @@ proc mainProc() =
var args = AccountArgs(a)
onAccountChanged(args.account)
status.events.once("login") do(a: Args):
var args = AccountArgs(a)
appService.onLoggedIn()
# Reset login and onboarding to remove any mnemonic that would have been saved in the accounts list
login.reset()
onboarding.reset()
login.moveToAppState()
onboarding.moveToAppState()
status.events.emit("loginCompleted", args)
status.events.once("loginCompleted") do(a: Args):
var args = AccountArgs(a)
@ -234,33 +224,30 @@ proc mainProc() =
# this should be the last defer in the scope
defer:
info "Status app is shutting down..."
singletonInstance.delete()
engine.setRootContextProperty("loginModel", login.variant)
engine.setRootContextProperty("onboardingModel", onboarding.variant)
engine.setRootContextProperty("keycardModel", keycard.variant)
engine.setRootContextProperty("singleInstance", newQVariant(singleInstance))
singletonInstance.engine.setRootContextProperty("keycardModel", keycard.variant)
singletonInstance.engine.setRootContextProperty("singleInstance", newQVariant(singleInstance))
let isExperimental = if getEnv("EXPERIMENTAL") == "1": "1" else: "0" # value explicity passed to avoid trusting input
let experimentalFlag = newQVariant(isExperimental)
engine.setRootContextProperty("isExperimental", experimentalFlag)
singletonInstance.engine.setRootContextProperty("isExperimental", experimentalFlag)
# Initialize only controllers whose init functions
# do not need a running node
proc initControllers() =
login.init()
onboarding.init()
keycard.init()
initControllers()
appController.start()
# Handle node.stopped signal when user has logged out
status.events.once("nodeStopped") do(a: Args):
# TODO: remove this once accounts are not tracked in the AccountsModel
status.reset()
# 1. Reset controller data
login.reset()
onboarding.reset()
# TODO: implement all controller resets
# chat.reset()
# node.reset()
@ -271,18 +258,18 @@ proc mainProc() =
# 2. Re-init controllers that don't require a running node
initControllers()
engine.setRootContextProperty("signals", appService.signalController.variant)
engine.setRootContextProperty("mailserver", mailserverController.variant)
singletonInstance.engine.setRootContextProperty("signals", appService.signalController.variant)
singletonInstance.engine.setRootContextProperty("mailserver", mailserverController.variant)
var prValue = newQVariant(if defined(production): true else: false)
engine.setRootContextProperty("production", prValue)
singletonInstance.engine.setRootContextProperty("production", prValue)
# We're applying default language before we load qml. Also we're aware that
# switch language at runtime will have some impact to cpu usage.
# https://doc.qt.io/archives/qtjambi-4.5.2_01/com/trolltech/qt/qtjambi-linguist-programmers.html
changeLanguage("en")
engine.load(newQUrl("qrc:///main.qml"))
singletonInstance.engine.load(newQUrl("qrc:///main.qml"))
# Please note that this must use the `cdecl` calling convention because
# it will be passed as a regular C function to statusgo_backend. This means that

View File

@ -164,15 +164,24 @@ StatusAppThreePanelLayout {
sourceComponent: appSettings.communitiesEnabled && root.rootStore.chatsModelInst.communities.activeCommunity.active ? communtiyColumnComponent : contactsColumnComponent
}
centerPanel: ChatColumnView {
// centerPanel: ChatColumn {
// id: chatColumn
// chatGroupsListViewCount: contactColumnLoader.item.chatGroupsListViewCount
// }
centerPanel: Rectangle {
id: chatColumn
rootStore: root.rootStore
chatGroupsListViewCount: contactColumnLoader.item.chatGroupsListViewCount
anchors.fill: parent
color: "green"
}
showRightPanel: (appSettings.expandUsersList && (appSettings.showOnlineUsers || root.rootStore.chatsModelInst.communities.activeCommunity.active)
&& (root.rootStore.chatsModelInst.channelView.activeChannel.chatType !== Constants.chatTypeOneToOne))
rightPanel: appSettings.communitiesEnabled && root.rootStore.chatsModelInst.communities.activeCommunity.active ? communityUserListComponent : userListComponent
showRightPanel: (appSettings.expandUsersList && (appSettings.showOnlineUsers || chatsModel.communities.activeCommunity.active)
&& (chatsModel.channelView.activeChannel.chatType !== Constants.chatTypeOneToOne))
//rightPanel: appSettings.communitiesEnabled && chatsModel.communities.activeCommunity.active ? communityUserListComponent : userListComponent
rightPanel: Rectangle {
anchors.fill: parent
color: "blue"
}
Component {
id: communityUserListComponent

View File

@ -213,7 +213,7 @@ Item {
}
}
navBarCommunityTabButtons.model: appSettings.communitiesEnabled && chatsModel.communities.joinedCommunities
navBarCommunityTabButtons.model: appSettings.communitiesEnabled && mainModule.sectionsModel
navBarCommunityTabButtons.delegate: StatusNavBarTabButton {
onClicked: {
appMain.changeAppSection(Constants.chat)
@ -226,8 +226,9 @@ Item {
checked: chatsModel.communities.activeCommunity.active && chatsModel.communities.activeCommunity.id === model.id
name: model.name
tooltip.text: model.name
icon.color: model.communityColor
icon.source: model.thumbnailImage
icon.color: model.color
icon.source: model.image.length > 0? model.image : model.icon
icon.name: model.icon
badge.value: model.unviewedMentionsCount + model.requestsCount
badge.visible: badge.value > 0 || (!checked && model.unviewedMessagesCount > 0)

2
vendor/status-lib vendored

@ -1 +1 @@
Subproject commit 72a32ee72549e44d14d28a430a75a09078efc7e3
Subproject commit c8b721994b91dccdc7ab6d4b03c90e48730aa682