@@ -2,6 +2,7 @@ package com.github.capntrips.kernelflasher
2
2
3
3
import android.animation.ObjectAnimator
4
4
import android.animation.PropertyValuesHolder
5
+ import android.app.Activity
5
6
import android.content.ComponentName
6
7
import android.content.Intent
7
8
import android.content.ServiceConnection
@@ -16,11 +17,27 @@ import androidx.activity.compose.BackHandler
16
17
import androidx.activity.compose.setContent
17
18
import androidx.compose.animation.AnimatedVisibilityScope
18
19
import androidx.compose.animation.ExperimentalAnimationApi
20
+ import androidx.compose.foundation.layout.Arrangement
21
+ import androidx.compose.foundation.layout.Column
22
+ import androidx.compose.foundation.layout.padding
19
23
import androidx.compose.material.ExperimentalMaterialApi
24
+ import androidx.compose.material.TextButton
25
+ import androidx.compose.material3.AlertDialog
20
26
import androidx.compose.material3.ExperimentalMaterial3Api
27
+ import androidx.compose.material3.MaterialTheme
28
+ import androidx.compose.material3.Text
21
29
import androidx.compose.runtime.Composable
30
+ import androidx.compose.runtime.LaunchedEffect
31
+ import androidx.compose.runtime.getValue
32
+ import androidx.compose.runtime.mutableStateOf
33
+ import androidx.compose.runtime.remember
34
+ import androidx.compose.runtime.setValue
35
+ import androidx.compose.ui.Modifier
36
+ import androidx.compose.ui.platform.LocalContext
22
37
import androidx.compose.ui.res.stringResource
38
+ import androidx.compose.ui.text.font.FontWeight
23
39
import androidx.compose.ui.unit.ExperimentalUnitApi
40
+ import androidx.compose.ui.unit.dp
24
41
import androidx.core.animation.doOnEnd
25
42
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
26
43
import androidx.core.view.WindowCompat
@@ -30,6 +47,7 @@ import androidx.navigation.NavBackStackEntry
30
47
import androidx.navigation.compose.NavHost
31
48
import androidx.navigation.compose.composable
32
49
import androidx.navigation.compose.rememberNavController
50
+ import com.github.capntrips.kernelflasher.ui.components.DialogButton
33
51
import com.github.capntrips.kernelflasher.ui.screens.RefreshableScreen
34
52
import com.github.capntrips.kernelflasher.ui.screens.backups.BackupsContent
35
53
import com.github.capntrips.kernelflasher.ui.screens.backups.SlotBackupsContent
@@ -49,7 +67,7 @@ import com.topjohnwu.superuser.ipc.RootService
49
67
import com.topjohnwu.superuser.nio.FileSystemManager
50
68
import kotlinx.serialization.ExperimentalSerializationApi
51
69
import java.io.File
52
-
70
+ import kotlin.system.exitProcess
53
71
54
72
@ExperimentalAnimationApi
55
73
@ExperimentalMaterialApi
@@ -185,6 +203,20 @@ class MainActivity : ComponentActivity() {
185
203
MainViewModel (application, fileSystemManager, navController)
186
204
}
187
205
val mainViewModel = viewModel!!
206
+
207
+ val context = LocalContext .current
208
+ val dialogData = viewModel!! .updateDialogData
209
+ LaunchedEffect (Unit ) {
210
+ AppUpdater .checkForUpdate(
211
+ context.applicationContext,
212
+ BuildConfig .VERSION_NAME
213
+ ) { title, lines, confirm ->
214
+ viewModel!! .showUpdateDialog(title, lines, confirm)
215
+ }
216
+ }
217
+
218
+ var showExitDialog by remember { mutableStateOf(false ) }
219
+
188
220
KernelFlasherTheme {
189
221
if (! mainViewModel.hasError) {
190
222
mainListener = MainListener {
@@ -195,11 +227,15 @@ class MainActivity : ComponentActivity() {
195
227
val backupsViewModel = mainViewModel.backups
196
228
val updatesViewModel = mainViewModel.updates
197
229
val rebootViewModel = mainViewModel.reboot
198
- BackHandler (enabled = mainViewModel.isRefreshing, onBack = {})
230
+ BackHandler (enabled = ! mainViewModel.isRefreshing, onBack = {})
231
+ // New back handler for exit
232
+ BackHandler (enabled = true ) {
233
+ showExitDialog = true
234
+ }
199
235
val slotContentA: @Composable AnimatedVisibilityScope .(NavBackStackEntry ) -> Unit = { backStackEntry ->
200
236
val slotSuffix = " _a"
201
237
val slotViewModel = slotViewModelA
202
- if (slotViewModel!! .wasFlashSuccess != null && listOf (" slot{slotSuffix}" , " slot" ).any { navController.currentDestination!! .route.equals(it) }) {
238
+ if (slotViewModel!! .wasFlashSuccess.value != null && listOf (" slot{slotSuffix}" , " slot" ).any { navController.currentDestination!! .route.equals(it) }) {
203
239
slotViewModel.clearFlash(this @MainActivity)
204
240
}
205
241
RefreshableScreen (mainViewModel, navController, swipeEnabled = true ) {
@@ -210,7 +246,7 @@ class MainActivity : ComponentActivity() {
210
246
val slotContentB: @Composable AnimatedVisibilityScope .(NavBackStackEntry ) -> Unit = { backStackEntry ->
211
247
val slotSuffix = " _b"
212
248
val slotViewModel = slotViewModelB
213
- if (slotViewModel!! .wasFlashSuccess != null && listOf (" slot{slotSuffix}" , " slot" ).any { navController.currentDestination!! .route.equals(it) }) {
249
+ if (slotViewModel!! .wasFlashSuccess.value != null && listOf (" slot{slotSuffix}" , " slot" ).any { navController.currentDestination!! .route.equals(it) }) {
214
250
slotViewModel.clearFlash(this @MainActivity)
215
251
}
216
252
RefreshableScreen (mainViewModel, navController, swipeEnabled = true ) {
@@ -221,7 +257,7 @@ class MainActivity : ComponentActivity() {
221
257
val slotContent: @Composable AnimatedVisibilityScope .(NavBackStackEntry ) -> Unit = { backStackEntry ->
222
258
val slotSuffix = " "
223
259
val slotViewModel = slotViewModelA
224
- if (slotViewModel!! .wasFlashSuccess != null && listOf (" slot{slotSuffix}" , " slot" ).any { navController.currentDestination!! .route.equals(it) }) {
260
+ if (slotViewModel!! .wasFlashSuccess.value != null && listOf (" slot{slotSuffix}" , " slot" ).any { navController.currentDestination!! .route.equals(it) }) {
225
261
slotViewModel.clearFlash(this @MainActivity)
226
262
}
227
263
RefreshableScreen (mainViewModel, navController, swipeEnabled = true ) {
@@ -424,6 +460,61 @@ class MainActivity : ComponentActivity() {
424
460
} else {
425
461
ErrorScreen (mainViewModel.error)
426
462
}
463
+
464
+ if (dialogData != null ) {
465
+ AlertDialog (
466
+ onDismissRequest = { viewModel!! .hideUpdateDialog() },
467
+ title = {
468
+ Text (
469
+ dialogData!! .title,
470
+ style = MaterialTheme .typography.titleLarge,
471
+ fontWeight = FontWeight .Bold
472
+ )
473
+ },
474
+ text = {
475
+ Column (verticalArrangement = Arrangement .spacedBy(8 .dp)) {
476
+ dialogData!! .changelog.forEach {
477
+ Text (it, fontWeight = FontWeight .Bold )
478
+ }
479
+ }
480
+ },
481
+ confirmButton = {
482
+ DialogButton (" Update APK" ) {
483
+ viewModel!! .hideUpdateDialog()
484
+ dialogData!! .onConfirm()
485
+ }
486
+ },
487
+ dismissButton = {
488
+ DialogButton (" CANCEL" ) {
489
+ viewModel!! .hideUpdateDialog()
490
+ }
491
+ },
492
+ modifier = Modifier .padding(16 .dp)
493
+ )
494
+ }
495
+
496
+ if (showExitDialog) {
497
+ AlertDialog (
498
+ onDismissRequest = { showExitDialog = false },
499
+ title = { Text (" Exit App" ) },
500
+ text = { Text (" Are you sure you want to exit?" ) },
501
+ confirmButton = {
502
+ TextButton (onClick = {
503
+ (context as ? Activity )?.let {
504
+ it.finishAffinity()
505
+ exitProcess(0 )
506
+ }
507
+ }) {
508
+ Text (" Yes" )
509
+ }
510
+ },
511
+ dismissButton = {
512
+ TextButton (onClick = { showExitDialog = false }) {
513
+ Text (" No" )
514
+ }
515
+ }
516
+ )
517
+ }
427
518
}
428
519
}
429
520
}
0 commit comments