From 4bc4eee4c093af8e2ff1b816d422b8250219cdcd Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 24 Nov 2025 10:59:30 -0300 Subject: [PATCH 01/10] chore: create google services util --- .../ui/utils/GooglePlayServicesUtils.kt | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 app/src/main/java/to/bitkit/ui/utils/GooglePlayServicesUtils.kt diff --git a/app/src/main/java/to/bitkit/ui/utils/GooglePlayServicesUtils.kt b/app/src/main/java/to/bitkit/ui/utils/GooglePlayServicesUtils.kt new file mode 100644 index 000000000..a449cfd62 --- /dev/null +++ b/app/src/main/java/to/bitkit/ui/utils/GooglePlayServicesUtils.kt @@ -0,0 +1,31 @@ +package to.bitkit.ui.utils + +import android.content.Context +import com.google.android.gms.common.ConnectionResult +import com.google.android.gms.common.GoogleApiAvailability +import to.bitkit.utils.Logger + +object GooglePlayServicesUtils { + /** + * Checks if Google Play Services are available on the device. + * Returns true if available and up to date, false otherwise. + */ + fun isAvailable(context: Context): Boolean { + val googleApiAvailability = GoogleApiAvailability.getInstance() + val resultCode = googleApiAvailability.isGooglePlayServicesAvailable(context) + + return when (resultCode) { + ConnectionResult.SUCCESS -> { + Logger.debug("Google Play Services are available", context = "GooglePlayServicesUtils") + true + } + else -> { + Logger.debug( + "Google Play Services not available. Code: $resultCode", + context = "GooglePlayServicesUtils" + ) + false + } + } + } +} From 942b03c90498991d36c1c58f9713a3e6a596abdb Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 24 Nov 2025 11:16:39 -0300 Subject: [PATCH 02/10] fix: foreground service starting rules --- .../main/java/to/bitkit/ui/MainActivity.kt | 122 +++++++++++++++++- .../ui/utils/GooglePlayServicesUtils.kt | 38 +++--- 2 files changed, 140 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/MainActivity.kt b/app/src/main/java/to/bitkit/ui/MainActivity.kt index cab8868cf..d2071387f 100644 --- a/app/src/main/java/to/bitkit/ui/MainActivity.kt +++ b/app/src/main/java/to/bitkit/ui/MainActivity.kt @@ -9,9 +9,17 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver import androidx.compose.ui.Modifier import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.testTagsAsResourceId @@ -43,8 +51,11 @@ import to.bitkit.ui.screens.SplashScreen import to.bitkit.ui.sheets.ForgotPinSheet import to.bitkit.ui.sheets.NewTransactionSheet import to.bitkit.ui.theme.AppThemeSurface +import to.bitkit.ui.utils.GooglePlayServicesUtils +import to.bitkit.ui.utils.NotificationUtils import to.bitkit.ui.utils.composableWithDefaultTransitions import to.bitkit.ui.utils.enableAppEdgeToEdge +import to.bitkit.utils.Logger import to.bitkit.viewmodels.ActivityListViewModel import to.bitkit.viewmodels.AppViewModel import to.bitkit.viewmodels.BackupsViewModel @@ -78,7 +89,15 @@ class MainActivity : FragmentActivity() { importance = NotificationManager.IMPORTANCE_LOW ) appViewModel.handleDeeplinkIntent(intent) - startForegroundService(Intent(this, LightningNodeService::class.java)) + + // Start foreground service only if conditions are met + if (shouldStartForegroundService()) { + Logger.debug("Starting LightningNodeService", context = "MainActivity") + startForegroundService(Intent(this, LightningNodeService::class.java)) + } else { + Logger.debug("Not starting LightningNodeService - conditions not met", context = "MainActivity") + } + installSplashScreen() enableAppEdgeToEdge() setContent { @@ -88,7 +107,42 @@ class MainActivity : FragmentActivity() { } ) { val scope = rememberCoroutineScope() + val context = LocalContext.current + val lifecycleOwner = LocalLifecycleOwner.current val isRecoveryMode by walletViewModel.isRecoveryMode.collectAsStateWithLifecycle() + + // Track notification permission state + var notificationsEnabled by remember { + mutableStateOf(NotificationUtils.areNotificationsEnabled(context)) + } + + // Monitor notification permission changes on resume + DisposableEffect(lifecycleOwner) { + val observer = LifecycleEventObserver { _, event -> + if (event == Lifecycle.Event.ON_RESUME) { + val currentState = NotificationUtils.areNotificationsEnabled(context) + if (currentState != notificationsEnabled) { + notificationsEnabled = currentState + Logger.debug( + "Notification permission changed to: $currentState", + context = "MainActivity" + ) + } + } + } + lifecycleOwner.lifecycle.addObserver(observer) + onDispose { + lifecycleOwner.lifecycle.removeObserver(observer) + } + } + + // Monitor wallet state and notification permission changes + LaunchedEffect(walletViewModel.walletExists, isRecoveryMode, notificationsEnabled) { + if (walletViewModel.walletExists && !isRecoveryMode && shouldStartForegroundService()) { + tryStartForegroundService() + } + } + if (!walletViewModel.walletExists && !isRecoveryMode) { OnboardingNav( startupNavController = rememberNavController(), @@ -170,6 +224,72 @@ class MainActivity : FragmentActivity() { setIntent(intent) appViewModel.handleDeeplinkIntent(intent) } + + /** + * Attempts to start the LightningNodeService if it's not already running. + */ + private fun tryStartForegroundService() { + runCatching { + Logger.debug("Attempting to start LightningNodeService", context = "MainActivity") + startForegroundService(Intent(this, LightningNodeService::class.java)) + }.onFailure { error -> + Logger.error("Failed to start LightningNodeService", error, context = "MainActivity") + } + } + + /** + * Determines if the LightningNodeService should be started. + * Requirements: + * - Wallet must exist + * - Must NOT be in recovery mode + * - If Google Play Services available: notifications must be enabled + * - If no Google Play Services: no notification check needed + */ + private fun shouldStartForegroundService(): Boolean { + // Check if wallet exists + if (!walletViewModel.walletExists) { + Logger.debug( + "Not starting service: wallet does not exist", + context = "MainActivity.shouldStartForegroundService" + ) + return false + } + + // Check if in recovery mode + if (walletViewModel.isRecoveryMode.value) { + Logger.debug( + "Not starting service: in recovery mode", + context = "MainActivity.shouldStartForegroundService" + ) + return false + } + + // Check Google Play Services availability + val hasGooglePlayServices = GooglePlayServicesUtils.isAvailable(this) + + // If Google Play Services are available, check notification permissions + if (hasGooglePlayServices) { + val notificationsEnabled = NotificationUtils.areNotificationsEnabled(this) + if (!notificationsEnabled) { + Logger.debug( + "Not starting service: Google Play Services available but notifications not enabled", + context = "MainActivity.shouldStartForegroundService" + ) + return false + } + Logger.debug( + "Service can start: wallet exists, not in recovery mode, Google Play Services available, notifications enabled", + context = "MainActivity.shouldStartForegroundService" + ) + } else { + Logger.debug( + "Service can start: wallet exists, not in recovery mode, no Google Play Services (notification check skipped)", + context = "MainActivity.shouldStartForegroundService" + ) + } + + return true + } } @Composable diff --git a/app/src/main/java/to/bitkit/ui/utils/GooglePlayServicesUtils.kt b/app/src/main/java/to/bitkit/ui/utils/GooglePlayServicesUtils.kt index a449cfd62..99884f568 100644 --- a/app/src/main/java/to/bitkit/ui/utils/GooglePlayServicesUtils.kt +++ b/app/src/main/java/to/bitkit/ui/utils/GooglePlayServicesUtils.kt @@ -1,31 +1,31 @@ package to.bitkit.ui.utils import android.content.Context -import com.google.android.gms.common.ConnectionResult -import com.google.android.gms.common.GoogleApiAvailability +import com.google.firebase.messaging.FirebaseMessaging import to.bitkit.utils.Logger object GooglePlayServicesUtils { /** - * Checks if Google Play Services are available on the device. - * Returns true if available and up to date, false otherwise. + * Checks if Firebase Cloud Messaging (and by extension Google Play Services) is available. + * This indicates whether the device can receive FCM notifications. + * Returns true if FCM is available, false otherwise. */ fun isAvailable(context: Context): Boolean { - val googleApiAvailability = GoogleApiAvailability.getInstance() - val resultCode = googleApiAvailability.isGooglePlayServicesAvailable(context) - - return when (resultCode) { - ConnectionResult.SUCCESS -> { - Logger.debug("Google Play Services are available", context = "GooglePlayServicesUtils") - true - } - else -> { - Logger.debug( - "Google Play Services not available. Code: $resultCode", - context = "GooglePlayServicesUtils" - ) - false - } + return runCatching { + // Try to get FirebaseMessaging instance + // This will fail if Google Play Services is not available + FirebaseMessaging.getInstance() + Logger.debug( + "Firebase Messaging available (Google Play Services present)", + context = "GooglePlayServicesUtils" + ) + true + }.getOrElse { error -> + Logger.debug( + "Firebase Messaging not available: ${error.message}", + context = "GooglePlayServicesUtils" + ) + false } } } From 309849ab5235e152c529da6b7190c05310a73e5a Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 24 Nov 2025 13:36:21 -0300 Subject: [PATCH 03/10] chore: remove unnecessary call --- app/src/main/java/to/bitkit/ui/MainActivity.kt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/MainActivity.kt b/app/src/main/java/to/bitkit/ui/MainActivity.kt index d2071387f..bcbe89c51 100644 --- a/app/src/main/java/to/bitkit/ui/MainActivity.kt +++ b/app/src/main/java/to/bitkit/ui/MainActivity.kt @@ -90,14 +90,6 @@ class MainActivity : FragmentActivity() { ) appViewModel.handleDeeplinkIntent(intent) - // Start foreground service only if conditions are met - if (shouldStartForegroundService()) { - Logger.debug("Starting LightningNodeService", context = "MainActivity") - startForegroundService(Intent(this, LightningNodeService::class.java)) - } else { - Logger.debug("Not starting LightningNodeService - conditions not met", context = "MainActivity") - } - installSplashScreen() enableAppEdgeToEdge() setContent { From 3b126275b4edba6a90ae409b63eacf21eea87c56 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 24 Nov 2025 14:09:19 -0300 Subject: [PATCH 04/10] chore: get notification state --- .../main/java/to/bitkit/ui/MainActivity.kt | 42 +++---------------- 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/MainActivity.kt b/app/src/main/java/to/bitkit/ui/MainActivity.kt index bcbe89c51..0605fe8de 100644 --- a/app/src/main/java/to/bitkit/ui/MainActivity.kt +++ b/app/src/main/java/to/bitkit/ui/MainActivity.kt @@ -9,17 +9,9 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleEventObserver import androidx.compose.ui.Modifier import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.testTagsAsResourceId @@ -99,37 +91,15 @@ class MainActivity : FragmentActivity() { } ) { val scope = rememberCoroutineScope() - val context = LocalContext.current - val lifecycleOwner = LocalLifecycleOwner.current val isRecoveryMode by walletViewModel.isRecoveryMode.collectAsStateWithLifecycle() - - // Track notification permission state - var notificationsEnabled by remember { - mutableStateOf(NotificationUtils.areNotificationsEnabled(context)) - } - - // Monitor notification permission changes on resume - DisposableEffect(lifecycleOwner) { - val observer = LifecycleEventObserver { _, event -> - if (event == Lifecycle.Event.ON_RESUME) { - val currentState = NotificationUtils.areNotificationsEnabled(context) - if (currentState != notificationsEnabled) { - notificationsEnabled = currentState - Logger.debug( - "Notification permission changed to: $currentState", - context = "MainActivity" - ) - } - } - } - lifecycleOwner.lifecycle.addObserver(observer) - onDispose { - lifecycleOwner.lifecycle.removeObserver(observer) - } - } + val notificationsGranted by settingsViewModel.notificationsGranted.collectAsStateWithLifecycle() // Monitor wallet state and notification permission changes - LaunchedEffect(walletViewModel.walletExists, isRecoveryMode, notificationsEnabled) { + LaunchedEffect( + walletViewModel.walletExists, + isRecoveryMode, + notificationsGranted + ) { if (walletViewModel.walletExists && !isRecoveryMode && shouldStartForegroundService()) { tryStartForegroundService() } From c67e9d1e05c54245701b93c0d8fadfbfbc99c590 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 25 Nov 2025 07:40:31 -0300 Subject: [PATCH 05/10] chore: simplify code --- .../main/java/to/bitkit/ui/MainActivity.kt | 58 +------------------ .../ui/utils/GooglePlayServicesUtils.kt | 31 ---------- 2 files changed, 1 insertion(+), 88 deletions(-) delete mode 100644 app/src/main/java/to/bitkit/ui/utils/GooglePlayServicesUtils.kt diff --git a/app/src/main/java/to/bitkit/ui/MainActivity.kt b/app/src/main/java/to/bitkit/ui/MainActivity.kt index 0605fe8de..40a70c46b 100644 --- a/app/src/main/java/to/bitkit/ui/MainActivity.kt +++ b/app/src/main/java/to/bitkit/ui/MainActivity.kt @@ -43,8 +43,6 @@ import to.bitkit.ui.screens.SplashScreen import to.bitkit.ui.sheets.ForgotPinSheet import to.bitkit.ui.sheets.NewTransactionSheet import to.bitkit.ui.theme.AppThemeSurface -import to.bitkit.ui.utils.GooglePlayServicesUtils -import to.bitkit.ui.utils.NotificationUtils import to.bitkit.ui.utils.composableWithDefaultTransitions import to.bitkit.ui.utils.enableAppEdgeToEdge import to.bitkit.utils.Logger @@ -100,7 +98,7 @@ class MainActivity : FragmentActivity() { isRecoveryMode, notificationsGranted ) { - if (walletViewModel.walletExists && !isRecoveryMode && shouldStartForegroundService()) { + if (walletViewModel.walletExists && !isRecoveryMode && notificationsGranted) { tryStartForegroundService() } } @@ -198,60 +196,6 @@ class MainActivity : FragmentActivity() { Logger.error("Failed to start LightningNodeService", error, context = "MainActivity") } } - - /** - * Determines if the LightningNodeService should be started. - * Requirements: - * - Wallet must exist - * - Must NOT be in recovery mode - * - If Google Play Services available: notifications must be enabled - * - If no Google Play Services: no notification check needed - */ - private fun shouldStartForegroundService(): Boolean { - // Check if wallet exists - if (!walletViewModel.walletExists) { - Logger.debug( - "Not starting service: wallet does not exist", - context = "MainActivity.shouldStartForegroundService" - ) - return false - } - - // Check if in recovery mode - if (walletViewModel.isRecoveryMode.value) { - Logger.debug( - "Not starting service: in recovery mode", - context = "MainActivity.shouldStartForegroundService" - ) - return false - } - - // Check Google Play Services availability - val hasGooglePlayServices = GooglePlayServicesUtils.isAvailable(this) - - // If Google Play Services are available, check notification permissions - if (hasGooglePlayServices) { - val notificationsEnabled = NotificationUtils.areNotificationsEnabled(this) - if (!notificationsEnabled) { - Logger.debug( - "Not starting service: Google Play Services available but notifications not enabled", - context = "MainActivity.shouldStartForegroundService" - ) - return false - } - Logger.debug( - "Service can start: wallet exists, not in recovery mode, Google Play Services available, notifications enabled", - context = "MainActivity.shouldStartForegroundService" - ) - } else { - Logger.debug( - "Service can start: wallet exists, not in recovery mode, no Google Play Services (notification check skipped)", - context = "MainActivity.shouldStartForegroundService" - ) - } - - return true - } } @Composable diff --git a/app/src/main/java/to/bitkit/ui/utils/GooglePlayServicesUtils.kt b/app/src/main/java/to/bitkit/ui/utils/GooglePlayServicesUtils.kt deleted file mode 100644 index 99884f568..000000000 --- a/app/src/main/java/to/bitkit/ui/utils/GooglePlayServicesUtils.kt +++ /dev/null @@ -1,31 +0,0 @@ -package to.bitkit.ui.utils - -import android.content.Context -import com.google.firebase.messaging.FirebaseMessaging -import to.bitkit.utils.Logger - -object GooglePlayServicesUtils { - /** - * Checks if Firebase Cloud Messaging (and by extension Google Play Services) is available. - * This indicates whether the device can receive FCM notifications. - * Returns true if FCM is available, false otherwise. - */ - fun isAvailable(context: Context): Boolean { - return runCatching { - // Try to get FirebaseMessaging instance - // This will fail if Google Play Services is not available - FirebaseMessaging.getInstance() - Logger.debug( - "Firebase Messaging available (Google Play Services present)", - context = "GooglePlayServicesUtils" - ) - true - }.getOrElse { error -> - Logger.debug( - "Firebase Messaging not available: ${error.message}", - context = "GooglePlayServicesUtils" - ) - false - } - } -} From 8a704e81a1f3ad5b274c582a32049e006223df63 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 25 Nov 2025 09:14:12 -0300 Subject: [PATCH 06/10] chore: get wallet state from repo --- app/src/main/java/to/bitkit/ui/MainActivity.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/MainActivity.kt b/app/src/main/java/to/bitkit/ui/MainActivity.kt index 40a70c46b..429112731 100644 --- a/app/src/main/java/to/bitkit/ui/MainActivity.kt +++ b/app/src/main/java/to/bitkit/ui/MainActivity.kt @@ -25,6 +25,7 @@ import androidx.navigation.compose.rememberNavController import androidx.navigation.toRoute import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import kotlinx.serialization.Serializable import to.bitkit.androidServices.LightningNodeService @@ -91,14 +92,17 @@ class MainActivity : FragmentActivity() { val scope = rememberCoroutineScope() val isRecoveryMode by walletViewModel.isRecoveryMode.collectAsStateWithLifecycle() val notificationsGranted by settingsViewModel.notificationsGranted.collectAsStateWithLifecycle() + val walletExists by walletViewModel.walletState + .map { it.walletExists } + .collectAsStateWithLifecycle(initialValue = false) // Monitor wallet state and notification permission changes LaunchedEffect( - walletViewModel.walletExists, + walletExists, isRecoveryMode, notificationsGranted ) { - if (walletViewModel.walletExists && !isRecoveryMode && notificationsGranted) { + if (walletExists && !isRecoveryMode && notificationsGranted) { tryStartForegroundService() } } From e07b58e06fd975bddeb2a4080f1ec4ea457a708b Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 25 Nov 2025 13:40:41 -0300 Subject: [PATCH 07/10] fix: handle node stop when service not initialized --- app/src/main/java/to/bitkit/ui/ContentView.kt | 25 +++++++++++++------ .../to/bitkit/viewmodels/WalletViewModel.kt | 12 +++++++++ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/ContentView.kt b/app/src/main/java/to/bitkit/ui/ContentView.kt index ff177fc3b..de530ba28 100644 --- a/app/src/main/java/to/bitkit/ui/ContentView.kt +++ b/app/src/main/java/to/bitkit/ui/ContentView.kt @@ -186,16 +186,21 @@ fun ContentView( val context = LocalContext.current val lifecycle = LocalLifecycleOwner.current.lifecycle + val walletUiState by walletViewModel.walletState.collectAsStateWithLifecycle() + val lightningState by walletViewModel.lightningState.collectAsStateWithLifecycle() + val nodeLifecycleState = lightningState.nodeLifecycleState + + val isRecoveryMode by walletViewModel.isRecoveryMode.collectAsStateWithLifecycle() + val notificationsGranted by settingsViewModel.notificationsGranted.collectAsStateWithLifecycle() + val walletExists = walletUiState.walletExists + // Effects on app entering fg (ON_START) / bg (ON_STOP) DisposableEffect(lifecycle) { - // TODO ADAPT THIS LOGIC TO WORK WITH LightningNodeService val observer = LifecycleEventObserver { _, event -> when (event) { Lifecycle.Event.ON_START -> { - try { + if (walletExists && !isRecoveryMode) { walletViewModel.start() - } catch (e: Throwable) { - Logger.error("Failed to start wallet", e) } val pendingTransaction = NewTransactionSheetDetails.load(context) @@ -208,6 +213,14 @@ fun ContentView( blocktankViewModel.refreshOrders() } + Lifecycle.Event.ON_STOP -> { + if (walletExists && !isRecoveryMode && !notificationsGranted) { + // App backgrounded without notification permission - stop node + walletViewModel.stop() + } + // If notificationsGranted=true, service keeps node running + } + else -> Unit } } @@ -242,9 +255,6 @@ fun ContentView( } } - val walletUiState by walletViewModel.uiState.collectAsStateWithLifecycle() - val nodeLifecycleState = walletUiState.nodeLifecycleState - var walletIsInitializing by remember { mutableStateOf(nodeLifecycleState == NodeLifecycleState.Initializing) } var walletInitShouldFinish by remember { mutableStateOf(false) } @@ -271,7 +281,6 @@ fun ContentView( var restoreRetryCount by remember { mutableIntStateOf(0) } if (walletIsInitializing) { - // TODO ADAPT THIS LOGIC TO WORK WITH LightningNodeService if (nodeLifecycleState is NodeLifecycleState.ErrorStarting) { WalletRestoreErrorView( retryCount = restoreRetryCount, diff --git a/app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt b/app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt index 968fb83bd..2b0de8324 100644 --- a/app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt +++ b/app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt @@ -153,6 +153,18 @@ class WalletViewModel @Inject constructor( } } + fun stop() { + if (!walletExists) return + + viewModelScope.launch(bgDispatcher) { + lightningRepo.stop() + .onFailure { error -> + Logger.error("Node stop error", error) + ToastEventBus.send(error) + } + } + } + suspend fun observeLdkWallet() { walletRepo.observeLdkWallet() } From 8af25a310f052ca26ca4ebd4670168aa4d20c762 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 25 Nov 2025 13:53:49 -0300 Subject: [PATCH 08/10] fix: stop service in onDestroy if notifications are disabled --- app/src/main/java/to/bitkit/ui/MainActivity.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/main/java/to/bitkit/ui/MainActivity.kt b/app/src/main/java/to/bitkit/ui/MainActivity.kt index 429112731..64f230dbb 100644 --- a/app/src/main/java/to/bitkit/ui/MainActivity.kt +++ b/app/src/main/java/to/bitkit/ui/MainActivity.kt @@ -189,6 +189,15 @@ class MainActivity : FragmentActivity() { appViewModel.handleDeeplinkIntent(intent) } + override fun onDestroy() { + super.onDestroy() + if (!settingsViewModel.notificationsGranted.value) { + runCatching { + stopService(Intent(this, LightningNodeService::class.java)) + } + } + } + /** * Attempts to start the LightningNodeService if it's not already running. */ From 87c56355b65b1af3d419fd3069ed00f82542a55f Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 25 Nov 2025 14:04:55 -0300 Subject: [PATCH 09/10] chore: walletExists initialization --- app/src/main/java/to/bitkit/ui/MainActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/to/bitkit/ui/MainActivity.kt b/app/src/main/java/to/bitkit/ui/MainActivity.kt index 64f230dbb..5800eb6ab 100644 --- a/app/src/main/java/to/bitkit/ui/MainActivity.kt +++ b/app/src/main/java/to/bitkit/ui/MainActivity.kt @@ -94,7 +94,7 @@ class MainActivity : FragmentActivity() { val notificationsGranted by settingsViewModel.notificationsGranted.collectAsStateWithLifecycle() val walletExists by walletViewModel.walletState .map { it.walletExists } - .collectAsStateWithLifecycle(initialValue = false) + .collectAsStateWithLifecycle(initialValue = walletViewModel.walletExists) // Monitor wallet state and notification permission changes LaunchedEffect( From 201e72f7f115963c91d5021b95baf258c7844ab2 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 25 Nov 2025 14:10:16 -0300 Subject: [PATCH 10/10] chore: comments --- app/src/main/java/to/bitkit/ui/ContentView.kt | 1 + app/src/main/java/to/bitkit/ui/MainActivity.kt | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/to/bitkit/ui/ContentView.kt b/app/src/main/java/to/bitkit/ui/ContentView.kt index de530ba28..bfd4fe676 100644 --- a/app/src/main/java/to/bitkit/ui/ContentView.kt +++ b/app/src/main/java/to/bitkit/ui/ContentView.kt @@ -281,6 +281,7 @@ fun ContentView( var restoreRetryCount by remember { mutableIntStateOf(0) } if (walletIsInitializing) { + // TODO ADAPT THIS LOGIC TO WORK WITH LightningNodeService if (nodeLifecycleState is NodeLifecycleState.ErrorStarting) { WalletRestoreErrorView( retryCount = restoreRetryCount, diff --git a/app/src/main/java/to/bitkit/ui/MainActivity.kt b/app/src/main/java/to/bitkit/ui/MainActivity.kt index 5800eb6ab..90b8e9eef 100644 --- a/app/src/main/java/to/bitkit/ui/MainActivity.kt +++ b/app/src/main/java/to/bitkit/ui/MainActivity.kt @@ -96,7 +96,6 @@ class MainActivity : FragmentActivity() { .map { it.walletExists } .collectAsStateWithLifecycle(initialValue = walletViewModel.walletExists) - // Monitor wallet state and notification permission changes LaunchedEffect( walletExists, isRecoveryMode,