From 88795ca98c0e8fead85cfe4ce5c11222cda41fe4 Mon Sep 17 00:00:00 2001 From: rodvar Date: Tue, 28 Jan 2025 16:08:50 +1100 Subject: [PATCH] Feature/clients ongoing trades notifications (android) (#176) * - land user in open trades when clicking notification implemented for bisq connect android * refactor: extract foreground detector into a separate platform based code controller * - android client working (Except kill app case for the reasons in discussion) - improved logging for iOS --- .../client/AndroidClientMainPresenter.kt | 29 ++++++++++++ .../bisq/mobile/client/MainActivity.kt | 10 ++++ .../mobile/client/di/AndroidClientModule.kt | 13 ++++++ .../node/presentation/NodeMainPresenter.kt | 5 +- .../mobile/domain/di/DomainModule.android.kt | 6 ++- .../AppForegroundController.android.kt | 46 +++++++++++++++++++ .../NotificationServiceController.android.kt | 40 +++++----------- .../client/websocket/WebSocketClient.kt | 2 +- .../domain/service/AppForegroundController.kt | 10 ++++ .../bisq/mobile/domain/di/ClientModule.ios.kt | 6 ++- .../service/AppForegroundController.ios.kt | 43 +++++++++++++++++ .../NotificationServiceController.ios.kt | 26 ++++++++--- .../bisq/mobile/client/ClientMainPresenter.kt | 5 +- .../ui/components/molecules/TopBar.kt | 1 + .../ui/uicases/TabContainerScreen.kt | 2 + 15 files changed, 204 insertions(+), 40 deletions(-) create mode 100644 androidClient/src/androidMain/kotlin/network/bisq/mobile/client/AndroidClientMainPresenter.kt create mode 100644 shared/domain/src/androidMain/kotlin/network/bisq/mobile/domain/service/AppForegroundController.android.kt create mode 100644 shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/AppForegroundController.kt create mode 100644 shared/domain/src/iosMain/kotlin/network/bisq/mobile/domain/service/AppForegroundController.ios.kt diff --git a/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/AndroidClientMainPresenter.kt b/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/AndroidClientMainPresenter.kt new file mode 100644 index 00000000..4eaea79b --- /dev/null +++ b/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/AndroidClientMainPresenter.kt @@ -0,0 +1,29 @@ +package network.bisq.mobile.client + +import network.bisq.mobile.client.websocket.WebSocketClientProvider +import network.bisq.mobile.domain.UrlLauncher +import network.bisq.mobile.domain.service.bootstrap.ApplicationBootstrapFacade +import network.bisq.mobile.domain.service.market_price.MarketPriceServiceFacade +import network.bisq.mobile.domain.service.notifications.OpenTradesNotificationService +import network.bisq.mobile.domain.service.offers.OffersServiceFacade +import network.bisq.mobile.domain.service.settings.SettingsServiceFacade +import network.bisq.mobile.domain.service.trades.TradesServiceFacade + +/** + * Redefinition to be able to access activity for trading notifications click handling + */ +class AndroidClientMainPresenter(openTradesNotificationService: OpenTradesNotificationService, + tradesServiceFacade: TradesServiceFacade, + webSocketClientProvider: WebSocketClientProvider, + applicationBootstrapFacade: ApplicationBootstrapFacade, + offersServiceFacade: OffersServiceFacade, + marketPriceServiceFacade: MarketPriceServiceFacade, + settingsServiceFacade: SettingsServiceFacade, urlLauncher: UrlLauncher +) : ClientMainPresenter( + openTradesNotificationService, tradesServiceFacade, webSocketClientProvider, applicationBootstrapFacade, + offersServiceFacade, marketPriceServiceFacade, settingsServiceFacade, urlLauncher +) { + init { + openTradesNotificationService.notificationServiceController.activityClassForIntents = MainActivity::class.java + } +} \ No newline at end of file diff --git a/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/MainActivity.kt b/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/MainActivity.kt index ea06e131..63cff75e 100644 --- a/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/MainActivity.kt +++ b/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/MainActivity.kt @@ -1,5 +1,6 @@ package network.bisq.mobile.client +import android.content.Intent import android.content.pm.PackageManager import android.graphics.Color import android.os.Build @@ -17,6 +18,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.core.content.ContextCompat import network.bisq.mobile.presentation.MainPresenter import network.bisq.mobile.presentation.ui.App +import network.bisq.mobile.presentation.ui.navigation.Routes import org.koin.android.ext.android.inject class MainActivity : ComponentActivity() { @@ -29,6 +31,14 @@ class MainActivity : ComponentActivity() { MainPresenter.init() } + override fun onNewIntent(intent: Intent) { + super.onNewIntent(intent) + + intent?.getStringExtra("destination")?.let { destination -> + Routes.fromString(destination)?.let { presenter.navigateToTab(it) } + } + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) presenter.attachView(this) diff --git a/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/di/AndroidClientModule.kt b/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/di/AndroidClientModule.kt index f949d401..7f8d107e 100644 --- a/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/di/AndroidClientModule.kt +++ b/androidClient/src/androidMain/kotlin/network/bisq/mobile/client/di/AndroidClientModule.kt @@ -1,8 +1,14 @@ package network.bisq.mobile.client.di +import network.bisq.mobile.client.AndroidClientMainPresenter import network.bisq.mobile.client.service.user_profile.ClientCatHashService import network.bisq.mobile.domain.AndroidUrlLauncher import network.bisq.mobile.domain.UrlLauncher +import network.bisq.mobile.domain.service.AppForegroundController +import network.bisq.mobile.domain.service.ForegroundDetector +import network.bisq.mobile.domain.service.notifications.controller.NotificationServiceController +import network.bisq.mobile.presentation.MainPresenter +import network.bisq.mobile.presentation.ui.AppPresenter import network.bisq.mobile.service.AndroidClientCatHashService import org.koin.android.ext.koin.androidContext import org.koin.dsl.bind @@ -16,4 +22,11 @@ val androidClientModule = module { val filesDir = context.filesDir.absolutePath AndroidClientCatHashService(context, filesDir) } bind ClientCatHashService::class + + single { AppForegroundController(androidContext()) } bind ForegroundDetector::class + single { + NotificationServiceController(get()) + } + + single { AndroidClientMainPresenter(get(), get(), get(), get(), get(), get(), get(), get()) } bind AppPresenter::class } \ No newline at end of file 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 ea0c3b0b..3a4d93aa 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 @@ -13,10 +13,13 @@ import network.bisq.mobile.domain.service.settings.SettingsServiceFacade import network.bisq.mobile.domain.service.trades.TradesServiceFacade import network.bisq.mobile.presentation.MainPresenter +/** + * Node main presenter has a very different setup than the rest of the apps (bisq2 core dependencies) + */ class NodeMainPresenter( urlLauncher: UrlLauncher, + openTradesNotificationService: OpenTradesNotificationService, private val tradesServiceFacade: TradesServiceFacade, - private val openTradesNotificationService: OpenTradesNotificationService, private val provider: AndroidApplicationService.Provider, private val androidMemoryReportService: AndroidMemoryReportService, private val applicationBootstrapFacade: ApplicationBootstrapFacade, diff --git a/shared/domain/src/androidMain/kotlin/network/bisq/mobile/domain/di/DomainModule.android.kt b/shared/domain/src/androidMain/kotlin/network/bisq/mobile/domain/di/DomainModule.android.kt index c0a837cd..48f9f62a 100644 --- a/shared/domain/src/androidMain/kotlin/network/bisq/mobile/domain/di/DomainModule.android.kt +++ b/shared/domain/src/androidMain/kotlin/network/bisq/mobile/domain/di/DomainModule.android.kt @@ -1,9 +1,13 @@ package network.bisq.mobile.domain.di +import network.bisq.mobile.domain.service.AppForegroundController +import network.bisq.mobile.domain.service.ForegroundDetector import network.bisq.mobile.domain.service.notifications.controller.NotificationServiceController import org.koin.dsl.module import org.koin.android.ext.koin.androidContext +import org.koin.dsl.bind val serviceModule = module { - single { NotificationServiceController(androidContext()) } + single { AppForegroundController(androidContext()) } bind ForegroundDetector::class + single { NotificationServiceController(get()) } } \ No newline at end of file diff --git a/shared/domain/src/androidMain/kotlin/network/bisq/mobile/domain/service/AppForegroundController.android.kt b/shared/domain/src/androidMain/kotlin/network/bisq/mobile/domain/service/AppForegroundController.android.kt new file mode 100644 index 00000000..188c0b08 --- /dev/null +++ b/shared/domain/src/androidMain/kotlin/network/bisq/mobile/domain/service/AppForegroundController.android.kt @@ -0,0 +1,46 @@ +package network.bisq.mobile.domain.service + +import android.app.Activity +import android.app.Application +import android.content.Context +import android.os.Bundle +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import network.bisq.mobile.domain.utils.Logging + +@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") +actual class AppForegroundController(val context: Context) : ForegroundDetector, Logging { + private val _isForeground = MutableStateFlow(false) + override val isForeground: StateFlow = _isForeground + + init { + (context.applicationContext as Application).registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks { + override fun onActivityResumed(activity: Activity) { + onAppWillEnterForeground() + } + + override fun onActivityPaused(activity: Activity) { + onAppDidEnterBackground() + } + + // Other lifecycle methods can be left empty + override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {} + override fun onActivityStarted(activity: Activity) {} + override fun onActivityStopped(activity: Activity) {} + override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {} + override fun onActivityDestroyed(activity: Activity) {} + }) + } + + + private fun onAppDidEnterBackground() { + log.d("App is in foreground -> false") + _isForeground.value = false + } + + private fun onAppWillEnterForeground() { + log.d("App is in foreground -> true") + _isForeground.value = true + } + +} \ No newline at end of file diff --git a/shared/domain/src/androidMain/kotlin/network/bisq/mobile/domain/service/notifications/controller/NotificationServiceController.android.kt b/shared/domain/src/androidMain/kotlin/network/bisq/mobile/domain/service/notifications/controller/NotificationServiceController.android.kt index 8034a60b..f9c5d48e 100644 --- a/shared/domain/src/androidMain/kotlin/network/bisq/mobile/domain/service/notifications/controller/NotificationServiceController.android.kt +++ b/shared/domain/src/androidMain/kotlin/network/bisq/mobile/domain/service/notifications/controller/NotificationServiceController.android.kt @@ -1,20 +1,18 @@ package network.bisq.mobile.domain.service.notifications.controller -import android.app.Activity -import android.app.Application import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent import android.content.Context import android.content.Intent import android.os.Build -import android.os.Bundle import androidx.core.app.NotificationCompat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch +import network.bisq.mobile.domain.service.AppForegroundController import network.bisq.mobile.domain.service.BisqForegroundService import network.bisq.mobile.domain.utils.Logging @@ -22,7 +20,9 @@ import network.bisq.mobile.domain.utils.Logging * Controller interacting with the bisq service */ @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") -actual class NotificationServiceController (private val context: Context): ServiceController, Logging { +actual class NotificationServiceController (private val appForegroundController: AppForegroundController): ServiceController, Logging { + + private val context = appForegroundController.context companion object { const val SERVICE_NAME = "Bisq Service" @@ -30,29 +30,10 @@ actual class NotificationServiceController (private val context: Context): Servi private val serviceScope = CoroutineScope(SupervisorJob()) private val observerJobs = mutableMapOf, Job>() - private var isForeground = false private var isRunning = false var activityClassForIntents = context::class.java - - init { - (context.applicationContext as Application).registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks { - override fun onActivityResumed(activity: Activity) { - isForeground = true - } - - override fun onActivityPaused(activity: Activity) { - isForeground = false - } - - // Other lifecycle methods can be left empty - override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {} - override fun onActivityStarted(activity: Activity) {} - override fun onActivityStopped(activity: Activity) {} - override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {} - override fun onActivityDestroyed(activity: Activity) {} - }) - } + var defaultDestination = "tab_my_trades" // TODO minor refactor move this hardcode out of here and into client leaf code } /** * Starts the service in the appropiate mode based on the current device running Android API @@ -108,15 +89,16 @@ actual class NotificationServiceController (private val context: Context): Servi // TODO support for on click and decide if we block on foreground actual fun pushNotification(title: String, message: String) { -// if (isForeground) { -// log.w { "Skipping notification since app is in the foreground" } -// } else { + if (isAppInForeground()) { + log.w { "Skipping notification since app is in the foreground" } + return + } // Create an intent that brings the user back to the app val intent = Intent(context, activityClassForIntents).apply { flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP // flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP - putExtra("destination", "tab_my_trades") // Add extras to navigate to a specific screen + putExtra("destination", defaultDestination) // Add extras to navigate to a specific screen } // Create a PendingIntent to handle the notification click @@ -159,7 +141,7 @@ actual class NotificationServiceController (private val context: Context): Servi } actual fun isAppInForeground(): Boolean { - TODO("Not yet implemented") + return appForegroundController.isForeground.value } } \ No newline at end of file diff --git a/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/websocket/WebSocketClient.kt b/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/websocket/WebSocketClient.kt index cdd854fd..1afbf23e 100644 --- a/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/websocket/WebSocketClient.kt +++ b/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/websocket/WebSocketClient.kt @@ -192,7 +192,7 @@ class WebSocketClient( } catch (e: Exception) { log.e(e) { "Exception ocurred whilst listening for WS messages - triggering reconnect" } } finally { - log.d { "Not listining for WS messages anymore" } + log.d { "Not listening for WS messages anymore - launching reconnect" } reconnect() } diff --git a/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/AppForegroundController.kt b/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/AppForegroundController.kt new file mode 100644 index 00000000..b190c6eb --- /dev/null +++ b/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/AppForegroundController.kt @@ -0,0 +1,10 @@ +package network.bisq.mobile.domain.service + +import kotlinx.coroutines.flow.StateFlow + +interface ForegroundDetector { + val isForeground: StateFlow +} + +@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") +expect class AppForegroundController \ No newline at end of file diff --git a/shared/domain/src/iosMain/kotlin/network/bisq/mobile/domain/di/ClientModule.ios.kt b/shared/domain/src/iosMain/kotlin/network/bisq/mobile/domain/di/ClientModule.ios.kt index 4fff7809..ef964186 100644 --- a/shared/domain/src/iosMain/kotlin/network/bisq/mobile/domain/di/ClientModule.ios.kt +++ b/shared/domain/src/iosMain/kotlin/network/bisq/mobile/domain/di/ClientModule.ios.kt @@ -2,13 +2,17 @@ package network.bisq.mobile.domain.di import network.bisq.mobile.domain.IOSUrlLauncher import network.bisq.mobile.domain.UrlLauncher +import network.bisq.mobile.domain.service.AppForegroundController +import network.bisq.mobile.domain.service.ForegroundDetector import network.bisq.mobile.domain.service.notifications.controller.NotificationServiceController +import org.koin.dsl.bind import org.koin.dsl.module val iosClientModule = module { single { IOSUrlLauncher() } + single { AppForegroundController() } bind ForegroundDetector::class single { - NotificationServiceController().apply { + NotificationServiceController(get()).apply { this.registerBackgroundTask() } } diff --git a/shared/domain/src/iosMain/kotlin/network/bisq/mobile/domain/service/AppForegroundController.ios.kt b/shared/domain/src/iosMain/kotlin/network/bisq/mobile/domain/service/AppForegroundController.ios.kt new file mode 100644 index 00000000..5fc5567c --- /dev/null +++ b/shared/domain/src/iosMain/kotlin/network/bisq/mobile/domain/service/AppForegroundController.ios.kt @@ -0,0 +1,43 @@ +package network.bisq.mobile.domain.service + +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import network.bisq.mobile.domain.utils.Logging +import platform.Foundation.NSNotificationCenter +import platform.UIKit.UIApplicationDidEnterBackgroundNotification +import platform.UIKit.UIApplicationWillEnterForegroundNotification + +@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") +actual class AppForegroundController : ForegroundDetector, Logging { + private val _isForeground = MutableStateFlow(true) + override val isForeground: StateFlow = _isForeground + + init { + val notificationCenter = NSNotificationCenter.defaultCenter + notificationCenter.addObserverForName( + name = UIApplicationDidEnterBackgroundNotification, + `object` = null, + queue = null + ) { notification -> + onAppDidEnterBackground() + } + notificationCenter.addObserverForName( + name = UIApplicationWillEnterForegroundNotification, + `object` = null, + queue = null + ) { notification -> + onAppWillEnterForeground() + } + } + + private fun onAppDidEnterBackground() { + log.d {"App is in foreground -> false" } + _isForeground.value = false + + } + + private fun onAppWillEnterForeground() { + log.d {"App is in foreground -> true" } + _isForeground.value = true + } +} \ No newline at end of file diff --git a/shared/domain/src/iosMain/kotlin/network/bisq/mobile/domain/service/notifications/controller/NotificationServiceController.ios.kt b/shared/domain/src/iosMain/kotlin/network/bisq/mobile/domain/service/notifications/controller/NotificationServiceController.ios.kt index f1874059..6164fc20 100644 --- a/shared/domain/src/iosMain/kotlin/network/bisq/mobile/domain/service/notifications/controller/NotificationServiceController.ios.kt +++ b/shared/domain/src/iosMain/kotlin/network/bisq/mobile/domain/service/notifications/controller/NotificationServiceController.ios.kt @@ -3,6 +3,7 @@ package network.bisq.mobile.domain.service.notifications.controller import kotlinx.cinterop.ExperimentalForeignApi import kotlinx.coroutines.* import kotlinx.coroutines.flow.StateFlow +import network.bisq.mobile.domain.service.AppForegroundController import network.bisq.mobile.domain.utils.Logging import platform.BackgroundTasks.* import platform.Foundation.NSDate @@ -12,10 +13,12 @@ import platform.UIKit.UIApplication import platform.UIKit.UIApplicationState import platform.UserNotifications.* import platform.darwin.NSObject +import platform.darwin.dispatch_get_main_queue +import platform.darwin.dispatch_sync @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") -actual class NotificationServiceController: ServiceController, Logging { +actual class NotificationServiceController(private val appForegroundController: AppForegroundController): ServiceController, Logging { companion object { const val BACKGROUND_TASK_ID = "network.bisq.mobile.iosUC4273Y485" @@ -60,6 +63,7 @@ actual class NotificationServiceController: ServiceController, Logging { actual override fun startService() { if (isRunning) { + logDebug("Notification Service already started, skipping launch") return } logDebug("Starting background service") @@ -73,7 +77,6 @@ actual class NotificationServiceController: ServiceController, Logging { // Once permission is granted, you can start scheduling background tasks startBackgroundTaskLoop() logDebug("Background service started") - isRunning = true } else { logDebug("Notification permission denied: ${error?.localizedDescription}") } @@ -90,6 +93,7 @@ actual class NotificationServiceController: ServiceController, Logging { actual override fun registerObserver(stateFlow: StateFlow, onStateChange: (T) -> Unit) { if (observerJobs.contains(stateFlow)) { log.w { "State flow observer already registered, skipping registration" } + return } val job = serviceScope.launch { stateFlow.collect { @@ -106,6 +110,11 @@ actual class NotificationServiceController: ServiceController, Logging { } actual fun pushNotification(title: String, message: String) { + if (isAppInForeground()) { + log.w { "Skipping notification since app is in the foreground" } + return + } + val content = UNMutableNotificationContent().apply { setValue(title, forKey = "title") setValue(message, forKey = "body") @@ -141,6 +150,7 @@ actual class NotificationServiceController: ServiceController, Logging { } private fun startBackgroundTaskLoop() { + isRunning = true CoroutineScope(Dispatchers.Default).launch { while (isRunning) { scheduleBackgroundTask() @@ -165,7 +175,7 @@ actual class NotificationServiceController: ServiceController, Logging { private fun logDebug(message: String) { - logScope.launch { + logScope.launch { // (Dispatchers.Main) log.d { message } } } @@ -174,7 +184,7 @@ actual class NotificationServiceController: ServiceController, Logging { // in iOS this needs to be done on app init or it will throw exception fun registerBackgroundTask() { if (isBackgroundTaskRegistered) { - logDebug("Background task is already registered.") + logDebug("Background task is already registered, skipping registration launch") return } @@ -187,10 +197,14 @@ actual class NotificationServiceController: ServiceController, Logging { } isBackgroundTaskRegistered = true - logDebug("Background task handler registered.") + logDebug("Background task handler registered") } actual fun isAppInForeground(): Boolean { - return UIApplication.sharedApplication.applicationState == UIApplicationState.UIApplicationStateActive + var isForeground = false + dispatch_sync(dispatch_get_main_queue()) { + isForeground = (appForegroundController.isForeground.value) + } + return isForeground } } diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/client/ClientMainPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/client/ClientMainPresenter.kt index c104a082..626abde4 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/client/ClientMainPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/client/ClientMainPresenter.kt @@ -11,7 +11,10 @@ import network.bisq.mobile.domain.service.settings.SettingsServiceFacade import network.bisq.mobile.domain.service.trades.TradesServiceFacade import network.bisq.mobile.presentation.MainPresenter -class ClientMainPresenter( +/** + * Contains all the share code for each client. Each specific app might extend this class if needed. + */ +open class ClientMainPresenter( openTradesNotificationService: OpenTradesNotificationService, private val tradesServiceFacade: TradesServiceFacade, private val webSocketClientProvider: WebSocketClientProvider, diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/TopBar.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/TopBar.kt index 8863408b..1810fde3 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/TopBar.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/TopBar.kt @@ -134,6 +134,7 @@ fun TopBar( .alpha(if (currentTab == Routes.TabSettings.name) 0.5f else 1.0f) .clickable { if (currentTab != Routes.TabSettings.name) { + // TODO this should be presenter code, with the proper main thread coroutine used (causes random crashes as is) navController.navigate(Routes.UserProfileSettings.name) } }) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/TabContainerScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/TabContainerScreen.kt index 4181e299..c4336424 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/TabContainerScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/TabContainerScreen.kt @@ -66,6 +66,7 @@ fun TabContainerScreen() { }, backBehavior = { if (currentRoute != Routes.TabHome.name) { + // TODO this should be presenter code, with the proper main thread coroutine used (causes random crashes as is) navController.navigate(Routes.TabHome.name) { navController.graph.startDestinationRoute?.let { route -> popUpTo(route) { saveState = false } @@ -86,6 +87,7 @@ fun TabContainerScreen() { items = navigationListItem, currentRoute = currentRoute.orEmpty(), onItemClick = { currentNavigationItem -> + // TODO this should be presenter code, with the proper main thread coroutine used (causes random crashes as is) navController.navigate(currentNavigationItem.route) { navController.graph.startDestinationRoute?.let { route -> popUpTo(route) {