feat: implement basic notification #6

Merged
reya merged 6 commits from feat/notifications into master 2026-05-29 06:56:48 +00:00
4 changed files with 23 additions and 18 deletions
Showing only changes of commit ef3d5184fb - Show all commits

View File

@@ -22,7 +22,6 @@
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
android:launchMode="singleTop"
android:theme="@style/Theme.App.Starting"> android:theme="@style/Theme.App.Starting">
<intent-filter> <intent-filter>

View File

@@ -82,11 +82,13 @@ fun App(viewModel: NostrViewModel) {
// Enabled the dynamic color scheme // Enabled the dynamic color scheme
val colorScheme = when { val colorScheme = when {
// Enable the dynamic color scheme for Android 12+
android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S -> { android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S -> {
if (darkMode) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) if (darkMode) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
} }
// When dark mode is enabled, use the dark color scheme
darkMode -> darkColorScheme() darkMode -> darkColorScheme()
// Fallback to the light color scheme
else -> expressiveLightColorScheme() else -> expressiveLightColorScheme()
} }
@@ -106,22 +108,27 @@ fun App(viewModel: NostrViewModel) {
LocalSnackbarHostState provides snackbarHostState, LocalSnackbarHostState provides snackbarHostState,
LocalNavController provides navController, LocalNavController provides navController,
) { ) {
val emptySecret by viewModel.emptySecret.collectAsState(initial = null) val signerRequired by viewModel.signerRequired.collectAsState(initial = null)
val isRelayListEmpty by viewModel.isRelayListEmpty.collectAsState() val isRelayListEmpty by viewModel.isRelayListEmpty.collectAsState()
val sheetState = rememberModalBottomSheetState() val sheetState = rememberModalBottomSheetState()
LaunchedEffect(emptySecret) { LaunchedEffect(signerRequired) {
// Navigate to the home screen if the secret is already set // Navigate to the home screen if the secret is already set
if (emptySecret == false) { if (signerRequired == false) {
navController.navigate(Screen.Home) { navController.navigate(Screen.Home) {
popUpTo(Screen.Onboarding) { inclusive = true } popUpTo(Screen.Onboarding) { inclusive = true }
} }
} }
} }
// Keep the splash screen visible until the secret check is complete
if (signerRequired == null) {
return@CompositionLocalProvider
}
NavHost( NavHost(
navController = navController, navController = navController,
startDestination = if (emptySecret == false) Screen.Home else Screen.Onboarding startDestination = if (signerRequired!!) Screen.Onboarding else Screen.Home
) { ) {
composable<Screen.Onboarding> { backStackEntry -> composable<Screen.Onboarding> { backStackEntry ->
OnboardingScreen( OnboardingScreen(

View File

@@ -36,8 +36,9 @@ class MainActivity : ComponentActivity() {
startService(serviceIntent) startService(serviceIntent)
} }
// Keep the splash screen visible until the signer check is complete
splashScreen.setKeepOnScreenCondition { splashScreen.setKeepOnScreenCondition {
viewModel.emptySecret.value == null viewModel.signerRequired.value == null
} }
setContent { setContent {

View File

@@ -39,8 +39,8 @@ class NostrViewModel(
private val nostr: Nostr, private val nostr: Nostr,
private val secretStore: SecretStorage private val secretStore: SecretStorage
) : ViewModel() { ) : ViewModel() {
private val _emptySecret = MutableStateFlow<Boolean?>(null) private val _signerRequired = MutableStateFlow<Boolean?>(null)
val emptySecret = _emptySecret.asStateFlow() val signerRequired = _signerRequired.asStateFlow()
private val _isCreating = MutableStateFlow(false) private val _isCreating = MutableStateFlow(false)
val isCreating = _isCreating.asStateFlow() val isCreating = _isCreating.asStateFlow()
@@ -206,12 +206,12 @@ class NostrViewModel(
// If no secret is found, show onboarding screen // If no secret is found, show onboarding screen
if (secret == null) { if (secret == null) {
_emptySecret.value = true _signerRequired.value = true
return@launch return@launch
} }
// Update the empty secret state // Update the empty secret state
_emptySecret.value = false _signerRequired.value = false
// Handle different signer types // Handle different signer types
if (secret.startsWith("nsec1")) { if (secret.startsWith("nsec1")) {
@@ -294,7 +294,7 @@ class NostrViewModel(
viewModelScope.launch { viewModelScope.launch {
secretStore.clear("user_signer") secretStore.clear("user_signer")
nostr.signer.switch(Keys.generate()) nostr.signer.switch(Keys.generate())
_emptySecret.value = true _signerRequired.value = true
} }
} }
@@ -363,7 +363,7 @@ class NostrViewModel(
secretStore.set("user_signer", secret) secretStore.set("user_signer", secret)
// Set an empty secret state // Set an empty secret state
_emptySecret.value = false _signerRequired.value = false
} catch (e: Exception) { } catch (e: Exception) {
showError("Error: ${e.message}") showError("Error: ${e.message}")
} }
@@ -396,18 +396,16 @@ class NostrViewModel(
nostr.setSigner(keys) nostr.setSigner(keys)
secretStore.set("user_signer", secret) secretStore.set("user_signer", secret)
// Set an empty secret state // Set an empty secret state
_emptySecret.value = false _signerRequired.value = false
} else if (secret.startsWith("bunker://")) { } else if (secret.startsWith("bunker://")) {
try { try {
val appKeys = getOrInitAppKeys() val appKeys = getOrInitAppKeys()
val bunker = NostrConnectUri.parse(secret) val bunker = NostrConnectUri.parse(secret)
val timeout = Duration.parse("50s") // 50 seconds timeout val timeout = Duration.parse("50s") // 50 seconds timeout
val remote = val remote = NostrConnect(uri = bunker, appKeys, timeout, null)
NostrConnect(uri = bunker, appKeys = appKeys, timeout = timeout, null)
nostr.setSigner(remote) nostr.setSigner(remote)
secretStore.set("user_signer", secret) secretStore.set("user_signer", secret)
// Set an empty secret state _signerRequired.value = false
_emptySecret.value = false
} catch (e: Exception) { } catch (e: Exception) {
showError("Error: ${e.message}") showError("Error: ${e.message}")
} }