Skip to content

Commit

Permalink
chore(onboarding): add scaffolding for the new onboarding (#16980)
Browse files Browse the repository at this point in the history
Part of #16832

Adds the basic files needed for the new onboarding, aka onboarding V2.
It does not do anything yet, but it's ready to be implemented.

It is locked behind a feature flag.
To enable it,  run the app with `export FLAG_ONBOARDING_V2_ENABLED=1`
  • Loading branch information
jrainville authored Dec 19, 2024
1 parent 8aebb81 commit 3dd5fa9
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 1 deletion.
24 changes: 23 additions & 1 deletion src/app/boot/app_controller.nim
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ import app_service/service/metrics/service as metrics_service

import app/modules/shared_modules/keycard_popup/module as keycard_shared_module
import app/modules/startup/module as startup_module
import app/modules/onboarding/module as onboarding_module
import app/modules/main/module as main_module
import app/core/notifications/notifications_manager
import app/global/global_singleton
import app/global/[global_singleton, feature_flags]
import app/global/app_signals
import app/core/[main]

Expand Down Expand Up @@ -105,6 +106,7 @@ type

# Modules
startupModule: startup_module.AccessInterface
onboardingModule: onboarding_module.AccessInterface
mainModule: main_module.AccessInterface

#################################################
Expand All @@ -116,6 +118,7 @@ proc applyNecessaryActionsAfterLoggingIn(self: AppController)

# Startup Module Delegate Interface
proc startupDidLoad*(self: AppController)
proc onboardingDidLoad*(self: AppController)
proc userLoggedIn*(self: AppController): string
proc appReady*(self: AppController)
proc logout*(self: AppController)
Expand Down Expand Up @@ -248,6 +251,11 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
result.keycardService,
result.devicesService
)
if singletonInstance.featureFlags().getOnboardingV2Enabled():
result.onboardingModule = onboarding_module.newModule[AppController](
result,
statusFoundation.events,
)
result.mainModule = main_module.newModule[AppController](
result,
statusFoundation.events,
Expand Down Expand Up @@ -304,6 +312,9 @@ proc delete*(self: AppController) =
if not self.startupModule.isNil:
self.startupModule.delete
self.startupModule = nil
if not self.onboardingModule.isNil:
self.onboardingModule.delete
self.onboardingModule = nil
self.mainModule.delete
self.languageService.delete

Expand Down Expand Up @@ -387,6 +398,7 @@ proc checkForStoringPasswordToKeychain(self: AppController) =
self.keychainService.storeData(account.keyUid, self.startupModule.getPin())

proc startupDidLoad*(self: AppController) =
# TODO move these functions to onboardingDidLoad
singletonInstance.engine.setRootContextProperty("localAppSettings", self.localAppSettingsVariant)
singletonInstance.engine.setRootContextProperty("localAccountSettings", self.localAccountSettingsVariant)
singletonInstance.engine.setRootContextProperty("globalUtils", self.globalUtilsVariant)
Expand All @@ -398,6 +410,10 @@ proc startupDidLoad*(self: AppController) =
# We need this to set app width/height appropriatelly on the app start.
self.startupModule.startUpUIRaised()

proc onboardingDidLoad*(self: AppController) =
debug "NEW ONBOARDING LOADED"
# TODO when removing the old startup module, we should move the functions above here

proc mainDidLoad*(self: AppController) =
self.applyNecessaryActionsAfterLoggingIn()
self.startupModule.moveToAppState()
Expand All @@ -411,6 +427,8 @@ proc start*(self: AppController) =
self.devicesService.init()

self.startupModule.load()
if singletonInstance.featureFlags().getOnboardingV2Enabled():
self.onboardingModule.load()

proc load(self: AppController) =
self.settingsService.init()
Expand Down Expand Up @@ -484,6 +502,10 @@ proc finishAppLoading*(self: AppController) =
self.startupModule.onAppLoaded()
self.startupModule = nil

if not self.onboardingModule.isNil:
self.onboardingModule.onAppLoaded()
self.onboardingModule = nil

self.mainModule.checkAndPerformProfileMigrationIfNeeded()

proc logout*(self: AppController) =
Expand Down
9 changes: 9 additions & 0 deletions src/app/global/feature_flags.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const DEFAULT_FLAG_CONNECTOR_ENABLED* = true
const DEFAULT_FLAG_SEND_VIA_PERSONAL_CHAT_ENABLED = true
const DEFAULT_FLAG_PAYMENT_REQUEST_ENABLED = true
const DEFAULT_FLAG_SIMPLE_SEND_ENABLED = false
const DEFAULT_FLAG_ONBOARDING_V2_ENABLED = false

proc boolToEnv*(defaultValue: bool): string =
return if defaultValue: "1" else: "0"
Expand All @@ -19,6 +20,7 @@ QtObject:
sendViaPersonalChatEnabled: bool
paymentRequestEnabled: bool
simpleSendEnabled: bool
onboardingV2Enabled: bool

proc setup(self: FeatureFlags) =
self.QObject.setup()
Expand All @@ -28,6 +30,7 @@ QtObject:
self.sendViaPersonalChatEnabled = getEnv("FLAG_SEND_VIA_PERSONAL_CHAT_ENABLED", boolToEnv(DEFAULT_FLAG_SEND_VIA_PERSONAL_CHAT_ENABLED)) != "0"
self.paymentRequestEnabled = getEnv("FLAG_PAYMENT_REQUEST_ENABLED", boolToEnv(DEFAULT_FLAG_PAYMENT_REQUEST_ENABLED)) != "0"
self.simpleSendEnabled = getEnv("FLAG_SIMPLE_SEND_ENABLED", boolToEnv(DEFAULT_FLAG_SIMPLE_SEND_ENABLED)) != "0"
self.onboardingV2Enabled = getEnv("FLAG_ONBOARDING_V2_ENABLED", boolToEnv(DEFAULT_FLAG_ONBOARDING_V2_ENABLED)) != "0"

proc delete*(self: FeatureFlags) =
self.QObject.delete()
Expand Down Expand Up @@ -71,3 +74,9 @@ QtObject:

QtProperty[bool] simpleSendEnabled:
read = getSimpleSendEnabled

proc getOnboardingV2Enabled*(self: FeatureFlags): bool {.slot.} =
return self.onboardingV2Enabled

QtProperty[bool] onboardingV2Enabled:
read = getOnboardingV2Enabled
24 changes: 24 additions & 0 deletions src/app/modules/onboarding/controller.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import chronicles
import io_interface

import app/core/eventemitter

logScope:
topics = "onboarding-controller"

type
Controller* = ref object of RootObj
delegate: io_interface.AccessInterface
events: EventEmitter

proc newController*(delegate: io_interface.AccessInterface, events: EventEmitter):
Controller =
result = Controller()
result.delegate = delegate
result.events = events

proc delete*(self: Controller) =
discard

proc init*(self: Controller) =
discard
16 changes: 16 additions & 0 deletions src/app/modules/onboarding/io_interface.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
type
AccessInterface* {.pure inheritable.} = ref object of RootObj

method delete*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")

method onAppLoaded*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")

method load*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")

# This way (using concepts) is used only for the modules managed by AppController
type
DelegateInterface* = concept c
c.onboardingDidLoad()
49 changes: 49 additions & 0 deletions src/app/modules/onboarding/module.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import NimQml, chronicles, json

import io_interface
import view, controller

import app/global/global_singleton
import app/core/eventemitter

export io_interface

logScope:
topics = "onboarding-module"

type
Module*[T: io_interface.DelegateInterface] = ref object of io_interface.AccessInterface
delegate: T
view: View
viewVariant: QVariant
controller: Controller

proc newModule*[T](delegate: T, events: EventEmitter): Module[T] =
result = Module[T]()
result.delegate = delegate
result.view = view.newView(result)
result.viewVariant = newQVariant(result.view)
result.controller = controller.newController(result, events)

{.push warning[Deprecated]: off.}

method delete*[T](self: Module[T]) =
self.view.delete
self.viewVariant.delete
self.controller.delete

method onAppLoaded*[T](self: Module[T]) =
singletonInstance.engine.setRootContextProperty("onboardingModule", newQVariant())
self.view.delete
self.view = nil
self.viewVariant.delete
self.viewVariant = nil
self.controller.delete
self.controller = nil

method load*[T](self: Module[T]) =
singletonInstance.engine.setRootContextProperty("onboardingModule", self.viewVariant)
self.controller.init()
self.delegate.onboardingDidLoad()

{.pop.}
15 changes: 15 additions & 0 deletions src/app/modules/onboarding/view.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import NimQml, json
import io_interface

QtObject:
type
View* = ref object of QObject
delegate: io_interface.AccessInterface

proc delete*(self: View) =
self.QObject.delete

proc newView*(delegate: io_interface.AccessInterface): View =
new(result, delete)
result.QObject.setup
result.delegate = delegate

0 comments on commit 3dd5fa9

Please sign in to comment.