diff --git a/app/src/main/java/org/andbootmgr/app/CreatePartFlow.kt b/app/src/main/java/org/andbootmgr/app/CreatePartFlow.kt index a7fcdde5..2083d035 100644 --- a/app/src/main/java/org/andbootmgr/app/CreatePartFlow.kt +++ b/app/src/main/java/org/andbootmgr/app/CreatePartFlow.kt @@ -184,7 +184,7 @@ private class CreatePartDataHolder(val vm: WizardActivityState): ProgressListene fun lateInit() { noobMode = LocalContext.current.getSharedPreferences("abm", 0).getBoolean("noob_mode", BuildConfig.DEFAULT_NOOB_MODE) meta = SDUtils.generateMeta(vm.deviceInfo) - (meta?.s?.find { vm.activity.intent.getLongExtra("part_sid", -1L) == it.startSector } as SDUtils.Partition.FreeSpace?)?.also { p = it } + p = (meta?.s?.find { vm.mvm.wizardCompatSid == it.startSector } as SDUtils.Partition.FreeSpace?)!! } fun painterFromRtype(type: String): @Composable () -> Painter { diff --git a/app/src/main/java/org/andbootmgr/app/MainActivity.kt b/app/src/main/java/org/andbootmgr/app/MainActivity.kt index 2464975e..77643cfa 100644 --- a/app/src/main/java/org/andbootmgr/app/MainActivity.kt +++ b/app/src/main/java/org/andbootmgr/app/MainActivity.kt @@ -1,6 +1,5 @@ package org.andbootmgr.app -import android.content.Intent import android.net.Uri import android.os.Build import android.os.Bundle @@ -12,7 +11,9 @@ import androidx.activity.compose.setContent import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -27,13 +28,12 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalDrawerSheet import androidx.compose.material3.ModalNavigationDrawer import androidx.compose.material3.NavigationDrawerItem import androidx.compose.material3.Scaffold -import androidx.compose.material3.Surface import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberDrawerState import androidx.compose.runtime.Composable @@ -76,25 +76,26 @@ class MainActivityState(val activity: MainActivity?) { var wizardCompat by mutableStateOf(null) fun startFlow(flow: String) { + unmountBootset() wizardCompat = flow } var wizardCompatSid: Long? = null fun startCreateFlow(freeSpace: SDUtils.Partition.FreeSpace) { - wizardCompat = "create_part" wizardCompatSid = freeSpace.startSector + startFlow("create_part") } var wizardCompatE: String? = null fun startUpdateFlow(e: String) { - wizardCompat = "update" wizardCompatE = e + startFlow("update") } var wizardCompatPid: Int? = null fun startBackupAndRestoreFlow(partition: SDUtils.Partition) { - wizardCompat = "backup_restore" wizardCompatPid = partition.id + startFlow("backup_restore") } var noobMode by mutableStateOf(false) @@ -136,6 +137,22 @@ class MainActivityState(val activity: MainActivity?) { } } + // This will be called on startup, and after StayAlive work completes. + fun init() { + if (!StayAliveService.isRunning) { + val installed = deviceInfo?.isInstalled(logic!!) + if (installed == true) { + mountBootset() + } else { + Log.i("ABM", "not installed, not trying to mount") + } + if (deviceInfo != null) { + isOk = installed!! && deviceInfo!!.isBooted(logic!!) && + !(!logic!!.mounted || deviceInfo!!.isCorrupt(logic!!)) + } + } + } + fun mountBootset() { logic!!.mountBootset(deviceInfo!!) loadDefaultCfg() @@ -202,14 +219,6 @@ class MainActivity : ComponentActivity() { val vm = MainActivityState(this) vm.logic = DeviceLogic(this) CoroutineScope(Dispatchers.IO).launch { - if (Shell.getCachedShell() == null) { - Shell.enableVerboseLogging = BuildConfig.DEBUG - Shell.setDefaultBuilder( - Shell.Builder.create() - .setFlags(FLAG_MOUNT_MASTER or FLAG_REDIRECT_STDERR) - .setTimeout(30) - ) - } launch { vm.noobMode = this@MainActivity.getSharedPreferences("abm", 0) @@ -217,48 +226,74 @@ class MainActivity : ComponentActivity() { } // TODO I/O on app startup is meh, but can we avoid it? val di = async { JsonDeviceInfoFactory(vm.activity!!).get(Build.DEVICE) } - val shell = Shell.getShell() // blocking - if (shell.isRoot && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - Shell.cmd("pm grant $packageName ${android.Manifest.permission.POST_NOTIFICATIONS}") - .submit() - } - // == temp migration code start == - launch { - if (Shell.cmd("mountpoint -q /data/abm/bootset").exec().isSuccess) { - Shell.cmd("umount /data/abm/bootset").exec() + if (Shell.getCachedShell() == null) { + Shell.enableVerboseLogging = BuildConfig.DEBUG + Shell.setDefaultBuilder( + Shell.Builder.create() + .setFlags(FLAG_MOUNT_MASTER or FLAG_REDIRECT_STDERR) + .setTimeout(30) + ) + val shell = Shell.getShell() // blocking + if (shell.isRoot && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + Shell.cmd("pm grant $packageName ${android.Manifest.permission.POST_NOTIFICATIONS}") + .submit() } - SuFile.open("/data/abm").let { - if (it.exists()) - Shell.cmd("rm -rf /data/abm").exec() + // == temp migration code start == + launch { + if (Shell.cmd("mountpoint -q /data/abm/bootset").exec().isSuccess) { + Shell.cmd("umount /data/abm/bootset").exec() + } + SuFile.open("/data/abm").let { + if (it.exists()) + Shell.cmd("rm -rf /data/abm").exec() + } + SuFile.open(filesDir.parentFile!!, "assets").let { + if (it.exists()) + Shell.cmd("rm -rf ${filesDir.parentFile!!.resolve("assets").absolutePath}") + .exec() + } } + // == temp migration code end == } - // == temp migration code end == vm.deviceInfo = di.await() // blocking - val installed = vm.deviceInfo?.isInstalled(vm.logic!!) - if (installed == true) { - vm.mountBootset() - } else { - Log.i("ABM", "not installed, not trying to mount") - } - if (vm.deviceInfo != null) { - vm.isOk = installed!! && vm.deviceInfo!!.isBooted(vm.logic!!) && - !(!vm.logic!!.mounted || vm.deviceInfo!!.isCorrupt(vm.logic!!)) - } + vm.init() withContext(Dispatchers.Main) { setContent { // TODO allow rotating device while viewing logs without loosing logs (will require rememberSavable) - if (remember { StayAliveService.isRunning }) { - DisposableEffect(Unit) { - window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) - onDispose { window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) } - } - Terminal(null, null) - } else if (vm.wizardCompat != null) { - WizardCompat(vm, vm.wizardCompat!!) - } else { - val navController = rememberNavController() - AppContent(vm, navController) { - NavGraph(vm, navController, it) + AbmTheme { + var showTerminal by remember { mutableStateOf(StayAliveService.isRunning) } + if (showTerminal) { + var canFinish by remember { mutableStateOf(false) } + DisposableEffect(Unit) { + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + onDispose { window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) } + } + Column(modifier = Modifier.fillMaxSize()) { + Terminal(null, { canFinish = true }, null) + Row(modifier = Modifier.fillMaxWidth()) { + TextButton(onClick = { + }, modifier = Modifier.weight(1f, true)) { + Text("") // This button is useless. + } + TextButton(onClick = { + if (canFinish) { + CoroutineScope(Dispatchers.IO).launch { + vm.init() + showTerminal = false + } + } + }, modifier = Modifier.weight(1f, true)) { + Text(if (canFinish) stringResource(R.string.finish) else "") + } + } + } + } else if (vm.wizardCompat != null) { + WizardCompat(vm, vm.wizardCompat!!) + } else { + val navController = rememberNavController() + AppContent(vm, navController) { + NavGraph(vm, navController, it) + } } } } @@ -292,104 +327,102 @@ fun AppContent(vm: MainActivityState, navController: NavHostController, val scope = rememberCoroutineScope() var fabhint by remember { mutableStateOf(false) } val navBackStackEntry by navController.currentBackStackEntryAsState() + val currentRoute = navBackStackEntry?.destination?.route ?: "start" val fab = @Composable { - if (vm.noobMode && vm.isOk && navBackStackEntry!!.destination.route == "start") { + if (vm.noobMode && vm.isOk && currentRoute == "start") { FloatingActionButton(onClick = { fabhint = true }) { Icon(Icons.Default.Add, stringResource(R.string.add_icon_content_desc)) } } } - AbmTheme { - // A surface container using the 'background' color from the theme - Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) { - ModalNavigationDrawer( - drawerContent = { - ModalDrawerSheet { - NavigationDrawerItem( - label = { Text(stringResource(R.string.home)) }, - selected = navBackStackEntry!!.destination.route == "start", - onClick = { - scope.launch { - navController.navigate("start") { - launchSingleTop = true - } - drawerState.close() - } - }, - modifier = Modifier.padding(start = 8.dp, end = 8.dp, top = 8.dp) - ) - if (vm.isOk) { - NavigationDrawerItem( - label = { Text(stringResource(R.string.themes)) }, - selected = navBackStackEntry!!.destination.route == "themes", - onClick = { - scope.launch { - navController.navigate("themes") { - launchSingleTop = true - } - drawerState.close() - } - }, - modifier = Modifier.padding(start = 8.dp, end = 8.dp, top = 8.dp) - ) - NavigationDrawerItem( - label = { Text(stringResource(R.string.settings)) }, - selected = navBackStackEntry!!.destination.route == "settings", - onClick = { - scope.launch { - navController.navigate("settings") { - launchSingleTop = true - } - drawerState.close() - } - }, - modifier = Modifier.padding(start = 8.dp, end = 8.dp, top = 8.dp) - ) + ModalNavigationDrawer( + drawerContent = { + ModalDrawerSheet { + NavigationDrawerItem( + label = { Text(stringResource(R.string.home)) }, + selected = currentRoute == "start", + onClick = { + scope.launch { + navController.navigate("start") { + launchSingleTop = true + } + drawerState.close() } - } - }, - drawerState = drawerState, - content = { - if (fabhint) { - AlertDialog(onDismissRequest = { fabhint = false }, text = { - Text(stringResource(R.string.select_free_space)) - }, confirmButton = { - Button(onClick = { fabhint = false }) { - Text(stringResource(R.string.ok)) + }, + modifier = Modifier.padding(start = 8.dp, end = 8.dp, top = 8.dp) + ) + if (vm.isOk) { + NavigationDrawerItem( + label = { Text(stringResource(R.string.themes)) }, + selected = currentRoute == "themes", + onClick = { + scope.launch { + navController.navigate("themes") { + launchSingleTop = true + } + drawerState.close() } - }) - } - Scaffold( - topBar = { - CenterAlignedTopAppBar( - title = { - Text(stringResource(R.string.app_name)) - }, - colors = TopAppBarDefaults.centerAlignedTopAppBarColors(), - navigationIcon = { - IconButton(content = { - Icon( - imageVector = Icons.Filled.Menu, - contentDescription = stringResource(R.string.menu) - ) - }, onClick = { - scope.launch { drawerState.open() } - }) - }) }, - content = view, - floatingActionButton = fab, - modifier = Modifier.fillMaxWidth() + modifier = Modifier.padding(start = 8.dp, end = 8.dp, top = 8.dp) + ) + NavigationDrawerItem( + label = { Text(stringResource(R.string.settings)) }, + selected = currentRoute == "settings", + onClick = { + scope.launch { + navController.navigate("settings") { + launchSingleTop = true + } + drawerState.close() + } + }, + modifier = Modifier.padding(start = 8.dp, end = 8.dp, top = 8.dp) ) } + } + }, + drawerState = drawerState, + content = { + if (fabhint) { + AlertDialog(onDismissRequest = { fabhint = false }, text = { + Text(stringResource(R.string.select_free_space)) + }, confirmButton = { + Button(onClick = { fabhint = false }) { + Text(stringResource(R.string.ok)) + } + }) + } + Scaffold( + topBar = { + CenterAlignedTopAppBar( + title = { + Text(stringResource(R.string.app_name)) + }, + colors = TopAppBarDefaults.centerAlignedTopAppBarColors(), + navigationIcon = { + IconButton(content = { + Icon( + imageVector = Icons.Filled.Menu, + contentDescription = stringResource(R.string.menu) + ) + }, onClick = { + scope.launch { drawerState.open() } + }) + }) + }, + content = view, + floatingActionButton = fab, + modifier = Modifier.fillMaxWidth() ) } - } + ) } @Composable private fun NavGraph(vm: MainActivityState, navController: NavHostController, it: PaddingValues) { - NavHost(navController = navController, startDestination = "start", modifier = Modifier.padding(it).fillMaxSize()) { + NavHost(navController = navController, startDestination = "start", modifier = Modifier + .padding(it) + .fillMaxSize()) { composable("start") { Start(vm) } @@ -406,9 +439,11 @@ private fun NavGraph(vm: MainActivityState, navController: NavHostController, it @Composable private fun Preview() { val vm = MainActivityState(null) - AppContent(vm, rememberNavController()) { - Box(modifier = Modifier.padding(it)) { - Start(vm) + AbmTheme { + AppContent(vm, rememberNavController()) { + Box(modifier = Modifier.padding(it)) { + Start(vm) + } } } } \ No newline at end of file diff --git a/app/src/main/java/org/andbootmgr/app/UpdateFlow.kt b/app/src/main/java/org/andbootmgr/app/UpdateFlow.kt index dc3a8e3d..9fadc291 100644 --- a/app/src/main/java/org/andbootmgr/app/UpdateFlow.kt +++ b/app/src/main/java/org/andbootmgr/app/UpdateFlow.kt @@ -87,7 +87,7 @@ private fun Start(u: UpdateFlowDataHolder) { Log.e("ABM", Log.getStackTraceString(e)) } } - val toFind = u.vm.activity.intent.getStringExtra("entryFilename") ?: "null" + val toFind = u.vm.mvm.wizardCompatE!! u.e = entries.entries.find { it.value.absolutePath == toFind }!!.also { u.ef = it.value }.key CoroutineScope(Dispatchers.IO).launch { diff --git a/app/src/main/java/org/andbootmgr/app/WizardActivity.kt b/app/src/main/java/org/andbootmgr/app/WizardActivity.kt index 23a8d6c8..71774ff8 100644 --- a/app/src/main/java/org/andbootmgr/app/WizardActivity.kt +++ b/app/src/main/java/org/andbootmgr/app/WizardActivity.kt @@ -2,6 +2,7 @@ package org.andbootmgr.app import android.net.Uri import android.view.WindowManager +import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -55,6 +56,9 @@ fun WizardCompat(mvm: MainActivityState, flow: String) { val vm = remember { WizardActivityState(mvm) } vm.navController = rememberNavController() val wizardPages = remember(flow) { WizardPageFactory(vm).get(flow) } + BackHandler { + vm.onPrev.value.invoke(vm) + } Column(modifier = Modifier.fillMaxSize()) { NavHost( navController = vm.navController, @@ -120,6 +124,7 @@ class WizardActivityState(val mvm: MainActivityState) { mvm.wizardCompatE = null mvm.wizardCompatPid = null mvm.wizardCompatSid = null + mvm.mountBootset() } fun copy(inputStream: InputStream, outputStream: OutputStream): Long { diff --git a/app/src/main/java/org/andbootmgr/app/themes/Themes.kt b/app/src/main/java/org/andbootmgr/app/themes/Themes.kt index 65afef35..3fbbcb0e 100644 --- a/app/src/main/java/org/andbootmgr/app/themes/Themes.kt +++ b/app/src/main/java/org/andbootmgr/app/themes/Themes.kt @@ -53,6 +53,7 @@ import kotlinx.coroutines.launch import org.andbootmgr.app.AppContent import org.andbootmgr.app.MainActivityState import org.andbootmgr.app.R +import org.andbootmgr.app.util.AbmTheme /* uint32_t win_bg_color; @@ -323,9 +324,11 @@ class ThemeViewModel(val mvm: MainActivityState) : ViewModel() { @Composable fun ThemePreview() { val vm = MainActivityState(null) - AppContent(vm, rememberNavController()) { - Box(modifier = Modifier.padding(it)) { - Themes(vm.theme) + AbmTheme { + AppContent(vm, rememberNavController()) { + Box(modifier = Modifier.padding(it)) { + Themes(vm.theme) + } } } } \ No newline at end of file diff --git a/app/src/main/java/org/andbootmgr/app/util/StayAliveService.kt b/app/src/main/java/org/andbootmgr/app/util/StayAliveService.kt index ac0446ce..8a9be37b 100644 --- a/app/src/main/java/org/andbootmgr/app/util/StayAliveService.kt +++ b/app/src/main/java/org/andbootmgr/app/util/StayAliveService.kt @@ -13,6 +13,10 @@ import android.util.Log import androidx.core.app.NotificationChannelCompat import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.LifecycleObserver +import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleService import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.delay @@ -62,9 +66,11 @@ class StayAliveService : LifecycleService(), IStayAlive { lifecycleScope.launch { wakeLock.acquire() try { + Log.i(TAG, "Starting work...") this@StayAliveService.work!!.invoke(this@StayAliveService) + Log.i(TAG, "Done working!") isWorkDone = true - onDone!!.invoke() + onDone?.invoke() } finally { wakeLock.release() } @@ -141,6 +147,7 @@ class StayAliveService : LifecycleService(), IStayAlive { } override fun onDestroy() { + Log.i(TAG, "Goodbye!") super.onDestroy() if (!destroyed) { if (!isRunning) throw IllegalStateException("excepted isRunning to be true for non-destroyed service") @@ -166,12 +173,16 @@ private interface Provider { } class StayAliveConnection(inContext: Context, - private val onConnected: (IStayAlive) -> Unit) : ServiceConnection { + lifecycleOwner: LifecycleOwner, + private val doWhenDone: (() -> Unit)?, + private val onConnected: (IStayAlive) -> Unit) + : ServiceConnection, DefaultLifecycleObserver { companion object { @SuppressLint("StaticFieldLeak") // application context private var currentConn: StayAliveConnection? = null } private val context = inContext.applicationContext + private var provider: Provider? = null init { if (currentConn != null) { @@ -183,26 +194,33 @@ class StayAliveConnection(inContext: Context, this, Context.BIND_IMPORTANT or Context.BIND_AUTO_CREATE ) + lifecycleOwner.lifecycle.addObserver(this) } override fun onServiceConnected(name: ComponentName?, inService: IBinder?) { val provider = inService as Provider + this.provider = provider val service = provider.service val onDone = { + onServiceDisconnected(null) provider.finish() - provider.onDone = null - context.unbindService(this) - currentConn = null + doWhenDone?.invoke(); Unit } + onConnected(service) if (provider.isWorkDone) { onDone() } else { provider.onDone = onDone } - onConnected(service) } override fun onServiceDisconnected(name: ComponentName?) { - // Do nothing + context.unbindService(this) + provider?.onDone = null + currentConn = null + } + + override fun onDestroy(owner: LifecycleOwner) { + onServiceDisconnected(null) } } \ No newline at end of file diff --git a/app/src/main/java/org/andbootmgr/app/util/Terminal.kt b/app/src/main/java/org/andbootmgr/app/util/Terminal.kt index 74152049..2866b118 100644 --- a/app/src/main/java/org/andbootmgr/app/util/Terminal.kt +++ b/app/src/main/java/org/andbootmgr/app/util/Terminal.kt @@ -14,10 +14,12 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -129,21 +131,28 @@ private class BudgetCallbackList(private val scope: CoroutineScope, } /* Monospace auto-scrolling text view, fed using MutableList, catching exceptions and running logic on a different thread */ +@OptIn(ExperimentalCoroutinesApi::class) @Composable -fun Terminal(logFile: String? = null, action: (suspend (MutableList) -> Unit)?) { +fun Terminal(logFile: String? = null, doWhenDone: (() -> Unit)? = null, + action: (suspend (MutableList) -> Unit)?) { val scrollH = rememberScrollState() val scrollV = rememberScrollState() val scope = rememberCoroutineScope() val text = remember { mutableStateOf("") } val ctx = LocalContext.current.applicationContext + val lo = LocalLifecycleOwner.current LaunchedEffect(Unit) { if (action == null && logFile != null) { throw IllegalArgumentException("logFile must be null if action is null") } - StayAliveConnection(ctx) { service -> + if (action != null && doWhenDone != null) { + throw IllegalArgumentException("Don't use both action and doWhenDone") + } + StayAliveConnection(ctx, lo, doWhenDone) { service -> if (action != null) { + val logDispatcher = Dispatchers.IO.limitedParallelism(1) val log = logFile?.let { FileOutputStream(File(ctx.externalCacheDir, it)) } - val s = BudgetCallbackList(CoroutineScope(Dispatchers.IO), log) + val s = BudgetCallbackList(CoroutineScope(logDispatcher), log) s.cb = { element -> scope.launch { text.value += element + "\n" @@ -161,7 +170,7 @@ fun Terminal(logFile: String? = null, action: (suspend (MutableList) -> s.add(ctx.getString(R.string.dev_details)) s.add(Log.getStackTraceString(e)) } - withContext(Dispatchers.IO) { + withContext(logDispatcher) { log?.close() } } diff --git a/app/src/main/java/org/andbootmgr/app/util/Theme.kt b/app/src/main/java/org/andbootmgr/app/util/Theme.kt index 3281dcb2..4ae20d4e 100644 --- a/app/src/main/java/org/andbootmgr/app/util/Theme.kt +++ b/app/src/main/java/org/andbootmgr/app/util/Theme.kt @@ -3,8 +3,10 @@ package org.andbootmgr.app.util import android.annotation.TargetApi import android.os.Build import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.* import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @Composable @@ -14,16 +16,25 @@ fun AbmTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () dynamicColor && darkTheme -> @TargetApi(Build.VERSION_CODES.S) { dynamicDarkColorScheme(LocalContext.current) } + dynamicColor && !darkTheme -> @TargetApi(Build.VERSION_CODES.S) { dynamicLightColorScheme(LocalContext.current) } + darkTheme -> darkColorScheme() else -> lightColorScheme() } MaterialTheme( - colorScheme = colorScheme, - typography = Typography(), - content = content + colorScheme = colorScheme, + typography = Typography(), + content = { + // A surface container using the 'background' color from the theme + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background, + content = content + ) + } ) } \ No newline at end of file