From 577865617cc4bd5d2d4a71cd7a16d4ed88289ddd Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Wed, 20 Nov 2024 20:35:19 +0700 Subject: [PATCH] Remove domain models and use return values instead --- .../mobile/client/di/AndroidClientModule.kt | 16 ++- .../AndroidClientMainPresenter.kt | 22 ++++ .../android/node/di/AndroidNodeModule.kt | 10 +- .../NodeApplicationBootstrapFacade.kt | 28 ++--- .../NodeApplicationBootstrapModel.kt | 7 -- .../user_profile/NodeUserProfileModel.kt | 10 -- .../NodeUserProfileServiceFacade.kt | 112 ++++++++---------- .../node/presentation/NodeMainPresenter.kt | 2 - .../ClientApplicationBootstrapFacade.kt | 26 ++-- .../ClientApplicationBootstrapModel.kt | 7 -- .../user_profile/ClientUserProfileModel.kt | 11 -- .../ClientUserProfileServiceFacade.kt | 84 +++++++------ .../bootstrap/ApplicationBootstrapFacade.kt | 20 +++- .../bootstrap/ApplicationBootstrapModel.kt | 18 --- .../domain/data/repository/Repositories.kt | 3 - .../bisq/mobile/domain/di/DomainModule.kt | 2 - .../domain/user_profile/UserProfileModel.kt | 47 -------- .../user_profile/UserProfileServiceFacade.kt | 11 +- .../presentation/di/PresentationModule.kt | 8 +- .../uicases/startup/CreateProfilePresenter.kt | 78 +++++++----- .../ui/uicases/startup/CreateProfileScreen.kt | 5 +- .../ui/uicases/startup/SplashPresenter.kt | 42 +++---- .../ui/uicases/startup/SplashScreen.kt | 31 ++--- .../presentation/IosClientMainPresenter.kt | 21 ++++ .../mobile/presentation/di/IosClientModule.kt | 15 ++- 25 files changed, 284 insertions(+), 352 deletions(-) create mode 100644 bisqapps/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/presentation/AndroidClientMainPresenter.kt delete mode 100644 bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/bootstrap/NodeApplicationBootstrapModel.kt delete mode 100644 bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/user_profile/NodeUserProfileModel.kt delete mode 100644 bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/bootstrap/ClientApplicationBootstrapModel.kt delete mode 100644 bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/ClientUserProfileModel.kt delete mode 100644 bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/bootstrap/ApplicationBootstrapModel.kt delete mode 100644 bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/user_profile/UserProfileModel.kt create mode 100644 bisqapps/shared/presentation/src/iosMain/kotlin/network/bisq/mobile/presentation/IosClientMainPresenter.kt diff --git a/bisqapps/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/di/AndroidClientModule.kt b/bisqapps/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/di/AndroidClientModule.kt index 52c4122e..0cdb64b2 100644 --- a/bisqapps/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/di/AndroidClientModule.kt +++ b/bisqapps/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/di/AndroidClientModule.kt @@ -1,24 +1,22 @@ package network.bisq.mobile.client.di import network.bisq.mobile.android.node.main.bootstrap.ClientApplicationBootstrapFacade -import network.bisq.mobile.android.node.main.bootstrap.ClientApplicationBootstrapModel +import network.bisq.mobile.client.presentation.AndroidClientMainPresenter import network.bisq.mobile.client.service.ApiRequestService -import network.bisq.mobile.domain.client.main.user_profile.ClientUserProfileModel import network.bisq.mobile.domain.client.main.user_profile.ClientUserProfileServiceFacade import network.bisq.mobile.domain.client.main.user_profile.UserProfileApiGateway import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapFacade -import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapModel -import network.bisq.mobile.domain.user_profile.UserProfileModel import network.bisq.mobile.domain.user_profile.UserProfileServiceFacade +import network.bisq.mobile.presentation.MainPresenter +import network.bisq.mobile.presentation.ui.AppPresenter +import org.koin.dsl.bind import org.koin.dsl.module val androidClientModule = module { - single { ClientApplicationBootstrapModel() } - single { ClientApplicationBootstrapFacade(get()) } + single { ClientApplicationBootstrapFacade() } - single { ClientUserProfileModel() } single { ApiRequestService(get(), "10.0.2.2") } single { UserProfileApiGateway(get()) } - single { ClientUserProfileServiceFacade(get(), get()) } - + single { ClientUserProfileServiceFacade(get()) } + single { AndroidClientMainPresenter(get()) } bind AppPresenter::class } diff --git a/bisqapps/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/presentation/AndroidClientMainPresenter.kt b/bisqapps/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/presentation/AndroidClientMainPresenter.kt new file mode 100644 index 00000000..8080b6ab --- /dev/null +++ b/bisqapps/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/presentation/AndroidClientMainPresenter.kt @@ -0,0 +1,22 @@ +package network.bisq.mobile.client.presentation + +import network.bisq.mobile.domain.data.repository.GreetingRepository +import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapFacade +import network.bisq.mobile.presentation.MainPresenter + +@Suppress("UNCHECKED_CAST") +class AndroidClientMainPresenter( + private val applicationBootstrapFacade: ApplicationBootstrapFacade +) : MainPresenter(GreetingRepository()) { + + // FIXME onViewAttached is called twice + var applicationServiceInited = false + override fun onViewAttached() { + super.onViewAttached() + + if (!applicationServiceInited) { + applicationServiceInited = true + applicationBootstrapFacade.initialize() + } + } +} \ No newline at end of file diff --git a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/di/AndroidNodeModule.kt b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/di/AndroidNodeModule.kt index 9ec96ebc..b67cea71 100644 --- a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/di/AndroidNodeModule.kt +++ b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/di/AndroidNodeModule.kt @@ -2,14 +2,10 @@ package network.bisq.mobile.android.node.di import network.bisq.mobile.android.node.AndroidApplicationService import network.bisq.mobile.android.node.domain.data.repository.NodeGreetingRepository -import network.bisq.mobile.android.node.domain.user_profile.NodeUserProfileModel import network.bisq.mobile.android.node.domain.user_profile.NodeUserProfileServiceFacade import network.bisq.mobile.android.node.main.bootstrap.NodeApplicationBootstrapFacade -import network.bisq.mobile.android.node.main.bootstrap.NodeApplicationBootstrapModel import network.bisq.mobile.android.node.presentation.NodeMainPresenter import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapFacade -import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapModel -import network.bisq.mobile.domain.user_profile.UserProfileModel import network.bisq.mobile.domain.user_profile.UserProfileServiceFacade import network.bisq.mobile.presentation.MainPresenter import network.bisq.mobile.presentation.ui.AppPresenter @@ -22,11 +18,9 @@ val androidNodeModule = module { single { AndroidApplicationService.Supplier() } - single { NodeApplicationBootstrapModel() } - single { NodeApplicationBootstrapFacade(get(), get()) } + single { NodeApplicationBootstrapFacade(get()) } - single { NodeUserProfileModel() } - single { NodeUserProfileServiceFacade(get(), get()) } + single { NodeUserProfileServiceFacade(get()) } // this line showcases both, the possibility to change behaviour of the app by changing one definition diff --git a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/bootstrap/NodeApplicationBootstrapFacade.kt b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/bootstrap/NodeApplicationBootstrapFacade.kt index 7404a625..bc12d3d4 100644 --- a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/bootstrap/NodeApplicationBootstrapFacade.kt +++ b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/bootstrap/NodeApplicationBootstrapFacade.kt @@ -3,25 +3,23 @@ package network.bisq.mobile.android.node.main.bootstrap import bisq.application.State import network.bisq.mobile.android.node.AndroidApplicationService import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapFacade -import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapModel class NodeApplicationBootstrapFacade( - override val model: ApplicationBootstrapModel, - private val applicationServiceSupplier: AndroidApplicationService.Supplier + private val supplier: AndroidApplicationService.Supplier ) : - ApplicationBootstrapFacade { + ApplicationBootstrapFacade() { override fun initialize() { - applicationServiceSupplier.stateSupplier.get().addObserver { state: State -> + supplier.stateSupplier.get().addObserver { state: State -> when (state) { State.INITIALIZE_APP -> { - model.setState("Starting Bisq") - model.setProgress(0f) + setState("Starting Bisq") + setProgress(0f) } State.INITIALIZE_NETWORK -> { - model.setState("Initialize P2P network") - model.setProgress(0.5f) + setState("Initialize P2P network") + setProgress(0.5f) } // not used @@ -29,18 +27,18 @@ class NodeApplicationBootstrapFacade( } State.INITIALIZE_SERVICES -> { - model.setState("Initialize services") - model.setProgress(0.75f) + setState("Initialize services") + setProgress(0.75f) } State.APP_INITIALIZED -> { - model.setState("Bisq started") - model.setProgress(1f) + setState("Bisq started") + setProgress(1f) } State.FAILED -> { - model.setState("Startup failed") - model.setProgress(0f) + setState("Startup failed") + setProgress(0f) } } } diff --git a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/bootstrap/NodeApplicationBootstrapModel.kt b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/bootstrap/NodeApplicationBootstrapModel.kt deleted file mode 100644 index c3472d66..00000000 --- a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/bootstrap/NodeApplicationBootstrapModel.kt +++ /dev/null @@ -1,7 +0,0 @@ -package network.bisq.mobile.android.node.main.bootstrap - -import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapModel - -// In case we do not get any specific data added we can use ApplicationBootstrapModel instead -class NodeApplicationBootstrapModel : ApplicationBootstrapModel() { -} \ No newline at end of file diff --git a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/user_profile/NodeUserProfileModel.kt b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/user_profile/NodeUserProfileModel.kt deleted file mode 100644 index 7b3d05d1..00000000 --- a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/user_profile/NodeUserProfileModel.kt +++ /dev/null @@ -1,10 +0,0 @@ -package network.bisq.mobile.android.node.domain.user_profile - -import bisq.security.pow.ProofOfWork -import network.bisq.mobile.domain.user_profile.UserProfileModel -import java.security.KeyPair - -class NodeUserProfileModel : UserProfileModel() { - lateinit var keyPair: KeyPair - lateinit var proofOfWork: ProofOfWork -} \ No newline at end of file diff --git a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/user_profile/NodeUserProfileServiceFacade.kt b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/user_profile/NodeUserProfileServiceFacade.kt index 4d43a771..56e35e2e 100644 --- a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/user_profile/NodeUserProfileServiceFacade.kt +++ b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/user_profile/NodeUserProfileServiceFacade.kt @@ -3,14 +3,14 @@ package network.bisq.mobile.android.node.domain.user_profile import bisq.common.encoding.Hex import bisq.security.DigestUtil import bisq.security.SecurityService +import bisq.security.pow.ProofOfWork import bisq.user.UserService import bisq.user.identity.NymIdGenerator -import bisq.user.identity.UserIdentity import bisq.user.profile.UserProfile import co.touchlab.kermit.Logger import network.bisq.mobile.android.node.AndroidApplicationService -import network.bisq.mobile.domain.user_profile.UserProfileModel import network.bisq.mobile.domain.user_profile.UserProfileServiceFacade +import java.security.KeyPair import java.util.Random import kotlin.math.max import kotlin.math.min @@ -21,10 +21,7 @@ import kotlin.math.min * It uses in a in-memory model for the relevant data required for the presenter to reflect the domains state. * Persistence is done inside the Bisq 2 libraries. */ -class NodeUserProfileServiceFacade( - override val model: UserProfileModel, - private val applicationServiceSupplier: AndroidApplicationService.Supplier -) : +class NodeUserProfileServiceFacade(private val supplier: AndroidApplicationService.Supplier) : UserProfileServiceFacade { companion object { @@ -33,35 +30,37 @@ class NodeUserProfileServiceFacade( private val log = Logger.withTag(this::class.simpleName ?: "NodeUserProfileServiceFacade") + private var pubKeyHash: ByteArray? = null + private var keyPair: KeyPair? = null + private var proofOfWork: ProofOfWork? = null + + private var nickName: String? = "" + private var id: String? = null + private var nym: String? = null private val securityService: SecurityService - get() = applicationServiceSupplier.securityServiceSupplier.get() + get() = supplier.securityServiceSupplier.get() private val userService: UserService - get() = applicationServiceSupplier.userServiceSupplier.get() + get() = supplier.userServiceSupplier.get() override suspend fun hasUserProfile(): Boolean { return userService.userIdentityService.userIdentities.isNotEmpty() } - override suspend fun generateKeyPair() { - model as NodeUserProfileModel - model.setGenerateKeyPairInProgress(true) - val keyPair = securityService.keyBundleService.generateKeyPair() - model.keyPair = keyPair - val pubKeyHash = DigestUtil.hash(keyPair.public.encoded) - model.pubKeyHash = pubKeyHash - model.setId(Hex.encode(pubKeyHash)) + override suspend fun generateKeyPair(result: (String, String) -> Unit) { + keyPair = securityService.keyBundleService.generateKeyPair() + pubKeyHash = DigestUtil.hash(keyPair!!.public.encoded) + val ts = System.currentTimeMillis() - val proofOfWork = userService.userIdentityService.mintNymProofOfWork(pubKeyHash) + proofOfWork = userService.userIdentityService.mintNymProofOfWork(pubKeyHash) val powDuration = System.currentTimeMillis() - ts log.i("Proof of work creation completed after $powDuration ms") createSimulatedDelay(powDuration) - model.proofOfWork = proofOfWork - val powSolution = proofOfWork.solution - val nym = NymIdGenerator.generate(pubKeyHash, powSolution) - model.setNym(nym) + + id = Hex.encode(pubKeyHash) + nym = NymIdGenerator.generate(pubKeyHash, proofOfWork!!.solution) // CatHash is in desktop, needs to be reimplemented or the javafx part extracted and refactored into a non javafx lib // Image image = CatHash.getImage(pubKeyHash, @@ -69,63 +68,48 @@ class NodeUserProfileServiceFacade( // CURRENT_AVATARS_VERSION, // CreateProfileModel.CAT_HASH_IMAGE_SIZE); - model.setGenerateKeyPairInProgress(false) + result(id!!, nym!!) + } + + override fun setNickName(value: String) { + this.nickName = value } override suspend fun createAndPublishNewUserProfile() { - model as NodeUserProfileModel - model.setCreateAndPublishInProgress(true) // UI should start busy animation based on that property - userService.userIdentityService.createAndPublishNewUserProfile( - model.nickName.value, - model.keyPair, - model.pubKeyHash, - model.proofOfWork, - AVATAR_VERSION, - "", - "" - ) - .whenComplete { userIdentity: UserIdentity?, throwable: Throwable? -> - // UI should stop busy animation and show `next` button - model.setCreateAndPublishInProgress(false) - } + nickName?.let { + userService.userIdentityService.createAndPublishNewUserProfile( + nickName, + keyPair, + pubKeyHash, + proofOfWork, + AVATAR_VERSION, + "", + "" + ) + } } override suspend fun getUserIdentityIds(): List { - return userService.userIdentityService.userIdentities - .map { userIdentity -> userIdentity.id } + return userService.userIdentityService.userIdentities.map { userIdentity -> userIdentity.id } } - override suspend fun applySelectedUserProfile() { + override suspend fun applySelectedUserProfile(result: (String?, String?, String?) -> Unit) { val userProfile = getSelectedUserProfile() if (userProfile != null) { - model.setNickName(userProfile.nickName) - model.setNym(userProfile.nym) - model.setId(userProfile.id) + nickName = userProfile.nickName + nym = userProfile.nym + id = userProfile.id + + // reset + pubKeyHash = null + keyPair = null + proofOfWork = null } + result(nickName, nym, id) } private fun getSelectedUserProfile(): UserProfile? { - val userIdentity = userService.userIdentityService.selectedUserIdentity ?: return null - return userIdentity.userProfile - - } - - private fun findUserProfile(id: String): UserProfileModel? { - return userService.userIdentityService.userIdentities - .map { userIdentity -> getNodeUserProfileModel(userIdentity) } - .find { model -> model.id.equals(id) } - } - - private fun getNodeUserProfileModel(userIdentity: UserIdentity): UserProfileModel { - val userProfile = userIdentity.userProfile - val model = NodeUserProfileModel() - model.setNickName(userProfile.nickName) - model.setNym(userProfile.nym) - model.setId(userProfile.id) - model.keyPair = userIdentity.identity.keyBundle.keyPair - model.pubKeyHash = userIdentity.userProfile.pubKeyHash - model.proofOfWork = userIdentity.userProfile.proofOfWork - return model + return userService.userIdentityService.selectedUserIdentity?.userProfile } private fun createSimulatedDelay(powDuration: Long) { diff --git a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/presentation/NodeMainPresenter.kt b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/presentation/NodeMainPresenter.kt index c331f8bc..091cde51 100644 --- a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/presentation/NodeMainPresenter.kt +++ b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/presentation/NodeMainPresenter.kt @@ -35,6 +35,4 @@ class NodeMainPresenter( supplier.applicationService.shutdown() super.onDestroying() } - - } \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/bootstrap/ClientApplicationBootstrapFacade.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/bootstrap/ClientApplicationBootstrapFacade.kt index b757fcb8..76ef94ac 100644 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/bootstrap/ClientApplicationBootstrapFacade.kt +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/bootstrap/ClientApplicationBootstrapFacade.kt @@ -5,32 +5,28 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.launch import network.bisq.mobile.domain.data.BackgroundDispatcher import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapFacade -import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapModel -class ClientApplicationBootstrapFacade( - override val model: ApplicationBootstrapModel -) : - ApplicationBootstrapFacade { - private val coroutineScope = CoroutineScope(BackgroundDispatcher) +class ClientApplicationBootstrapFacade() : + ApplicationBootstrapFacade() { + private val coroutineScope = CoroutineScope(BackgroundDispatcher) override fun initialize() { - val model = model as ClientApplicationBootstrapModel - model.setState( "Dummy state 1") - model.setProgress(0f) + setState("Dummy state 1") + setProgress(0f) // just dummy loading simulation, might be that there is no loading delay at the end... coroutineScope.launch { delay(500L) - model.setState( "Dummy state 2") - model.setProgress(0.25f) + setState("Dummy state 2") + setProgress(0.25f) delay(500L) - model.setState( "Dummy state 3") - model.setProgress(0.5f) + setState("Dummy state 3") + setProgress(0.5f) delay(500L) - model.setState( "Dummy state 4") - model.setProgress(1f) + setState("Dummy state 4") + setProgress(1f) } } } \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/bootstrap/ClientApplicationBootstrapModel.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/bootstrap/ClientApplicationBootstrapModel.kt deleted file mode 100644 index 48f7e283..00000000 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/bootstrap/ClientApplicationBootstrapModel.kt +++ /dev/null @@ -1,7 +0,0 @@ -package network.bisq.mobile.android.node.main.bootstrap - -import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapModel - -// In case we do not get any specific data added we can use ApplicationBootstrapModel instead -class ClientApplicationBootstrapModel : ApplicationBootstrapModel() { -} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/ClientUserProfileModel.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/ClientUserProfileModel.kt deleted file mode 100644 index ad102f41..00000000 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/ClientUserProfileModel.kt +++ /dev/null @@ -1,11 +0,0 @@ -package network.bisq.mobile.domain.client.main.user_profile - -import network.bisq.mobile.client.replicated_model.security.keys.KeyPair -import network.bisq.mobile.client.replicated_model.security.pow.ProofOfWork -import network.bisq.mobile.domain.user_profile.UserProfileModel - -class ClientUserProfileModel : UserProfileModel() { - lateinit var preparedDataAsJson: String - lateinit var keyPair: KeyPair - lateinit var proofOfWork: ProofOfWork -} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/ClientUserProfileServiceFacade.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/ClientUserProfileServiceFacade.kt index 79de6313..eab5bf20 100644 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/ClientUserProfileServiceFacade.kt +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/ClientUserProfileServiceFacade.kt @@ -3,67 +3,73 @@ package network.bisq.mobile.domain.client.main.user_profile import co.touchlab.kermit.Logger import kotlinx.coroutines.delay import kotlinx.datetime.Clock +import network.bisq.mobile.client.replicated_model.security.keys.KeyPair +import network.bisq.mobile.client.replicated_model.security.pow.ProofOfWork import network.bisq.mobile.client.replicated_model.user.profile.UserProfile import network.bisq.mobile.client.user_profile.UserProfileResponse -import network.bisq.mobile.domain.user_profile.UserProfileModel import network.bisq.mobile.domain.user_profile.UserProfileServiceFacade import kotlin.math.max import kotlin.math.min import kotlin.random.Random -class ClientUserProfileServiceFacade( - override val model: UserProfileModel, - private val apiGateway: UserProfileApiGateway -) : +class ClientUserProfileServiceFacade(private val apiGateway: UserProfileApiGateway) : UserProfileServiceFacade { private val log = Logger.withTag(this::class.simpleName ?: "UserProfileServiceFacade") + private var preparedDataAsJson: String? = null + private var keyPair: KeyPair? = null + private var proofOfWork: ProofOfWork? = null + + private var nickName: String? = null + private var id: String? = null + private var nym: String? = null override suspend fun hasUserProfile(): Boolean { return getUserIdentityIds().isNotEmpty() } - override suspend fun generateKeyPair() { - model as ClientUserProfileModel + override suspend fun generateKeyPair(result: (String, String) -> Unit) { try { - model.setGenerateKeyPairInProgress(true) val ts = Clock.System.now().toEpochMilliseconds() val response = apiGateway.requestPreparedData() - model.preparedDataAsJson = response.first + preparedDataAsJson = response.first val preparedData = response.second createSimulatedDelay(Clock.System.now().toEpochMilliseconds() - ts) - model.keyPair = preparedData.keyPair - model.proofOfWork = preparedData.proofOfWork - model.setNym(preparedData.nym) - model.setId(preparedData.id) + keyPair = preparedData.keyPair + proofOfWork = preparedData.proofOfWork + id = preparedData.id + nym = preparedData.nym + + result(id!!, nym!!) } catch (e: Exception) { log.e { e.toString() } - } finally { - model.setGenerateKeyPairInProgress(false) } } + override fun setNickName(value: String) { + this.nickName = value + } + override suspend fun createAndPublishNewUserProfile() { - model as ClientUserProfileModel - try { - model.setCreateAndPublishInProgress(true) - val response: UserProfileResponse = - apiGateway.createAndPublishNewUserProfile( - model.nickName.value, - model.preparedDataAsJson - ) - require(model.id.value == response.userProfileId) - { "userProfileId from model does not match userProfileId from response" } - } catch (e: Exception) { - log.e { e.toString() } - } finally { - model.setCreateAndPublishInProgress(false) + nickName?.let { nickName -> + preparedDataAsJson?.let { preparedDataAsJson -> + try { + val response: UserProfileResponse = + apiGateway.createAndPublishNewUserProfile( + nickName, + preparedDataAsJson + ) + require(id == response.userProfileId) + { "userProfileId from model does not match userProfileId from response" } + } catch (e: Exception) { + log.e { e.toString() } + } + } } } - override suspend fun getUserIdentityIds(): List { return try { apiGateway.getUserIdentityIds() @@ -73,25 +79,27 @@ class ClientUserProfileServiceFacade( } } - override suspend fun applySelectedUserProfile() { + override suspend fun applySelectedUserProfile(result: (String?, String?, String?) -> Unit) { try { val userProfile = getSelectedUserProfile() - model.setNickName(userProfile.nickName) - model.setNym(userProfile.nym) - model.setId(userProfile.id) + nickName = userProfile.nickName + nym = userProfile.nym + id = userProfile.id + + // reset + preparedDataAsJson = null + keyPair = null + proofOfWork = null } catch (e: Exception) { log.e { e.toString() } } + result(nickName, nym, id) } private suspend fun getSelectedUserProfile(): UserProfile { return apiGateway.getSelectedUserProfile() } - private suspend fun findUserProfile(id: String): UserProfileModel? { - TODO("Not yet implemented") - } - private suspend fun createSimulatedDelay(requestDuration: Long) { // Proof of work creation for difficulty 65536 takes about 50 ms to 100 ms on a 4 GHz Intel Core i7. // The API request is likely also quite fast diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/bootstrap/ApplicationBootstrapFacade.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/bootstrap/ApplicationBootstrapFacade.kt index a84a71af..8eb2fff3 100644 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/bootstrap/ApplicationBootstrapFacade.kt +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/bootstrap/ApplicationBootstrapFacade.kt @@ -1,6 +1,20 @@ package network.bisq.mobile.domain.data.repository.main.bootstrap -interface ApplicationBootstrapFacade { - fun initialize() - val model: ApplicationBootstrapModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +abstract class ApplicationBootstrapFacade { + abstract fun initialize() + + private val _state = MutableStateFlow("") + val state: StateFlow = _state + fun setState(value: String) { + _state.value = value + } + + private val _progress = MutableStateFlow(0f) + val progress: StateFlow = _progress + fun setProgress(value: Float) { + _progress.value = value + } } \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/bootstrap/ApplicationBootstrapModel.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/bootstrap/ApplicationBootstrapModel.kt deleted file mode 100644 index a45d7db4..00000000 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/bootstrap/ApplicationBootstrapModel.kt +++ /dev/null @@ -1,18 +0,0 @@ -package network.bisq.mobile.domain.data.repository.main.bootstrap - -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow - -open class ApplicationBootstrapModel { - private val _state = MutableStateFlow("") - val state: StateFlow = _state - fun setState(value: String) { - _state.value = value - } - - private val _progress = MutableStateFlow(0f) - val progress: StateFlow = _progress - fun setProgress(value: Float) { - _progress.value = value - } -} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/repository/Repositories.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/repository/Repositories.kt index 0b09afc4..44b0504b 100644 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/repository/Repositories.kt +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/repository/Repositories.kt @@ -4,8 +4,6 @@ import network.bisq.mobile.domain.data.model.BisqStats import network.bisq.mobile.domain.data.model.BtcPrice import network.bisq.mobile.domain.data.model.Greeting import network.bisq.mobile.domain.data.model.Settings -import network.bisq.mobile.domain.user_profile.UserProfileModel -import network.bisq.mobile.domain.user_profile.UserProfileServiceFacade // this way of definingsupports both platforms // add your repositories here and then in your DI module call this classes for instanciation @@ -13,4 +11,3 @@ open class GreetingRepository: SingleObjectRepository() open class BisqStatsRepository: SingleObjectRepository() open class BtcPriceRepository: SingleObjectRepository() open class SettingsRepository: SingleObjectRepository() -class UserProfileRepository(val model: UserProfileModel, val service: UserProfileServiceFacade) diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/di/DomainModule.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/di/DomainModule.kt index 767918f4..042a5836 100644 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/di/DomainModule.kt +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/di/DomainModule.kt @@ -5,7 +5,6 @@ import network.bisq.mobile.domain.data.repository.BisqStatsRepository import network.bisq.mobile.domain.data.repository.BtcPriceRepository import network.bisq.mobile.domain.data.repository.GreetingRepository import network.bisq.mobile.domain.data.repository.SettingsRepository -import network.bisq.mobile.domain.data.repository.UserProfileRepository import org.koin.dsl.module val domainModule = module { @@ -13,5 +12,4 @@ val domainModule = module { single { BisqStatsRepository() } single { BtcPriceRepository() } single { SettingsRepository() } - single { UserProfileRepository(get(), get()) } } diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/user_profile/UserProfileModel.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/user_profile/UserProfileModel.kt deleted file mode 100644 index ea824bbe..00000000 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/user_profile/UserProfileModel.kt +++ /dev/null @@ -1,47 +0,0 @@ -package network.bisq.mobile.domain.user_profile - -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow - -open class UserProfileModel { - private val _nickName = MutableStateFlow("") - val nickName: StateFlow get() = _nickName - fun setNickName(value: String) { - _nickName.value = value - } - - private val _id = MutableStateFlow("") - val id: StateFlow get() = _id - fun setId(value: String) { - _id.value = value - } - - private val _nym = MutableStateFlow("") - val nym: StateFlow get() = _nym - fun setNym(value: String) { - _nym.value = value - } - - private val _generateKeyPairInProgress = MutableStateFlow(false) - val generateKeyPairInProgress: StateFlow get() = _generateKeyPairInProgress - fun setGenerateKeyPairInProgress(value: Boolean) { - _generateKeyPairInProgress.value = value - } - - private val _createAndPublishInProgress = MutableStateFlow(false) - val createAndPublishInProgress: StateFlow get() = _createAndPublishInProgress - fun setCreateAndPublishInProgress(value: Boolean) { - _createAndPublishInProgress.value = value - } - - lateinit var pubKeyHash: ByteArray - - override fun toString(): String { - return "UserProfileModel(_nickName=${_nickName.value}, " + - "_id=${_id.value}, " + - "_nym=${_nym.value}, " + - "_generateKeyPairInProgress=${_generateKeyPairInProgress.value}, " + - "_createAndPublishInProgress=${_createAndPublishInProgress.value}, " + - "pubKeyHash=${pubKeyHash.contentToString()})" - } -} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/user_profile/UserProfileServiceFacade.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/user_profile/UserProfileServiceFacade.kt index 35b2232e..81129d0d 100644 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/user_profile/UserProfileServiceFacade.kt +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/user_profile/UserProfileServiceFacade.kt @@ -1,11 +1,6 @@ package network.bisq.mobile.domain.user_profile interface UserProfileServiceFacade { - /** - * The model for holding presentation relevant data as well as data needed for creating the user identity. - */ - val model: UserProfileModel - /** * Returns true if there is a user identity already created. * This should be used to detect a first time user who has no identity created yet and where @@ -26,7 +21,7 @@ interface UserProfileServiceFacade { * the proof of work solution. * The CatHash image is also created based on that hash and the proof of work solution. */ - suspend fun generateKeyPair() + suspend fun generateKeyPair(result: (String, String) -> Unit) /** * Once the user clicks the `create` button we create a user identity and publish the @@ -44,5 +39,7 @@ interface UserProfileServiceFacade { /** * Applies the selected user identity to the user profile model */ - suspend fun applySelectedUserProfile() + suspend fun applySelectedUserProfile(result: (String?, String?, String?) -> Unit) + + fun setNickName(value: String) } \ No newline at end of file diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt index dd0d6b06..57d1db7a 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt @@ -8,7 +8,6 @@ import network.bisq.mobile.presentation.ui.uicases.GettingStartedPresenter import network.bisq.mobile.presentation.ui.uicases.IGettingStarted import network.bisq.mobile.presentation.ui.uicases.startup.CreateProfilePresenter import network.bisq.mobile.presentation.ui.uicases.startup.IOnboardingPresenter -import network.bisq.mobile.presentation.ui.uicases.startup.ISplashPresenter import network.bisq.mobile.presentation.ui.uicases.startup.ITrustedNodeSetupPresenter import network.bisq.mobile.presentation.ui.uicases.startup.OnBoardingPresenter import network.bisq.mobile.presentation.ui.uicases.startup.SplashPresenter @@ -29,9 +28,10 @@ val presentationModule = module { single { (navController: NavController) -> SplashPresenter( get(), - navController = navController + navController = navController, + get() ) - } bind ISplashPresenter::class + } single { (navController: NavController) -> OnBoardingPresenter( @@ -52,7 +52,7 @@ val presentationModule = module { CreateProfilePresenter( get(), navController = navController, - userProfileRepository = get() + get() ) } diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfilePresenter.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfilePresenter.kt index 2a950f51..6e6f8c06 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfilePresenter.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfilePresenter.kt @@ -4,10 +4,11 @@ import androidx.navigation.NavController import co.touchlab.kermit.Logger import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch import network.bisq.mobile.domain.data.BackgroundDispatcher -import network.bisq.mobile.domain.data.repository.UserProfileRepository +import network.bisq.mobile.domain.user_profile.UserProfileServiceFacade import network.bisq.mobile.presentation.BasePresenter import network.bisq.mobile.presentation.MainPresenter import network.bisq.mobile.presentation.ui.navigation.Routes @@ -15,16 +16,41 @@ import network.bisq.mobile.presentation.ui.navigation.Routes open class CreateProfilePresenter( mainPresenter: MainPresenter, private val navController: NavController, - private val userProfileRepository: UserProfileRepository + private val userProfileService: UserProfileServiceFacade ) : BasePresenter(mainPresenter) { private val log = Logger.withTag(this::class.simpleName ?: "CreateProfilePresenter") - private val userProfileModel = userProfileRepository.model - val nickName: StateFlow = userProfileModel.nickName - val nym: StateFlow = userProfileModel.nym - val id: StateFlow = userProfileModel.id + private val _id = MutableStateFlow("") + val id: StateFlow get() = _id + private fun setId(value: String) { + _id.value = value + } + + private val _nym = MutableStateFlow("") + val nym: StateFlow get() = _nym + private fun setNym(value: String) { + _nym.value = value + } + + private val _nickName = MutableStateFlow("") + val nickName: StateFlow get() = _nickName + fun setNickname(value: String) { + _nickName.value = value + userProfileService.setNickName(value) + } + private val _generateKeyPairInProgress = MutableStateFlow(false) + val generateKeyPairInProgress: StateFlow get() = _generateKeyPairInProgress + private fun setGenerateKeyPairInProgress(value: Boolean) { + _generateKeyPairInProgress.value = value + } + + private val _createAndPublishInProgress = MutableStateFlow(false) + val createAndPublishInProgress: StateFlow get() = _createAndPublishInProgress + private fun setCreateAndPublishInProgress(value: Boolean) { + _createAndPublishInProgress.value = value + } override fun onViewAttached() { onGenerateKeyPair() @@ -41,33 +67,31 @@ open class CreateProfilePresenter( // `onGenerateKeyPair()` when view is ready. } - fun onNickNameChanged(value: String) { - userProfileRepository.model.setNickName(value) - } - fun onGenerateKeyPair() { // takes 200 -1000 ms - // todo start busy animation in UI CoroutineScope(BackgroundDispatcher).launch { - userProfileRepository.model.generateKeyPairInProgress.collect { inProgress -> - if (!inProgress) { - // todo stop busy animation in UI - } + setGenerateKeyPairInProgress(true) + log.i { "Show busy animation for generateKeyPair" } + userProfileService.generateKeyPair { id, nym -> + setId(id) + setNym(nym) + //todo show new profile image } - } - - CoroutineScope(BackgroundDispatcher).launch { - userProfileRepository.service.generateKeyPair() + setGenerateKeyPairInProgress(false) + log.i { "Hide busy animation for generateKeyPair" } } } fun onCreateAndPublishNewUserProfile() { - // todo start busy animation in UI - // We cannot use BackgroundDispatcher here as we get error: - // `Method setCurrentState must be called on the main thread` - CoroutineScope(Dispatchers.Main).launch { - userProfileRepository.model.createAndPublishInProgress.collect { inProgress -> - if (!inProgress) { + if (nickName.value.isNotEmpty()) { + CoroutineScope(BackgroundDispatcher).launch { + setCreateAndPublishInProgress(true) + log.i { "Show busy animation for createAndPublishInProgress" } + userProfileService.createAndPublishNewUserProfile() + log.i { "Hide busy animation for createAndPublishInProgress" } + setCreateAndPublishInProgress(false) + + CoroutineScope(Dispatchers.Main).launch { // todo stop busy animation in UI navController.navigate(Routes.TrustedNodeSetup.name) { popUpTo(Routes.CreateProfile.name) { inclusive = true } @@ -75,9 +99,5 @@ open class CreateProfilePresenter( } } } - - CoroutineScope(BackgroundDispatcher).launch { - userProfileRepository.service.createAndPublishNewUserProfile() - } } } diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfileScreen.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfileScreen.kt index 15d7c168..58ab8e83 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfileScreen.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfileScreen.kt @@ -35,7 +35,6 @@ fun CreateProfileScreen( val navController: NavHostController = koinInject(named("RootNavController")) val presenter: CreateProfilePresenter = koinInject { parametersOf(navController) } - val profileName = presenter.nickName.collectAsState().value LaunchedEffect(Unit) { presenter.onViewAttached() @@ -65,7 +64,7 @@ fun CreateProfileScreen( MaterialTextField( text = presenter.nickName.collectAsState().value, placeholder = strings.onboarding_createProfile_nickName_prompt, - onValueChanged = { presenter.onNickNameChanged(it) }) + onValueChanged = { presenter.setNickname(it) }) } Spacer(modifier = Modifier.height(36.dp)) Image(painterResource(Res.drawable.img_bot_image), "User profile icon generated from the hash of the public key") // TODO: Translation @@ -90,7 +89,7 @@ fun CreateProfileScreen( BisqButton( strings.buttons_next, onClick = { presenter.onCreateAndPublishNewUserProfile() }, - backgroundColor = if (profileName.isEmpty()) BisqTheme.colors.primaryDisabled else BisqTheme.colors.primary + backgroundColor = if (presenter.nickName.value.isEmpty()) BisqTheme.colors.primaryDisabled else BisqTheme.colors.primary ) } } \ No newline at end of file diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/SplashPresenter.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/SplashPresenter.kt index 64bd7464..99d55652 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/SplashPresenter.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/SplashPresenter.kt @@ -3,36 +3,30 @@ package network.bisq.mobile.presentation.ui.uicases.startup import androidx.navigation.NavController import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch +import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapFacade import network.bisq.mobile.presentation.BasePresenter import network.bisq.mobile.presentation.MainPresenter import network.bisq.mobile.presentation.ui.navigation.Routes open class SplashPresenter( mainPresenter: MainPresenter, - private val navController: NavController -) : BasePresenter(mainPresenter), ISplashPresenter { + private val navController: NavController, + applicationBootstrapFacade: ApplicationBootstrapFacade +) : BasePresenter(mainPresenter) { private val coroutineScope = CoroutineScope(Dispatchers.Main) - override fun startLoading(onProgressUpdate: (Float) -> Unit) { + val state: StateFlow = applicationBootstrapFacade.state + val progress: StateFlow = applicationBootstrapFacade.progress + + override fun onViewAttached() { coroutineScope.launch { - initializeNetwork{ progress -> - onProgressUpdate(progress) + progress.collect { value -> + when { + value == 1.0f -> navigateToNextScreen() + } } - navigateToNextScreen() - } - } - - // TODO refactor into a service once networking is done - protected open suspend fun initializeNetwork(updateProgress: (Float) -> Unit) { - - //1. Initialize Tor here - //2. Connect to peers (for androidNode), to Bisq instance (for xClients) - //3. Do any other app initialization - for (i in 1..100) { - updateProgress(i.toFloat() / 100) - delay(25) } } @@ -40,7 +34,15 @@ open class SplashPresenter( // TODO: Conditional nav // If firstTimeApp launch, goto Onboarding[clientMode] (androidNode / xClient) // If not, goto TabContainerScreen - navController.navigate(Routes.Onboarding.name) { + /* navController.navigate(Routes.Onboarding.name) { + popUpTo(Routes.Splash.name) { inclusive = true } + }*/ + + //TODO + /* navController.navigate(Routes.TabContainer.name) { + popUpTo(Routes.TrustedNodeSetup.name) { inclusive = true } + }*/ + navController.navigate(Routes.CreateProfile.name) { popUpTo(Routes.Splash.name) { inclusive = true } } } diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/SplashScreen.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/SplashScreen.kt index 33e74445..3d2e31af 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/SplashScreen.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/SplashScreen.kt @@ -1,63 +1,50 @@ package network.bisq.mobile.presentation.ui.uicases.startup -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableFloatStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue +import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign -import androidx.navigation.NavController import androidx.navigation.NavHostController - import cafe.adriel.lyricist.LocalStrings -import network.bisq.mobile.presentation.ViewPresenter import network.bisq.mobile.presentation.ui.components.atoms.BisqProgressBar -import network.bisq.mobile.presentation.ui.components.atoms.icons.BisqLogo import network.bisq.mobile.presentation.ui.components.atoms.BisqText +import network.bisq.mobile.presentation.ui.components.atoms.icons.BisqLogo import network.bisq.mobile.presentation.ui.components.layout.BisqStaticLayout -import network.bisq.mobile.presentation.ui.theme.* +import network.bisq.mobile.presentation.ui.theme.BisqTheme import org.koin.compose.koinInject import org.koin.core.parameter.parametersOf import org.koin.core.qualifier.named -interface ISplashPresenter: ViewPresenter { - fun startLoading(onProgressUpdate: (Float) -> Unit) -} @Composable fun SplashScreen( ) { val strings = LocalStrings.current val navController: NavHostController = koinInject(named("RootNavController")) - val presenter: ISplashPresenter = koinInject { parametersOf(navController) } - - var currentProgress by remember { mutableFloatStateOf(0f) } + val presenter: SplashPresenter = koinInject { parametersOf(navController) } LaunchedEffect(Unit) { presenter.onViewAttached() - presenter.startLoading { progress -> - currentProgress = progress - } } BisqStaticLayout { BisqLogo() Column { - BisqProgressBar(progress = currentProgress) + BisqProgressBar(presenter.progress.collectAsState().value) // TODO: Get this from presenter val networkType = strings.splash_bootstrapState_network_TOR BisqText.baseRegular( - text = strings.splash_bootstrapState_BOOTSTRAP_TO_NETWORK(networkType), + text = presenter.state.collectAsState().value, color = BisqTheme.colors.secondaryHover, textAlign = TextAlign.Center, modifier = Modifier.fillMaxWidth(), - ) + ) } } } diff --git a/bisqapps/shared/presentation/src/iosMain/kotlin/network/bisq/mobile/presentation/IosClientMainPresenter.kt b/bisqapps/shared/presentation/src/iosMain/kotlin/network/bisq/mobile/presentation/IosClientMainPresenter.kt new file mode 100644 index 00000000..cc67d416 --- /dev/null +++ b/bisqapps/shared/presentation/src/iosMain/kotlin/network/bisq/mobile/presentation/IosClientMainPresenter.kt @@ -0,0 +1,21 @@ +package network.bisq.mobile.presentation + +import network.bisq.mobile.domain.data.repository.GreetingRepository +import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapFacade + +@Suppress("UNCHECKED_CAST") +class IosClientMainPresenter( + private val applicationBootstrapFacade: ApplicationBootstrapFacade +) : MainPresenter(GreetingRepository()) { + + // FIXME onViewAttached is called twice + var applicationServiceInited = false + override fun onViewAttached() { + super.onViewAttached() + + if (!applicationServiceInited) { + applicationServiceInited = true + applicationBootstrapFacade.initialize() + } + } +} \ No newline at end of file diff --git a/bisqapps/shared/presentation/src/iosMain/kotlin/network/bisq/mobile/presentation/di/IosClientModule.kt b/bisqapps/shared/presentation/src/iosMain/kotlin/network/bisq/mobile/presentation/di/IosClientModule.kt index fddfac0d..6b14f6d4 100644 --- a/bisqapps/shared/presentation/src/iosMain/kotlin/network/bisq/mobile/presentation/di/IosClientModule.kt +++ b/bisqapps/shared/presentation/src/iosMain/kotlin/network/bisq/mobile/presentation/di/IosClientModule.kt @@ -1,24 +1,23 @@ package network.bisq.mobile.presentation.di import network.bisq.mobile.android.node.main.bootstrap.ClientApplicationBootstrapFacade -import network.bisq.mobile.android.node.main.bootstrap.ClientApplicationBootstrapModel import network.bisq.mobile.client.service.ApiRequestService -import network.bisq.mobile.domain.client.main.user_profile.ClientUserProfileModel import network.bisq.mobile.domain.client.main.user_profile.ClientUserProfileServiceFacade import network.bisq.mobile.domain.client.main.user_profile.UserProfileApiGateway import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapFacade -import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapModel -import network.bisq.mobile.domain.user_profile.UserProfileModel import network.bisq.mobile.domain.user_profile.UserProfileServiceFacade +import network.bisq.mobile.presentation.IosClientMainPresenter +import network.bisq.mobile.presentation.MainPresenter +import network.bisq.mobile.presentation.ui.AppPresenter +import org.koin.dsl.bind import org.koin.dsl.module val iosClientModule = module { - single { ClientApplicationBootstrapModel() } - single { ClientApplicationBootstrapFacade(get()) } + single { ClientApplicationBootstrapFacade() } - single { ClientUserProfileModel() } single { ApiRequestService(get(), "localhost") } single { UserProfileApiGateway(get()) } - single { ClientUserProfileServiceFacade(get(), get()) } + single { ClientUserProfileServiceFacade(get()) } + single { IosClientMainPresenter(get()) } bind AppPresenter::class }