From 08058c02977be4ce17bbe1eb3f50d6d2b1fe5847 Mon Sep 17 00:00:00 2001 From: Ren Amamiya Date: Thu, 28 May 2026 15:54:25 +0700 Subject: [PATCH] . --- .../androidMain/kotlin/su/reya/coop/App.kt | 28 ++++++++----------- .../kotlin/su/reya/coop/MainActivity.kt | 26 +++++++++++++---- .../commonMain/kotlin/su/reya/coop/Nostr.kt | 8 ++---- .../kotlin/su/reya/coop/NostrViewModel.kt | 10 +++---- 4 files changed, 40 insertions(+), 32 deletions(-) diff --git a/composeApp/src/androidMain/kotlin/su/reya/coop/App.kt b/composeApp/src/androidMain/kotlin/su/reya/coop/App.kt index dbb56bf..09469a7 100644 --- a/composeApp/src/androidMain/kotlin/su/reya/coop/App.kt +++ b/composeApp/src/androidMain/kotlin/su/reya/coop/App.kt @@ -39,14 +39,12 @@ import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.navigation.toRoute import kotlinx.coroutines.launch -import su.reya.coop.coop.storage.SecretStore import su.reya.coop.screens.ChatScreen import su.reya.coop.screens.HomeScreen import su.reya.coop.screens.ImportScreen @@ -72,7 +70,10 @@ val LocalNavController = staticCompositionLocalOf { @OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class) @Composable -fun App(openRoomId: Long? = null) { +fun App( + viewModel: NostrViewModel, + openRoomId: Long? = null +) { val context = LocalContext.current val navController = rememberNavController() val scope = rememberCoroutineScope() @@ -81,10 +82,6 @@ fun App(openRoomId: Long? = null) { // Snackbar val snackbarHostState = remember { SnackbarHostState() } - // Initialize Nostr View Model and Secret Store - val secretStore = remember { SecretStore(context) } - val viewModel: NostrViewModel = viewModel { NostrViewModel(NostrManager.instance, secretStore) } - // Enabled the dynamic color scheme val colorScheme = when { android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S -> { @@ -101,12 +98,6 @@ fun App(openRoomId: Long? = null) { } } - LaunchedEffect(openRoomId) { - if (openRoomId != null) { - navController.navigate(Screen.Chat(openRoomId)) - } - } - MaterialExpressiveTheme( colorScheme = colorScheme, typography = Typography(), @@ -123,15 +114,20 @@ fun App(openRoomId: Long? = null) { LaunchedEffect(emptySecret) { // Navigate to the home screen if the secret is already set - if (emptySecret == false) { + if (emptySecret == false && openRoomId == null) { navController.navigate(Screen.Home) { popUpTo(Screen.Onboarding) { inclusive = true } } } } - // Show loading screen while initializing - if (emptySecret == null) return@CompositionLocalProvider + LaunchedEffect(openRoomId) { + if (openRoomId != null) { + navController.navigate(Screen.Chat(openRoomId)) { + popUpTo(Screen.Home) { saveState = true } + } + } + } // Show the relay setup dialog if the msg relay list is empty if (isRelayListEmpty) { diff --git a/composeApp/src/androidMain/kotlin/su/reya/coop/MainActivity.kt b/composeApp/src/androidMain/kotlin/su/reya/coop/MainActivity.kt index 22fac53..ff7d854 100644 --- a/composeApp/src/androidMain/kotlin/su/reya/coop/MainActivity.kt +++ b/composeApp/src/androidMain/kotlin/su/reya/coop/MainActivity.kt @@ -7,26 +7,40 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen +import su.reya.coop.coop.storage.SecretStore class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { - installSplashScreen() + val splashScreen = installSplashScreen() enableEdgeToEdge() super.onCreate(savedInstanceState) - val intent = Intent(this, NostrForegroundService::class.java) - + val serviceIntent = Intent(this, NostrForegroundService::class.java) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - startForegroundService(intent) + startForegroundService(serviceIntent) } else { - startService(intent) + startService(serviceIntent) } val roomId = intent.getLongExtra("room_id", -1L) + val secretStore = SecretStore(this) + val viewModel = NostrViewModel(NostrManager.instance, secretStore) + + splashScreen.setKeepOnScreenCondition { + viewModel.emptySecret.value == null + } setContent { - App(openRoomId = if (roomId != -1L) roomId else null) + App( + viewModel = viewModel, + openRoomId = if (roomId != -1L) roomId else null + ) } } + + override fun onNewIntent(intent: Intent) { + super.onNewIntent(intent) + setIntent(intent) + } } diff --git a/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt b/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt index 6204303..c56555c 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt @@ -6,13 +6,13 @@ import io.ktor.client.plugins.websocket.WebSockets import io.ktor.client.request.get import io.ktor.client.statement.HttpResponse import kotlinx.coroutines.Job -import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch +import kotlinx.coroutines.supervisorScope import rust.nostr.sdk.AckPolicy import rust.nostr.sdk.Alphabet import rust.nostr.sdk.AsyncNostrSigner @@ -170,8 +170,6 @@ class Nostr { suspend fun setSigner(new: AsyncNostrSigner) { try { signer.switch(new) - // Fetch metadata for current user - getUserMetadata() } catch (e: Exception) { throw IllegalStateException("Failed to set signer: ${e.message}", e) } @@ -244,10 +242,10 @@ class Nostr { onContactListUpdate: (List) -> Unit, onNewMessage: (UnsignedEvent) -> Unit, onSubscriptionClose: () -> Unit, - ) = coroutineScope { + ) = supervisorScope { val now = Timestamp.now() val processedEvent = mutableSetOf() - val notifications = client?.notifications() ?: return@coroutineScope + val notifications = client?.notifications() ?: return@supervisorScope var eoseTrackerJob: Job? = null diff --git a/shared/src/commonMain/kotlin/su/reya/coop/NostrViewModel.kt b/shared/src/commonMain/kotlin/su/reya/coop/NostrViewModel.kt index b353f76..058eb3d 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/NostrViewModel.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/NostrViewModel.kt @@ -82,7 +82,7 @@ class NostrViewModel( // Observe new events from the Nostr client runObserver() - + // Wait and merge metadata requests into a single batch runMetadataBatching() } @@ -201,9 +201,6 @@ class NostrViewModel( private fun login() { viewModelScope.launch { - // Wait until the client is ready - nostr.waitUntilInitialized() - // Get user's signer secret val secret = secretStore.get("user_signer") @@ -249,6 +246,9 @@ class NostrViewModel( _isPartialProcessedGiftWrap.value = true } + // Get all metadata for the current user + nostr.getUserMetadata() + // Small delay to ensure all relays are connected delay(3000) @@ -261,7 +261,7 @@ class NostrViewModel( break } - delay(1000) + delay(500) } } }