From 2259b25f3ffc274c1315e231d512fb614b25a69d Mon Sep 17 00:00:00 2001 From: Kgothatso Ngako Date: Mon, 27 Jul 2026 01:21:56 +0200 Subject: [PATCH] Remember scopes and repositories in MantraNavHost MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The coroutine scopes, AuxDatabaseManager, and repositories were created as plain vals in the composable body, so every recomposition recreated them — leaking the old scopes' jobs and duplicating repository instances. Wrap them in remember so they are created once per composition. Co-Authored-By: Claude Fable 5 --- .../ui/composable/navigation/MantraNavHost.kt | 62 ++++++++++++------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/press/mantra/compose/ui/composable/navigation/MantraNavHost.kt b/composeApp/src/commonMain/kotlin/press/mantra/compose/ui/composable/navigation/MantraNavHost.kt index 1a0c1236..a139f24d 100644 --- a/composeApp/src/commonMain/kotlin/press/mantra/compose/ui/composable/navigation/MantraNavHost.kt +++ b/composeApp/src/commonMain/kotlin/press/mantra/compose/ui/composable/navigation/MantraNavHost.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.lifecycle.compose.LocalLifecycleOwner @@ -112,40 +113,53 @@ fun MantraNavHost( ) { val logger = Logger.withTag("MantraNavHost") - val exceptionHandler = CoroutineExceptionHandler { _, throwable -> - logger.e("Caught exception: ${throwable.message}", throwable) + val exceptionHandler = remember { + CoroutineExceptionHandler { _, throwable -> + logger.e("Caught exception: ${throwable.message}", throwable) + } } - val applicationIOScope = CoroutineScope(Dispatchers.IO + SupervisorJob() + exceptionHandler) - val applicationMainScope = CoroutineScope(Dispatchers.Main) + val applicationIOScope = remember { CoroutineScope(Dispatchers.IO + SupervisorJob() + exceptionHandler) } + val applicationMainScope = remember { CoroutineScope(Dispatchers.Main) } val lifecycleOwner = LocalLifecycleOwner.current - val auxDatabaseManager = + val auxDatabaseManager = remember { AuxDatabaseManager(mantraGlobal) + } - val databaseNostrRepository = DatabaseNostrRepository( - database = auxDatabaseManager.auxDatabase, - applicationIOScope - ) + val databaseNostrRepository = remember { + DatabaseNostrRepository( + database = auxDatabaseManager.auxDatabase, + applicationIOScope + ) + } - val databaseChatRepository = DatabaseChatRepository( - database = auxDatabaseManager.auxDatabase, - applicationIOScope - ) + val databaseChatRepository = remember { + DatabaseChatRepository( + database = auxDatabaseManager.auxDatabase, + applicationIOScope + ) + } - val databaseMarmotRepository = DatabaseMarmotRepository( - database = auxDatabaseManager.auxDatabase, - applicationIOScope - ) - val databaseMantraRepository = DatabaseMantraRepository( - database = auxDatabaseManager.auxDatabase, - applicationIOScope - ) + val databaseMarmotRepository = remember { + DatabaseMarmotRepository( + database = auxDatabaseManager.auxDatabase, + applicationIOScope + ) + } + val databaseMantraRepository = remember { + DatabaseMantraRepository( + database = auxDatabaseManager.auxDatabase, + applicationIOScope + ) + } - val searchRepository = DatabaseSearchRepository( - database = auxDatabaseManager.auxDatabase - ) + val searchRepository = remember { + DatabaseSearchRepository( + database = auxDatabaseManager.auxDatabase + ) + } val sovereignWalletViewModel: SovereignWalletViewModel = viewModel( factory = SovereignWalletViewModel.factory(