Skip to content

Commit 7989bbf

Browse files
authored
Merge pull request #478 from synonymdev/fix/foreground-server-starting
fix: LightningNodeService startup
2 parents 58cbf0a + b079e1e commit 7989bbf

File tree

3 files changed

+68
-8
lines changed

3 files changed

+68
-8
lines changed

app/src/main/java/to/bitkit/ui/ContentView.kt

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,16 +186,21 @@ fun ContentView(
186186
val context = LocalContext.current
187187
val lifecycle = LocalLifecycleOwner.current.lifecycle
188188

189+
val walletUiState by walletViewModel.walletState.collectAsStateWithLifecycle()
190+
val lightningState by walletViewModel.lightningState.collectAsStateWithLifecycle()
191+
val nodeLifecycleState = lightningState.nodeLifecycleState
192+
193+
val isRecoveryMode by walletViewModel.isRecoveryMode.collectAsStateWithLifecycle()
194+
val notificationsGranted by settingsViewModel.notificationsGranted.collectAsStateWithLifecycle()
195+
val walletExists = walletUiState.walletExists
196+
189197
// Effects on app entering fg (ON_START) / bg (ON_STOP)
190198
DisposableEffect(lifecycle) {
191-
// TODO ADAPT THIS LOGIC TO WORK WITH LightningNodeService
192199
val observer = LifecycleEventObserver { _, event ->
193200
when (event) {
194201
Lifecycle.Event.ON_START -> {
195-
try {
202+
if (walletExists && !isRecoveryMode) {
196203
walletViewModel.start()
197-
} catch (e: Throwable) {
198-
Logger.error("Failed to start wallet", e)
199204
}
200205

201206
val pendingTransaction = NewTransactionSheetDetails.load(context)
@@ -208,6 +213,14 @@ fun ContentView(
208213
blocktankViewModel.refreshOrders()
209214
}
210215

216+
Lifecycle.Event.ON_STOP -> {
217+
if (walletExists && !isRecoveryMode && !notificationsGranted) {
218+
// App backgrounded without notification permission - stop node
219+
walletViewModel.stop()
220+
}
221+
// If notificationsGranted=true, service keeps node running
222+
}
223+
211224
else -> Unit
212225
}
213226
}
@@ -242,9 +255,6 @@ fun ContentView(
242255
}
243256
}
244257

245-
val walletUiState by walletViewModel.uiState.collectAsStateWithLifecycle()
246-
val nodeLifecycleState = walletUiState.nodeLifecycleState
247-
248258
var walletIsInitializing by remember { mutableStateOf(nodeLifecycleState == NodeLifecycleState.Initializing) }
249259
var walletInitShouldFinish by remember { mutableStateOf(false) }
250260

app/src/main/java/to/bitkit/ui/MainActivity.kt

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import androidx.navigation.compose.rememberNavController
2525
import androidx.navigation.toRoute
2626
import dagger.hilt.android.AndroidEntryPoint
2727
import kotlinx.coroutines.CoroutineScope
28+
import kotlinx.coroutines.flow.map
2829
import kotlinx.coroutines.launch
2930
import kotlinx.serialization.Serializable
3031
import to.bitkit.androidServices.LightningNodeService
@@ -45,6 +46,7 @@ import to.bitkit.ui.sheets.NewTransactionSheet
4546
import to.bitkit.ui.theme.AppThemeSurface
4647
import to.bitkit.ui.utils.composableWithDefaultTransitions
4748
import to.bitkit.ui.utils.enableAppEdgeToEdge
49+
import to.bitkit.utils.Logger
4850
import to.bitkit.viewmodels.ActivityListViewModel
4951
import to.bitkit.viewmodels.AppViewModel
5052
import to.bitkit.viewmodels.BackupsViewModel
@@ -78,7 +80,7 @@ class MainActivity : FragmentActivity() {
7880
importance = NotificationManager.IMPORTANCE_LOW
7981
)
8082
appViewModel.handleDeeplinkIntent(intent)
81-
startForegroundService(Intent(this, LightningNodeService::class.java))
83+
8284
installSplashScreen()
8385
enableAppEdgeToEdge()
8486
setContent {
@@ -89,6 +91,21 @@ class MainActivity : FragmentActivity() {
8991
) {
9092
val scope = rememberCoroutineScope()
9193
val isRecoveryMode by walletViewModel.isRecoveryMode.collectAsStateWithLifecycle()
94+
val notificationsGranted by settingsViewModel.notificationsGranted.collectAsStateWithLifecycle()
95+
val walletExists by walletViewModel.walletState
96+
.map { it.walletExists }
97+
.collectAsStateWithLifecycle(initialValue = walletViewModel.walletExists)
98+
99+
LaunchedEffect(
100+
walletExists,
101+
isRecoveryMode,
102+
notificationsGranted
103+
) {
104+
if (walletExists && !isRecoveryMode && notificationsGranted) {
105+
tryStartForegroundService()
106+
}
107+
}
108+
92109
if (!walletViewModel.walletExists && !isRecoveryMode) {
93110
OnboardingNav(
94111
startupNavController = rememberNavController(),
@@ -170,6 +187,27 @@ class MainActivity : FragmentActivity() {
170187
setIntent(intent)
171188
appViewModel.handleDeeplinkIntent(intent)
172189
}
190+
191+
override fun onDestroy() {
192+
super.onDestroy()
193+
if (!settingsViewModel.notificationsGranted.value) {
194+
runCatching {
195+
stopService(Intent(this, LightningNodeService::class.java))
196+
}
197+
}
198+
}
199+
200+
/**
201+
* Attempts to start the LightningNodeService if it's not already running.
202+
*/
203+
private fun tryStartForegroundService() {
204+
runCatching {
205+
Logger.debug("Attempting to start LightningNodeService", context = "MainActivity")
206+
startForegroundService(Intent(this, LightningNodeService::class.java))
207+
}.onFailure { error ->
208+
Logger.error("Failed to start LightningNodeService", error, context = "MainActivity")
209+
}
210+
}
173211
}
174212

175213
@Composable

app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,18 @@ class WalletViewModel @Inject constructor(
153153
}
154154
}
155155

156+
fun stop() {
157+
if (!walletExists) return
158+
159+
viewModelScope.launch(bgDispatcher) {
160+
lightningRepo.stop()
161+
.onFailure { error ->
162+
Logger.error("Node stop error", error)
163+
ToastEventBus.send(error)
164+
}
165+
}
166+
}
167+
156168
suspend fun observeLdkWallet() {
157169
walletRepo.observeLdkWallet()
158170
}

0 commit comments

Comments
 (0)