@@ -2,7 +2,6 @@ package de.mm20.launcher2.ui.common
|
||||
|
||||
import android.net.Uri
|
||||
import android.text.format.DateUtils
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
@@ -13,14 +12,12 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.backup.BackupCompatibility
|
||||
import de.mm20.launcher2.backup.BackupComponent
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||
import de.mm20.launcher2.ui.component.LargeMessage
|
||||
@@ -38,7 +35,6 @@ fun RestoreBackupSheet(
|
||||
}
|
||||
|
||||
val state by viewModel.state
|
||||
val selectedComponents by viewModel.selectedComponents
|
||||
val compatibility by viewModel.compatibility
|
||||
|
||||
BottomSheetDialog(
|
||||
@@ -52,7 +48,6 @@ fun RestoreBackupSheet(
|
||||
|
||||
if (state == RestoreBackupState.Ready && compatibility != BackupCompatibility.Incompatible) {
|
||||
Button(
|
||||
enabled = selectedComponents.isNotEmpty(),
|
||||
onClick = { viewModel.restore() }) {
|
||||
Text(stringResource(R.string.preference_restore))
|
||||
}
|
||||
@@ -138,60 +133,6 @@ fun RestoreBackupSheet(
|
||||
)
|
||||
)
|
||||
}
|
||||
Text(
|
||||
stringResource(R.string.restore_select_components),
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
modifier = Modifier.padding(top = 8.dp, bottom = 4.dp)
|
||||
)
|
||||
val components by viewModel.availableComponents
|
||||
for (component in components) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
viewModel.toggleComponent(
|
||||
component
|
||||
)
|
||||
}
|
||||
.padding(vertical = 4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
imageVector = when (component) {
|
||||
BackupComponent.Favorites -> Icons.Rounded.Star
|
||||
BackupComponent.Settings -> Icons.Rounded.Settings
|
||||
BackupComponent.SearchActions -> Icons.Rounded.ArrowOutward
|
||||
BackupComponent.Widgets -> Icons.Rounded.Widgets
|
||||
BackupComponent.Customizations -> Icons.Rounded.Edit
|
||||
BackupComponent.Themes -> Icons.Rounded.Palette
|
||||
},
|
||||
contentDescription = null
|
||||
)
|
||||
Text(
|
||||
text = stringResource(
|
||||
when (component) {
|
||||
BackupComponent.Favorites -> R.string.backup_component_favorites
|
||||
BackupComponent.Settings -> R.string.backup_component_settings
|
||||
BackupComponent.SearchActions -> R.string.backup_component_searchactions
|
||||
BackupComponent.Widgets -> R.string.backup_component_widgets
|
||||
BackupComponent.Customizations -> R.string.backup_component_customizations
|
||||
BackupComponent.Themes -> R.string.backup_component_themes
|
||||
}
|
||||
),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = 16.dp)
|
||||
)
|
||||
Checkbox(
|
||||
checked = selectedComponents.contains(
|
||||
component
|
||||
),
|
||||
onCheckedChange = {
|
||||
viewModel.toggleComponent(component)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.backup.BackupCompatibility
|
||||
import de.mm20.launcher2.backup.BackupComponent
|
||||
import de.mm20.launcher2.backup.BackupManager
|
||||
import de.mm20.launcher2.backup.BackupMetadata
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -21,9 +20,6 @@ class RestoreBackupSheetVM : ViewModel(), KoinComponent {
|
||||
val state = mutableStateOf(RestoreBackupState.Parsing)
|
||||
val metadata = mutableStateOf<BackupMetadata?>(null)
|
||||
val compatibility = mutableStateOf<BackupCompatibility?>(null)
|
||||
val selectedComponents = mutableStateOf(setOf<BackupComponent>())
|
||||
|
||||
val availableComponents = mutableStateOf(emptyList<BackupComponent>())
|
||||
|
||||
fun setInputUri(uri: Uri) {
|
||||
restoreUri = uri
|
||||
@@ -32,33 +28,20 @@ class RestoreBackupSheetVM : ViewModel(), KoinComponent {
|
||||
val metadata = backupManager.readBackupMeta(uri)
|
||||
if (metadata == null) {
|
||||
state.value = RestoreBackupState.InvalidFile
|
||||
availableComponents.value = emptyList()
|
||||
} else {
|
||||
state.value = RestoreBackupState.Ready
|
||||
compatibility.value = backupManager.checkCompatibility(metadata)
|
||||
availableComponents.value = metadata.components.toList().sortedBy { it.ordinal }
|
||||
}
|
||||
selectedComponents.value = metadata?.components ?: emptySet()
|
||||
this@RestoreBackupSheetVM.metadata.value = metadata
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleComponent(component: BackupComponent) {
|
||||
val components = selectedComponents.value ?: emptySet()
|
||||
if (components.contains(component)) {
|
||||
selectedComponents.value = components - component
|
||||
} else {
|
||||
selectedComponents.value = components + component
|
||||
}
|
||||
}
|
||||
|
||||
fun restore() {
|
||||
val components = selectedComponents.value ?: return
|
||||
val uri = restoreUri ?: return
|
||||
|
||||
viewModelScope.launch {
|
||||
state.value = RestoreBackupState.Restoring
|
||||
backupManager.restore(uri, components)
|
||||
backupManager.restore(uri)
|
||||
state.value = RestoreBackupState.Restored
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.backup.BackupComponent
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||
import de.mm20.launcher2.ui.component.LargeMessage
|
||||
@@ -33,20 +32,23 @@ fun CreateBackupSheet(
|
||||
|
||||
val viewModel: CreateBackupSheetVM = viewModel()
|
||||
|
||||
LaunchedEffect(null) {
|
||||
viewModel.reset()
|
||||
}
|
||||
|
||||
val components by viewModel.selectedComponents
|
||||
val state by viewModel.state
|
||||
|
||||
|
||||
val backupLauncher = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.CreateDocument("application/vnd.de.mm20.launcher2.backup"),
|
||||
onResult = {
|
||||
if (it != null) viewModel.createBackup(it)
|
||||
}
|
||||
)
|
||||
LaunchedEffect(null) {
|
||||
viewModel.reset()
|
||||
val fileName = "${
|
||||
ZonedDateTime.now().format(
|
||||
DateTimeFormatter.ISO_INSTANT
|
||||
).replace(":", "_")
|
||||
}.kvaesitso"
|
||||
backupLauncher.launch(fileName)
|
||||
}
|
||||
|
||||
val state by viewModel.state
|
||||
|
||||
BottomSheetDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
@@ -58,7 +60,6 @@ fun CreateBackupSheet(
|
||||
confirmButton = {
|
||||
if (state == CreateBackupState.Ready) {
|
||||
Button(
|
||||
enabled = components.isNotEmpty(),
|
||||
onClick = {
|
||||
val fileName = "${
|
||||
ZonedDateTime.now().format(
|
||||
@@ -87,68 +88,7 @@ fun CreateBackupSheet(
|
||||
) {
|
||||
when (state) {
|
||||
CreateBackupState.Ready -> {
|
||||
Column {
|
||||
Text(
|
||||
stringResource(R.string.backup_select_components),
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
modifier = Modifier.padding(top = 8.dp, bottom = 4.dp)
|
||||
)
|
||||
BackupableComponent(
|
||||
title = stringResource(R.string.backup_component_settings),
|
||||
icon = Icons.Rounded.Settings,
|
||||
checked = components.contains(BackupComponent.Settings),
|
||||
onCheckedChange = {
|
||||
viewModel.toggleComponent(BackupComponent.Settings)
|
||||
}
|
||||
)
|
||||
BackupableComponent(
|
||||
title = stringResource(R.string.backup_component_favorites),
|
||||
icon = Icons.Rounded.Star,
|
||||
checked = components.contains(BackupComponent.Favorites),
|
||||
onCheckedChange = {
|
||||
viewModel.toggleComponent(BackupComponent.Favorites)
|
||||
}
|
||||
)
|
||||
BackupableComponent(
|
||||
title = stringResource(R.string.backup_component_widgets),
|
||||
icon = Icons.Rounded.Widgets,
|
||||
checked = components.contains(BackupComponent.Widgets),
|
||||
onCheckedChange = {
|
||||
viewModel.toggleComponent(BackupComponent.Widgets)
|
||||
}
|
||||
)
|
||||
BackupableComponent(
|
||||
title = stringResource(R.string.backup_component_customizations),
|
||||
icon = Icons.Rounded.Edit,
|
||||
checked = components.contains(BackupComponent.Customizations),
|
||||
onCheckedChange = {
|
||||
viewModel.toggleComponent(BackupComponent.Customizations)
|
||||
}
|
||||
)
|
||||
BackupableComponent(
|
||||
title = stringResource(R.string.backup_component_searchactions),
|
||||
icon = Icons.Rounded.TravelExplore,
|
||||
checked = components.contains(BackupComponent.SearchActions),
|
||||
onCheckedChange = {
|
||||
viewModel.toggleComponent(BackupComponent.SearchActions)
|
||||
}
|
||||
)
|
||||
BackupableComponent(
|
||||
title = stringResource(R.string.backup_component_themes),
|
||||
icon = Icons.Rounded.Palette,
|
||||
checked = components.contains(BackupComponent.Themes),
|
||||
onCheckedChange = {
|
||||
viewModel.toggleComponent(BackupComponent.Themes)
|
||||
}
|
||||
)
|
||||
SmallMessage(
|
||||
modifier = Modifier
|
||||
.padding(top = 8.dp)
|
||||
.fillMaxWidth(),
|
||||
icon = Icons.Rounded.Warning,
|
||||
text = stringResource(R.string.backup_not_included)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
CreateBackupState.BackingUp -> {
|
||||
Box(
|
||||
@@ -176,36 +116,3 @@ fun CreateBackupSheet(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BackupableComponent(
|
||||
title: String,
|
||||
icon: ImageVector,
|
||||
checked: Boolean,
|
||||
onCheckedChange: (Boolean) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
onCheckedChange(!checked)
|
||||
}
|
||||
.padding(vertical = 4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = null
|
||||
)
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = 16.dp)
|
||||
)
|
||||
Checkbox(
|
||||
checked = checked,
|
||||
onCheckedChange = onCheckedChange
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.net.Uri
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.backup.BackupComponent
|
||||
import de.mm20.launcher2.backup.BackupManager
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
@@ -16,30 +15,17 @@ class CreateBackupSheetVM : ViewModel(), KoinComponent {
|
||||
|
||||
val state = mutableStateOf(CreateBackupState.Ready)
|
||||
|
||||
val selectedComponents = mutableStateOf(BackupComponent.values().toSet())
|
||||
|
||||
fun reset() {
|
||||
state.value = CreateBackupState.Ready
|
||||
}
|
||||
|
||||
fun createBackup(uri: Uri) {
|
||||
val components = selectedComponents.value ?: return
|
||||
viewModelScope.launch {
|
||||
state.value = CreateBackupState.BackingUp
|
||||
backupManager.backup(uri, components)
|
||||
backupManager.backup(uri)
|
||||
state.value = CreateBackupState.BackedUp
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleComponent(component: BackupComponent) {
|
||||
val components = selectedComponents.value ?: emptySet()
|
||||
if (components.contains(component)) {
|
||||
selectedComponents.value = components - component
|
||||
} else {
|
||||
selectedComponents.value = components + component
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum class CreateBackupState {
|
||||
|
||||
Reference in New Issue
Block a user