Convert create backup dialog to a screen
Allows us more flexibility in adding more options/explanations in the future.
This commit is contained in:
parent
634ceeec50
commit
00b2853d3d
8 changed files with 209 additions and 174 deletions
|
@ -1,6 +1,5 @@
|
|||
package eu.kanade.presentation.more.settings.screen
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
|
@ -13,11 +12,9 @@ import androidx.annotation.StringRes
|
|||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
|
@ -27,41 +24,34 @@ import androidx.compose.runtime.mutableIntStateOf
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.more.settings.Preference
|
||||
import eu.kanade.presentation.more.settings.screen.data.CreateBackupScreen
|
||||
import eu.kanade.presentation.more.settings.widget.BasePreferenceWidget
|
||||
import eu.kanade.presentation.more.settings.widget.PrefsHorizontalPadding
|
||||
import eu.kanade.presentation.permissions.PermissionRequestHelper
|
||||
import eu.kanade.presentation.util.relativeTimeSpanString
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.backup.BackupConst
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateJob
|
||||
import eu.kanade.tachiyomi.data.backup.BackupFileValidator
|
||||
import eu.kanade.tachiyomi.data.backup.BackupRestoreJob
|
||||
import eu.kanade.tachiyomi.data.backup.models.Backup
|
||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.coroutines.launch
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.util.lang.launchNonCancellable
|
||||
import tachiyomi.core.util.lang.withUIContext
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.backup.service.BackupPreferences
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.presentation.core.components.LabeledCheckbox
|
||||
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
||||
import tachiyomi.presentation.core.util.collectAsState
|
||||
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||
import tachiyomi.presentation.core.util.isScrolledToStart
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
|
@ -131,124 +121,11 @@ object SettingsDataScreen : SearchableSettings {
|
|||
|
||||
@Composable
|
||||
private fun getCreateBackupPref(): Preference.PreferenceItem.TextPreference {
|
||||
val scope = rememberCoroutineScope()
|
||||
val context = LocalContext.current
|
||||
|
||||
var flag by rememberSaveable { mutableIntStateOf(0) }
|
||||
val chooseBackupDir = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.CreateDocument("application/*"),
|
||||
) {
|
||||
if (it != null) {
|
||||
context.contentResolver.takePersistableUriPermission(
|
||||
it,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
|
||||
)
|
||||
BackupCreateJob.startNow(context, it, flag)
|
||||
}
|
||||
flag = 0
|
||||
}
|
||||
var showCreateDialog by rememberSaveable { mutableStateOf(false) }
|
||||
if (showCreateDialog) {
|
||||
CreateBackupDialog(
|
||||
onConfirm = {
|
||||
showCreateDialog = false
|
||||
flag = it
|
||||
try {
|
||||
chooseBackupDir.launch(Backup.getFilename())
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
flag = 0
|
||||
context.toast(R.string.file_picker_error)
|
||||
}
|
||||
},
|
||||
onDismissRequest = { showCreateDialog = false },
|
||||
)
|
||||
}
|
||||
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
return Preference.PreferenceItem.TextPreference(
|
||||
title = stringResource(R.string.pref_create_backup),
|
||||
subtitle = stringResource(R.string.pref_create_backup_summ),
|
||||
onClick = {
|
||||
scope.launch {
|
||||
if (!BackupCreateJob.isManualJobRunning(context)) {
|
||||
if (DeviceUtil.isMiui && DeviceUtil.isMiuiOptimizationDisabled()) {
|
||||
context.toast(R.string.restore_miui_warning, Toast.LENGTH_LONG)
|
||||
}
|
||||
showCreateDialog = true
|
||||
} else {
|
||||
context.toast(R.string.backup_in_progress)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CreateBackupDialog(
|
||||
onConfirm: (flag: Int) -> Unit,
|
||||
onDismissRequest: () -> Unit,
|
||||
) {
|
||||
val choices = remember {
|
||||
mapOf(
|
||||
BackupConst.BACKUP_CATEGORY to R.string.categories,
|
||||
BackupConst.BACKUP_CHAPTER to R.string.chapters,
|
||||
BackupConst.BACKUP_TRACK to R.string.track,
|
||||
BackupConst.BACKUP_HISTORY to R.string.history,
|
||||
BackupConst.BACKUP_APP_PREFS to R.string.app_settings,
|
||||
BackupConst.BACKUP_SOURCE_PREFS to R.string.source_settings,
|
||||
)
|
||||
}
|
||||
val flags = remember { choices.keys.toMutableStateList() }
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
title = { Text(text = stringResource(R.string.backup_choice)) },
|
||||
text = {
|
||||
Box {
|
||||
val state = rememberLazyListState()
|
||||
ScrollbarLazyColumn(state = state) {
|
||||
item {
|
||||
LabeledCheckbox(
|
||||
label = stringResource(R.string.manga),
|
||||
checked = true,
|
||||
onCheckedChange = {},
|
||||
)
|
||||
}
|
||||
choices.forEach { (k, v) ->
|
||||
item {
|
||||
val isSelected = flags.contains(k)
|
||||
LabeledCheckbox(
|
||||
label = stringResource(v),
|
||||
checked = isSelected,
|
||||
onCheckedChange = {
|
||||
if (it) {
|
||||
flags.add(k)
|
||||
} else {
|
||||
flags.remove(k)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!state.isScrolledToStart()) HorizontalDivider(modifier = Modifier.align(Alignment.TopCenter))
|
||||
if (!state.isScrolledToEnd()) HorizontalDivider(modifier = Modifier.align(Alignment.BottomCenter))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismissRequest) {
|
||||
Text(text = stringResource(R.string.action_cancel))
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
val flag = flags.fold(initial = 0, operation = { a, b -> a or b })
|
||||
onConfirm(flag)
|
||||
},
|
||||
) {
|
||||
Text(text = stringResource(R.string.action_ok))
|
||||
}
|
||||
},
|
||||
onClick = { navigator.push(CreateBackupScreen()) },
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -336,7 +213,7 @@ object SettingsDataScreen : SearchableSettings {
|
|||
},
|
||||
) {
|
||||
if (it == null) {
|
||||
error = InvalidRestore(message = context.getString(R.string.file_null_uri_error))
|
||||
context.toast(R.string.file_null_uri_error)
|
||||
return@rememberLauncherForActivityResult
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
package eu.kanade.presentation.more.settings.screen.data
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateJob
|
||||
import eu.kanade.tachiyomi.data.backup.models.Backup
|
||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.coroutines.flow.update
|
||||
import tachiyomi.presentation.core.components.LabeledCheckbox
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
|
||||
class CreateBackupScreen : Screen() {
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val context = LocalContext.current
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val model = rememberScreenModel { CreateBackupScreenModel() }
|
||||
val state by model.state.collectAsState()
|
||||
|
||||
val chooseBackupDir = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.CreateDocument("application/*"),
|
||||
) {
|
||||
if (it != null) {
|
||||
context.contentResolver.takePersistableUriPermission(
|
||||
it,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
|
||||
)
|
||||
model.createBackup(context, it)
|
||||
navigator.pop()
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
AppBar(
|
||||
title = stringResource(R.string.pref_create_backup),
|
||||
navigateUp = navigator::pop,
|
||||
scrollBehavior = it,
|
||||
)
|
||||
},
|
||||
) { contentPadding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(contentPadding)
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = MaterialTheme.padding.medium),
|
||||
) {
|
||||
item {
|
||||
LabeledCheckbox(
|
||||
label = stringResource(R.string.manga),
|
||||
checked = true,
|
||||
onCheckedChange = {},
|
||||
enabled = false,
|
||||
)
|
||||
}
|
||||
BackupChoices.forEach { (k, v) ->
|
||||
item {
|
||||
LabeledCheckbox(
|
||||
label = stringResource(v),
|
||||
checked = state.flags.contains(k),
|
||||
onCheckedChange = {
|
||||
model.toggleFlag(k)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalDivider()
|
||||
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||
.fillMaxWidth(),
|
||||
onClick = {
|
||||
if (!BackupCreateJob.isManualJobRunning(context)) {
|
||||
if (DeviceUtil.isMiui && DeviceUtil.isMiuiOptimizationDisabled()) {
|
||||
context.toast(R.string.restore_miui_warning, Toast.LENGTH_LONG)
|
||||
}
|
||||
try {
|
||||
chooseBackupDir.launch(Backup.getFilename())
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
context.toast(R.string.file_picker_error)
|
||||
}
|
||||
} else {
|
||||
context.toast(R.string.backup_in_progress)
|
||||
}
|
||||
},
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.action_create),
|
||||
color = MaterialTheme.colorScheme.onPrimary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class CreateBackupScreenModel : StateScreenModel<CreateBackupScreenModel.State>(State()) {
|
||||
|
||||
fun toggleFlag(flag: Int) {
|
||||
mutableState.update {
|
||||
if (it.flags.contains(flag)) {
|
||||
it.copy(flags = it.flags - flag)
|
||||
} else {
|
||||
it.copy(flags = it.flags + flag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createBackup(context: Context, uri: Uri) {
|
||||
val flags = state.value.flags.fold(initial = 0, operation = { a, b -> a or b })
|
||||
BackupCreateJob.startNow(context, uri, flags)
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class State(
|
||||
val flags: Set<Int> = BackupChoices.keys,
|
||||
)
|
||||
}
|
||||
|
||||
private val BackupChoices = mapOf(
|
||||
BackupCreateFlags.BACKUP_CATEGORY to R.string.categories,
|
||||
BackupCreateFlags.BACKUP_CHAPTER to R.string.chapters,
|
||||
BackupCreateFlags.BACKUP_TRACK to R.string.track,
|
||||
BackupCreateFlags.BACKUP_HISTORY to R.string.history,
|
||||
BackupCreateFlags.BACKUP_APP_PREFS to R.string.app_settings,
|
||||
BackupCreateFlags.BACKUP_SOURCE_PREFS to R.string.source_settings,
|
||||
)
|
|
@ -1,24 +0,0 @@
|
|||
package eu.kanade.tachiyomi.data.backup
|
||||
|
||||
// Filter options
|
||||
internal object BackupConst {
|
||||
const val BACKUP_CATEGORY = 0x1
|
||||
const val BACKUP_CATEGORY_MASK = 0x1
|
||||
|
||||
const val BACKUP_CHAPTER = 0x2
|
||||
const val BACKUP_CHAPTER_MASK = 0x2
|
||||
|
||||
const val BACKUP_HISTORY = 0x4
|
||||
const val BACKUP_HISTORY_MASK = 0x4
|
||||
|
||||
const val BACKUP_TRACK = 0x8
|
||||
const val BACKUP_TRACK_MASK = 0x8
|
||||
|
||||
const val BACKUP_APP_PREFS = 0x10
|
||||
const val BACKUP_APP_PREFS_MASK = 0x10
|
||||
|
||||
const val BACKUP_SOURCE_PREFS = 0x20
|
||||
const val BACKUP_SOURCE_PREFS_MASK = 0x20
|
||||
|
||||
const val BACKUP_ALL = 0x3F
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package eu.kanade.tachiyomi.data.backup
|
||||
|
||||
internal object BackupCreateFlags {
|
||||
const val BACKUP_CATEGORY = 0x1
|
||||
const val BACKUP_CHAPTER = 0x2
|
||||
const val BACKUP_HISTORY = 0x4
|
||||
const val BACKUP_TRACK = 0x8
|
||||
const val BACKUP_APP_PREFS = 0x10
|
||||
const val BACKUP_SOURCE_PREFS = 0x20
|
||||
|
||||
const val AutomaticDefaults = BACKUP_CATEGORY or
|
||||
BACKUP_CHAPTER or
|
||||
BACKUP_HISTORY or
|
||||
BACKUP_TRACK or
|
||||
BACKUP_APP_PREFS or
|
||||
BACKUP_SOURCE_PREFS
|
||||
}
|
|
@ -41,7 +41,7 @@ class BackupCreateJob(private val context: Context, workerParams: WorkerParamete
|
|||
val backupPreferences = Injekt.get<BackupPreferences>()
|
||||
val uri = inputData.getString(LOCATION_URI_KEY)?.toUri()
|
||||
?: backupPreferences.backupsDirectory().get().toUri()
|
||||
val flags = inputData.getInt(BACKUP_FLAGS_KEY, BackupConst.BACKUP_ALL)
|
||||
val flags = inputData.getInt(BACKUP_FLAGS_KEY, BackupCreateFlags.AutomaticDefaults)
|
||||
|
||||
try {
|
||||
setForeground(getForegroundInfo())
|
||||
|
|
|
@ -5,18 +5,12 @@ import android.content.Context
|
|||
import android.net.Uri
|
||||
import com.hippo.unifile.UniFile
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_APP_PREFS
|
||||
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_APP_PREFS_MASK
|
||||
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY
|
||||
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY_MASK
|
||||
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CHAPTER
|
||||
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CHAPTER_MASK
|
||||
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_HISTORY
|
||||
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_HISTORY_MASK
|
||||
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_SOURCE_PREFS
|
||||
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_SOURCE_PREFS_MASK
|
||||
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_TRACK
|
||||
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_TRACK_MASK
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_APP_PREFS
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_CATEGORY
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_CHAPTER
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_HISTORY
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_SOURCE_PREFS
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_TRACK
|
||||
import eu.kanade.tachiyomi.data.backup.models.Backup
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupChapter
|
||||
|
@ -161,7 +155,7 @@ class BackupCreator(
|
|||
*/
|
||||
private suspend fun backupCategories(options: Int): List<BackupCategory> {
|
||||
// Check if user wants category information in backup
|
||||
return if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) {
|
||||
return if (options and BACKUP_CATEGORY == BACKUP_CATEGORY) {
|
||||
getCategories.await()
|
||||
.filterNot(Category::isSystemCategory)
|
||||
.map(backupCategoryMapper)
|
||||
|
@ -188,7 +182,7 @@ class BackupCreator(
|
|||
val mangaObject = BackupManga.copyFrom(manga)
|
||||
|
||||
// Check if user wants chapter information in backup
|
||||
if (options and BACKUP_CHAPTER_MASK == BACKUP_CHAPTER) {
|
||||
if (options and BACKUP_CHAPTER == BACKUP_CHAPTER) {
|
||||
// Backup all the chapters
|
||||
handler.awaitList {
|
||||
chaptersQueries.getChaptersByMangaId(
|
||||
|
@ -202,7 +196,7 @@ class BackupCreator(
|
|||
}
|
||||
|
||||
// Check if user wants category information in backup
|
||||
if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) {
|
||||
if (options and BACKUP_CATEGORY == BACKUP_CATEGORY) {
|
||||
// Backup categories for this manga
|
||||
val categoriesForManga = getCategories.await(manga.id)
|
||||
if (categoriesForManga.isNotEmpty()) {
|
||||
|
@ -211,7 +205,7 @@ class BackupCreator(
|
|||
}
|
||||
|
||||
// Check if user wants track information in backup
|
||||
if (options and BACKUP_TRACK_MASK == BACKUP_TRACK) {
|
||||
if (options and BACKUP_TRACK == BACKUP_TRACK) {
|
||||
val tracks = handler.awaitList { manga_syncQueries.getTracksByMangaId(manga.id, backupTrackMapper) }
|
||||
if (tracks.isNotEmpty()) {
|
||||
mangaObject.tracking = tracks
|
||||
|
@ -219,7 +213,7 @@ class BackupCreator(
|
|||
}
|
||||
|
||||
// Check if user wants history information in backup
|
||||
if (options and BACKUP_HISTORY_MASK == BACKUP_HISTORY) {
|
||||
if (options and BACKUP_HISTORY == BACKUP_HISTORY) {
|
||||
val historyByMangaId = getHistory.await(manga.id)
|
||||
if (historyByMangaId.isNotEmpty()) {
|
||||
val history = historyByMangaId.map { history ->
|
||||
|
@ -236,13 +230,13 @@ class BackupCreator(
|
|||
}
|
||||
|
||||
private fun backupAppPreferences(flags: Int): List<BackupPreference> {
|
||||
if (flags and BACKUP_APP_PREFS_MASK != BACKUP_APP_PREFS) return emptyList()
|
||||
if (flags and BACKUP_APP_PREFS != BACKUP_APP_PREFS) return emptyList()
|
||||
|
||||
return preferenceStore.getAll().toBackupPreferences()
|
||||
}
|
||||
|
||||
private fun backupSourcePreferences(flags: Int): List<BackupSourcePreferences> {
|
||||
if (flags and BACKUP_SOURCE_PREFS_MASK != BACKUP_SOURCE_PREFS) return emptyList()
|
||||
if (flags and BACKUP_SOURCE_PREFS != BACKUP_SOURCE_PREFS) return emptyList()
|
||||
|
||||
return sourceManager.getCatalogueSources()
|
||||
.filterIsInstance<ConfigurableSource>()
|
||||
|
|
|
@ -484,6 +484,7 @@
|
|||
<string name="pref_backup_directory">Backup location</string>
|
||||
<string name="pref_backup_interval">Automatic backup frequency</string>
|
||||
<string name="pref_backup_slots">Maximum automatic backups</string>
|
||||
<string name="action_create">Create</string>
|
||||
<string name="backup_created">Backup created</string>
|
||||
<string name="invalid_backup_file">Invalid backup file</string>
|
||||
<string name="invalid_backup_file_missing_manga">Backup does not contain any library entries.</string>
|
||||
|
@ -880,7 +881,7 @@
|
|||
<string name="file_select_cover">Select cover image</string>
|
||||
<string name="file_select_backup">Select backup file</string>
|
||||
<string name="file_picker_error">No file picker app found</string>
|
||||
<string name="file_null_uri_error">File picker failed to return file to app</string>
|
||||
<string name="file_null_uri_error">No file selected</string>
|
||||
|
||||
<!--UpdateCheck-->
|
||||
<string name="update_check_confirm">Download</string>
|
||||
|
|
|
@ -21,6 +21,7 @@ fun LabeledCheckbox(
|
|||
label: String,
|
||||
checked: Boolean,
|
||||
onCheckedChange: (Boolean) -> Unit,
|
||||
enabled: Boolean = true,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
|
@ -37,6 +38,7 @@ fun LabeledCheckbox(
|
|||
Checkbox(
|
||||
checked = checked,
|
||||
onCheckedChange = null,
|
||||
enabled = enabled,
|
||||
)
|
||||
|
||||
Text(text = label)
|
||||
|
|
Reference in a new issue