@@ -17,6 +17,7 @@ import androidx.compose.material3.Button
1717import androidx.compose.material3.Card
1818import androidx.compose.material3.CardDefaults
1919import androidx.compose.material3.Icon
20+ import androidx.compose.material3.ListItem
2021import androidx.compose.material3.Text
2122import androidx.compose.material3.TextField
2223import androidx.compose.runtime.Composable
@@ -45,7 +46,9 @@ import kotlinx.coroutines.Dispatchers
4546import kotlinx.coroutines.launch
4647import kotlinx.coroutines.withContext
4748import org.andbootmgr.app.util.ConfigFile
49+ import org.andbootmgr.app.util.SDLessUtils
4850import org.andbootmgr.app.util.SDUtils
51+ import org.andbootmgr.app.util.SOUtils
4952import java.io.File
5053import kotlin.collections.set
5154import kotlin.io.nameWithoutExtension
@@ -363,6 +366,7 @@ private fun OsEditor(vm: MainActivityState, parts: SDUtils.SDPartitionMeta?, e:
363366 onClose : (newPt: Boolean ) -> Unit , onOpenUpdater : () -> Unit ) {
364367 var processing by remember { mutableStateOf(false ) }
365368 var delete by remember { mutableStateOf(false ) }
369+ var backupAskPart by remember { mutableStateOf(false ) }
366370 var result by remember { mutableStateOf<Pair <String , (() - > Unit )? > ? > (null ) }
367371 AlertDialog (
368372 onDismissRequest = {
@@ -380,8 +384,11 @@ private fun OsEditor(vm: MainActivityState, parts: SDUtils.SDPartitionMeta?, e:
380384 enabled = e.has(" xupdate" ) && ! e[" xupdate" ].isNullOrBlank()) {
381385 Text (stringResource(R .string.update))
382386 }
383- // TODO add button to open backup & restore tool (by asking which partition should
384- // be backed up / restored)
387+ Button (onClick = {
388+ backupAskPart = true
389+ }, enabled = e.has(" xparts" ) && ! e[" xparts" ].isNullOrBlank() && e[" xparts" ] != " real" ) {
390+ Text (stringResource(R .string.backupnrestore))
391+ }
385392 Button (
386393 onClick = {
387394 delete = true
@@ -400,6 +407,45 @@ private fun OsEditor(vm: MainActivityState, parts: SDUtils.SDPartitionMeta?, e:
400407 }
401408 )
402409
410+ if (backupAskPart) {
411+ AlertDialog (
412+ onDismissRequest = {
413+ backupAskPart = false
414+ },
415+ title = {
416+ Text (stringResource(R .string.choose_part_to_backup))
417+ },
418+ text = {
419+ for (i in e[" xparts" ]!! .split(" :" )) {
420+ val part = parts?.dumpKernelPartition(i.toInt())
421+ val file = if (! vm.deviceInfo!! .metaonsd)
422+ File (File (vm.logic!! .abmSdLessBootset, f.nameWithoutExtension), i) else null
423+ val size = part?.let { it.size * it.meta.logicalSectorSizeBytes }
424+ ? : SuFile .open(file!! .toURI()).length()
425+ ListItem (headlineContent = {
426+ Text (stringResource(R .string.entry_space_usage,
427+ if (part != null )
428+ stringResource(R .string.part_item, i, part.name)
429+ else
430+ stringResource(R .string.part_title, i),
431+ SOUtils .humanReadableByteCountBin(size)
432+ ))
433+ }, modifier = Modifier .clickable {
434+ vm.currentWizardFlow = if (file != null )
435+ BackupRestoreFlow (null , file)
436+ else
437+ BackupRestoreFlow (i.toInt(), null )
438+ })
439+ }
440+ },
441+ confirmButton = {
442+ Button (onClick = { backupAskPart = false }) {
443+ Text (stringResource(id = R .string.cancel))
444+ }
445+ }
446+ )
447+ }
448+
403449 if (delete) {
404450 AlertDialog (
405451 onDismissRequest = {
@@ -724,15 +770,17 @@ private fun EntryEditor(vm: MainActivityState, e: ConfigFile, f: File?, onClose:
724770 val initrdE by remember { derivedStateOf { ! initrdT.matches(asciiRegex) } }
725771 var dtbT by remember { mutableStateOf(e[" dtb" ] ? : " " ) }
726772 val dtbE by remember { derivedStateOf { ! dtbT.matches(asciiRegex) } }
773+ var dtboT by remember { mutableStateOf(e[" dtbo" ] ? : " " ) }
774+ val dtboE by remember { derivedStateOf { if (vm.deviceInfo!! .havedtbo)
775+ ! dtboT.matches(asciiRegex) else false } }
727776 var optionsT by remember { mutableStateOf(e[" options" ] ? : " " ) }
728777 val optionsE by remember { derivedStateOf { ! optionsT.matches(asciiRegex) } }
729778 var xtypeT by remember { mutableStateOf(e[" xtype" ] ? : " " ) }
730779 val xtypeE by remember { derivedStateOf { ! xtypeValidValues.contains(xtypeT) } }
731780 var xpartT by remember { mutableStateOf(e[" xpart" ] ? : " " ) }
732781 val xpartE by remember { derivedStateOf { ! xpartT.matches(xpartValidValues) } }
733782 var xupdateT by remember { mutableStateOf(e[" xupdate" ] ? : " " ) }
734- // TODO dtbo editing if havedtbo
735- val isOk = ! (newFileNameErr || titleE || linuxE || initrdE || dtbE || optionsE || xtypeE || xpartE)
783+ val isOk = ! (newFileNameErr || titleE || linuxE || initrdE || dtbE || dtboE || optionsE || xtypeE || xpartE)
736784 AlertDialog (
737785 onDismissRequest = {
738786 onClose()
@@ -776,6 +824,13 @@ private fun EntryEditor(vm: MainActivityState, e: ConfigFile, f: File?, onClose:
776824 Text (stringResource(R .string.dtb))
777825 })
778826
827+ if (vm.deviceInfo!! .havedtbo)
828+ TextField (value = dtbT, onValueChange = {
829+ dtbT = it
830+ }, isError = dtbE, label = {
831+ Text (stringResource(R .string.dtbo))
832+ })
833+
779834 TextField (value = optionsT, onValueChange = {
780835 optionsT = it
781836 }, isError = optionsE, label = {
@@ -828,6 +883,8 @@ private fun EntryEditor(vm: MainActivityState, e: ConfigFile, f: File?, onClose:
828883 e[" linux" ] = linuxT
829884 e[" initrd" ] = initrdT
830885 e[" dtb" ] = dtbT
886+ if (vm.deviceInfo!! .havedtbo)
887+ e[" dtbo" ] = dtboT
831888 e[" options" ] = optionsT
832889 e[" xtype" ] = xtypeT
833890 e[" xpart" ] = xpartT
@@ -879,7 +936,8 @@ private fun BootsetTool(vm: MainActivityState) {
879936 MyInfoCard (stringResource(R .string.click2inspect), padding = 5 .dp)
880937 if (entries != null ) {
881938 for (e in entries!! .keys) {
882- val spaceUsage = null // TODO compute space usage of installed OS
939+ val spaceUsage = SDLessUtils .getSpaceUsageBytes(vm.logic!! ,
940+ entries!! [e]!! .nameWithoutExtension)
883941 Row (horizontalArrangement = Arrangement .SpaceEvenly ,
884942 verticalAlignment = Alignment .CenterVertically ,
885943 modifier = Modifier
@@ -926,7 +984,6 @@ private fun BootsetTool(vm: MainActivityState) {
926984 }
927985 }
928986 }
929- // TODO we eventually want portable partitions for !metaonsd, but not supported yet
930987 if (editEntryID != null && filterEntryView) {
931988 EntryEditor (
932989 vm, editEntryID!! , entries!! [editEntryID!! ],
0 commit comments