From 2de6dd70163e61b50528f317e6bbcff92c07ad55 Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Fri, 29 Nov 2024 14:26:43 +0700 Subject: [PATCH] Move AndroidCatHashService creation to AndroidApplicationService as we need the application base directory. Pass context to AndroidApplicationService. Fix package names. Add image to generateKeyPair as type Any. This is just preliminary due KMP issues with BitMap or related image formats. --- .../android/node/AndroidApplicationService.kt | 7 +++++ .../android/node/di/AndroidNodeModule.kt | 5 ---- .../NodeUserProfileServiceFacade.kt | 27 ++++++++++++------- .../node/presentation/NodeMainPresenter.kt | 7 ++++- .../bisq/mobile/client/di/ClientModule.kt | 4 +-- .../ClientUserProfileServiceFacade.kt | 8 +++--- .../user_profile/CreateUserIdentityRequest.kt | 2 +- .../user_profile/UserProfileApiGateway.kt | 3 +-- .../user_profile/UserProfileServiceFacade.kt | 2 +- .../uicases/startup/CreateProfilePresenter.kt | 10 +++++-- .../ui/uicases/startup/CreateProfileScreen.kt | 24 ++++++++++++----- 11 files changed, 64 insertions(+), 35 deletions(-) diff --git a/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/AndroidApplicationService.kt b/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/AndroidApplicationService.kt index 227dec2b..1effa803 100644 --- a/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/AndroidApplicationService.kt +++ b/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/AndroidApplicationService.kt @@ -16,6 +16,7 @@ */ package network.bisq.mobile.android.node +import android.content.Context import androidx.core.util.Supplier import bisq.account.AccountService import bisq.application.ApplicationService @@ -42,6 +43,7 @@ import bisq.user.UserService import lombok.Getter import lombok.Setter import lombok.extern.slf4j.Slf4j +import network.bisq.mobile.android.node.service.AndroidCatHashService import network.bisq.mobile.android.node.service.AndroidMemoryReportService import network.bisq.mobile.utils.Logging import java.nio.file.Path @@ -59,6 +61,7 @@ import java.util.concurrent.TimeUnit @Getter class AndroidApplicationService( androidMemoryReportService: AndroidMemoryReportService, + context: Context, userDataDir: Path? ) : ApplicationService("android", arrayOf(), userDataDir), Logging { @@ -69,6 +72,8 @@ class AndroidApplicationService( lateinit var applicationService: AndroidApplicationService var state: Supplier> = Supplier { applicationService.state } + var androidCatHashService: Supplier = + Supplier { applicationService.androidCatHashService } var securityService: Supplier = Supplier { applicationService.securityService } var networkService: Supplier = @@ -113,6 +118,8 @@ class AndroidApplicationService( private val shutDownErrorMessage = Observable() private val startupErrorMessage = Observable() + val androidCatHashService = AndroidCatHashService(context, config.baseDir) + val securityService = SecurityService(persistenceService, SecurityService.Config.from(getConfig("security"))) diff --git a/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/di/AndroidNodeModule.kt b/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/di/AndroidNodeModule.kt index 4bf5f74f..78227405 100644 --- a/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/di/AndroidNodeModule.kt +++ b/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/di/AndroidNodeModule.kt @@ -25,11 +25,6 @@ val androidNodeModule = module { AndroidMemoryReportService(androidContext()) } - single { - val context = androidContext() - AndroidCatHashService(context, context.filesDir.toPath()) - } - single { AndroidApplicationService.Provider() } single { NodeApplicationBootstrapFacade(get()) } diff --git a/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/user_profile/NodeUserProfileServiceFacade.kt b/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/user_profile/NodeUserProfileServiceFacade.kt index 8e90c3e0..9b53a04e 100644 --- a/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/user_profile/NodeUserProfileServiceFacade.kt +++ b/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/user_profile/NodeUserProfileServiceFacade.kt @@ -1,5 +1,7 @@ package network.bisq.mobile.android.node.domain.user_profile +import android.graphics.Bitmap +import androidx.compose.ui.graphics.asImageBitmap import bisq.common.encoding.Hex import bisq.security.DigestUtil import bisq.security.SecurityService @@ -8,6 +10,7 @@ import bisq.user.UserService import bisq.user.identity.NymIdGenerator import bisq.user.profile.UserProfile import network.bisq.mobile.android.node.AndroidApplicationService +import network.bisq.mobile.android.node.service.AndroidCatHashService import network.bisq.mobile.domain.service.user_profile.UserProfileServiceFacade import network.bisq.mobile.utils.Logging import java.security.KeyPair @@ -35,6 +38,9 @@ class NodeUserProfileServiceFacade(private val applicationService: AndroidApplic private val userService: UserService by lazy { applicationService.userService.get() } + private val catHashService: AndroidCatHashService by lazy { + applicationService.androidCatHashService.get() + } // Misc private var pubKeyHash: ByteArray? = null @@ -47,7 +53,7 @@ class NodeUserProfileServiceFacade(private val applicationService: AndroidApplic return userService.userIdentityService.userIdentities.isNotEmpty() } - override suspend fun generateKeyPair(result: (String, String) -> Unit) { + override suspend fun generateKeyPair(result: (String, String, Any?) -> Unit) { keyPair = securityService.keyBundleService.generateKeyPair() pubKeyHash = DigestUtil.hash(keyPair!!.public.encoded) @@ -58,15 +64,16 @@ class NodeUserProfileServiceFacade(private val applicationService: AndroidApplic createSimulatedDelay(powDuration) val id = Hex.encode(pubKeyHash) - val 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, - // powSolution, - // CURRENT_AVATARS_VERSION, - // CreateProfileModel.CAT_HASH_IMAGE_SIZE); - - result(id!!, nym!!) + val solution = proofOfWork!!.solution + val nym = NymIdGenerator.generate(pubKeyHash, solution) + val profileIcon: Bitmap = catHashService.getImage( + pubKeyHash, + solution, + 0, + 120.0 + ) + val imageBitmap = profileIcon.asImageBitmap() + result(id!!, nym!!, imageBitmap) } override suspend fun createAndPublishNewUserProfile(nickName: String) { diff --git a/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/presentation/NodeMainPresenter.kt b/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/presentation/NodeMainPresenter.kt index e5ca47e4..6e533f61 100644 --- a/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/presentation/NodeMainPresenter.kt +++ b/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/presentation/NodeMainPresenter.kt @@ -22,8 +22,13 @@ class NodeMainPresenter( if (!applicationServiceCreated) { applicationServiceCreated = true val filesDirsPath = (view as Activity).filesDir.toPath() + val applicationContext = (view as Activity).applicationContext val applicationService = - AndroidApplicationService(androidMemoryReportService, filesDirsPath) + AndroidApplicationService( + androidMemoryReportService, + applicationContext, + filesDirsPath + ) provider.applicationService = applicationService applicationBootstrapFacade.activate() diff --git a/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/di/ClientModule.kt b/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/di/ClientModule.kt index 6af40f42..147eb33a 100644 --- a/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/di/ClientModule.kt +++ b/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/di/ClientModule.kt @@ -12,9 +12,9 @@ import network.bisq.mobile.client.market.ClientMarketPriceServiceFacade import network.bisq.mobile.client.market.MarketPriceApiGateway import network.bisq.mobile.client.offerbook.ClientOfferbookServiceFacade import network.bisq.mobile.client.service.ApiRequestService -import network.bisq.mobile.domain.client.main.user_profile.ClientUserProfileServiceFacade +import network.bisq.mobile.client.user_profile.ClientUserProfileServiceFacade import network.bisq.mobile.client.offerbook.offer.OfferbookApiGateway -import network.bisq.mobile.domain.client.main.user_profile.UserProfileApiGateway +import network.bisq.mobile.client.user_profile.UserProfileApiGateway import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapFacade import network.bisq.mobile.domain.service.market_price.MarketPriceServiceFacade import network.bisq.mobile.domain.service.offerbook.OfferbookServiceFacade diff --git a/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/ClientUserProfileServiceFacade.kt b/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/ClientUserProfileServiceFacade.kt index 3c04d1cf..ada9e672 100644 --- a/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/ClientUserProfileServiceFacade.kt +++ b/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/ClientUserProfileServiceFacade.kt @@ -1,10 +1,9 @@ -package network.bisq.mobile.domain.client.main.user_profile +package network.bisq.mobile.client.user_profile import kotlinx.coroutines.delay import kotlinx.datetime.Clock import network.bisq.mobile.client.replicated_model.user.identity.PreparedData import network.bisq.mobile.client.replicated_model.user.profile.UserProfile -import network.bisq.mobile.client.user_profile.UserProfileResponse import network.bisq.mobile.domain.service.user_profile.UserProfileServiceFacade import network.bisq.mobile.utils.Logging import kotlin.math.max @@ -22,12 +21,13 @@ class ClientUserProfileServiceFacade(private val apiGateway: UserProfileApiGatew return getUserIdentityIds().isNotEmpty() } - override suspend fun generateKeyPair(result: (String, String) -> Unit) { + override suspend fun generateKeyPair(result: (String, String, Any?) -> Unit) { try { val ts = Clock.System.now().toEpochMilliseconds() val preparedData = apiGateway.requestPreparedData() createSimulatedDelay(Clock.System.now().toEpochMilliseconds() - ts) - result(preparedData.id, preparedData.nym) + //todo not impl yet + result(preparedData.id, preparedData.nym, null) this.preparedData = preparedData } catch (e: Exception) { log.e { e.toString() } diff --git a/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/CreateUserIdentityRequest.kt b/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/CreateUserIdentityRequest.kt index 69c97df3..d90cf6c8 100644 --- a/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/CreateUserIdentityRequest.kt +++ b/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/CreateUserIdentityRequest.kt @@ -1,4 +1,4 @@ -package network.bisq.mobile.domain.client.main.user_profile +package network.bisq.mobile.client.user_profile import kotlinx.serialization.Serializable import network.bisq.mobile.client.replicated_model.user.identity.PreparedData diff --git a/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/UserProfileApiGateway.kt b/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/UserProfileApiGateway.kt index d6e72400..a2272da5 100644 --- a/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/UserProfileApiGateway.kt +++ b/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/UserProfileApiGateway.kt @@ -1,9 +1,8 @@ -package network.bisq.mobile.domain.client.main.user_profile +package network.bisq.mobile.client.user_profile import network.bisq.mobile.client.replicated_model.user.identity.PreparedData import network.bisq.mobile.client.replicated_model.user.profile.UserProfile import network.bisq.mobile.client.service.ApiRequestService -import network.bisq.mobile.client.user_profile.UserProfileResponse class UserProfileApiGateway( private val apiRequestService: ApiRequestService diff --git a/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/user_profile/UserProfileServiceFacade.kt b/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/user_profile/UserProfileServiceFacade.kt index 656276a9..ee51e9a9 100644 --- a/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/user_profile/UserProfileServiceFacade.kt +++ b/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/user_profile/UserProfileServiceFacade.kt @@ -21,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(result: (String, String) -> Unit) + suspend fun generateKeyPair(result: (String, String, Any?) -> Unit) /** * Once the user clicks the `create` button we create a user identity and publish the diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfilePresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfilePresenter.kt index 97501883..c3b503be 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfilePresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfilePresenter.kt @@ -30,6 +30,12 @@ open class CreateProfilePresenter( _nym.value = value } + private val _profileIcon = MutableStateFlow(null) + val profileIcon: StateFlow get() = _profileIcon + private fun setProfileIcon(value: Any?) { + _profileIcon.value = value + } + private val _nickName = MutableStateFlow("") val nickName: StateFlow get() = _nickName fun setNickname(value: String) { @@ -99,10 +105,10 @@ open class CreateProfilePresenter( setGenerateKeyPairInProgress(true) log.i { "Show busy animation for generateKeyPair" } // takes 200 -1000 ms - userProfileService.generateKeyPair { id, nym -> + userProfileService.generateKeyPair { id, nym, profileIcon -> setId(id) setNym(nym) - //todo show new profile image + setProfileIcon(profileIcon) } setGenerateKeyPairInProgress(false) log.i { "Hide busy animation for generateKeyPair" } diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfileScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfileScreen.kt index 86f4b3dc..ba54dd40 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfileScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfileScreen.kt @@ -3,16 +3,17 @@ package network.bisq.mobile.presentation.ui.uicases.startup import androidx.compose.foundation.Image import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController -import bisqapps.shared.presentation.generated.resources.Res -import bisqapps.shared.presentation.generated.resources.img_bot_image import cafe.adriel.lyricist.LocalStrings import network.bisq.mobile.presentation.ui.components.atoms.BisqButton import network.bisq.mobile.presentation.ui.components.atoms.BisqText @@ -21,10 +22,10 @@ import network.bisq.mobile.presentation.ui.components.atoms.icons.BisqLogo import network.bisq.mobile.presentation.ui.components.layout.BisqScrollScaffold import network.bisq.mobile.presentation.ui.helpers.RememberPresenterLifecycle import network.bisq.mobile.presentation.ui.theme.BisqTheme -import org.jetbrains.compose.resources.painterResource import org.koin.compose.koinInject import org.koin.core.parameter.parametersOf import org.koin.core.qualifier.named +import kotlin.math.log @Composable fun CreateProfileScreen( @@ -57,10 +58,19 @@ fun CreateProfileScreen( placeholder = strings.onboarding_createProfile_nickName_prompt ) 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 + + presenter.profileIcon.collectAsState().value?.let { profileIcon -> + // how can i convert a coil3.Bitmap to androidx.compose.ui.graphics.ImageBitmap in KMP + val imageBitmap: ImageBitmap? = profileIcon as ImageBitmap + if (imageBitmap != null) { + Image( + bitmap = imageBitmap, + contentDescription = "User profile icon generated from the hash of the public key", + modifier = Modifier.height(60.dp).width(60.dp) + ) + } + } + Spacer(modifier = Modifier.height(32.dp)) BisqText.baseRegular( text = presenter.nym.collectAsState().value,