Rename "Backup and restore" settings screen to "Data and storage"

We can house more things in here in the future, like:
- A unified storage location setting (with scoped storage)
- Sync
- Disk usage info
This commit is contained in:
arkon 2023-10-27 15:06:56 -04:00
parent d7d7a6d2fc
commit c46c39d4ae
8 changed files with 100 additions and 117 deletions

View File

@ -16,7 +16,7 @@ import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.outlined.Label
import androidx.compose.material.icons.outlined.QueryStats
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material.icons.outlined.SettingsBackupRestore
import androidx.compose.material.icons.outlined.Storage
import androidx.compose.material3.HorizontalDivider
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@ -45,7 +45,7 @@ fun MoreScreen(
onClickDownloadQueue: () -> Unit,
onClickCategories: () -> Unit,
onClickStats: () -> Unit,
onClickBackupAndRestore: () -> Unit,
onClickDataAndStorage: () -> Unit,
onClickSettings: () -> Unit,
onClickAbout: () -> Unit,
) {
@ -141,9 +141,9 @@ fun MoreScreen(
}
item {
TextPreferenceWidget(
title = stringResource(R.string.label_backup),
icon = Icons.Outlined.SettingsBackupRestore,
onPreferenceClick = onClickBackupAndRestore,
title = stringResource(R.string.label_data_storage),
icon = Icons.Outlined.Storage,
onPreferenceClick = onClickDataAndStorage,
)
}

View File

@ -14,7 +14,6 @@ import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
@ -31,7 +30,6 @@ import eu.kanade.presentation.more.settings.Preference
import eu.kanade.presentation.more.settings.screen.advanced.ClearDatabaseScreen
import eu.kanade.presentation.more.settings.screen.debug.DebugInfoScreen
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.ChapterCache
import eu.kanade.tachiyomi.data.download.DownloadCache
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
import eu.kanade.tachiyomi.network.NetworkHelper
@ -61,7 +59,6 @@ import okhttp3.Headers
import tachiyomi.core.util.lang.launchNonCancellable
import tachiyomi.core.util.lang.withUIContext
import tachiyomi.core.util.system.logcat
import tachiyomi.domain.library.service.LibraryPreferences
import tachiyomi.domain.manga.repository.MangaRepository
import tachiyomi.presentation.core.util.collectAsState
import uy.kohesive.injekt.Injekt
@ -183,40 +180,12 @@ object SettingsAdvancedScreen : SearchableSettings {
@Composable
private fun getDataGroup(): Preference.PreferenceGroup {
val scope = rememberCoroutineScope()
val context = LocalContext.current
val navigator = LocalNavigator.currentOrThrow
val libraryPreferences = remember { Injekt.get<LibraryPreferences>() }
val chapterCache = remember { Injekt.get<ChapterCache>() }
var readableSizeSema by remember { mutableIntStateOf(0) }
val readableSize = remember(readableSizeSema) { chapterCache.readableSize }
return Preference.PreferenceGroup(
title = stringResource(R.string.label_data),
preferenceItems = listOf(
Preference.PreferenceItem.TextPreference(
title = stringResource(R.string.pref_clear_chapter_cache),
subtitle = stringResource(R.string.used_cache, readableSize),
onClick = {
scope.launchNonCancellable {
try {
val deletedFiles = chapterCache.clear()
withUIContext {
context.toast(context.getString(R.string.cache_deleted, deletedFiles))
readableSizeSema++
}
} catch (e: Throwable) {
logcat(LogPriority.ERROR, e)
withUIContext { context.toast(R.string.cache_delete_error) }
}
}
},
),
Preference.PreferenceItem.SwitchPreference(
pref = libraryPreferences.autoClearChapterCache(),
title = stringResource(R.string.pref_auto_clear_chapter_cache),
),
Preference.PreferenceItem.TextPreference(
title = stringResource(R.string.pref_invalidate_download_cache),
subtitle = stringResource(R.string.pref_invalidate_download_cache_summary),

View File

@ -31,8 +31,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.core.net.toUri
import com.hippo.unifile.UniFile
import eu.kanade.presentation.more.settings.Preference
import eu.kanade.presentation.permissions.PermissionRequestHelper
import eu.kanade.tachiyomi.R
@ -41,11 +39,17 @@ 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.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
@ -54,12 +58,12 @@ import tachiyomi.presentation.core.util.isScrolledToStart
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
object SettingsBackupScreen : SearchableSettings {
object SettingsDataScreen : SearchableSettings {
@ReadOnlyComposable
@Composable
@StringRes
override fun getTitleRes() = R.string.label_backup
override fun getTitleRes() = R.string.label_data_storage
@Composable
override fun getPreferences(): List<Preference> {
@ -68,9 +72,49 @@ object SettingsBackupScreen : SearchableSettings {
PermissionRequestHelper.requestStoragePermission()
return listOf(
getBackupAndRestoreGroup(backupPreferences = backupPreferences),
getDataGroup(),
)
}
@Composable
private fun getBackupAndRestoreGroup(backupPreferences: BackupPreferences): Preference.PreferenceGroup {
val context = LocalContext.current
val backupIntervalPref = backupPreferences.backupInterval()
val backupInterval by backupIntervalPref.collectAsState()
return Preference.PreferenceGroup(
title = stringResource(R.string.label_backup),
preferenceItems = listOf(
// Manual actions
getCreateBackupPref(),
getRestoreBackupPref(),
getAutomaticBackupGroup(backupPreferences = backupPreferences),
// Automatic backups
Preference.PreferenceItem.ListPreference(
pref = backupIntervalPref,
title = stringResource(R.string.pref_backup_interval),
entries = mapOf(
0 to stringResource(R.string.off),
6 to stringResource(R.string.update_6hour),
12 to stringResource(R.string.update_12hour),
24 to stringResource(R.string.update_24hour),
48 to stringResource(R.string.update_48hour),
168 to stringResource(R.string.update_weekly),
),
onValueChanged = {
BackupCreateJob.setupTask(context, it)
true
},
),
Preference.PreferenceItem.ListPreference(
pref = backupPreferences.numberOfBackups(),
enabled = backupInterval != 0,
title = stringResource(R.string.pref_backup_slots),
entries = listOf(2, 3, 4, 5).associateWith { it.toString() },
),
Preference.PreferenceItem.InfoPreference(stringResource(R.string.backup_info)),
),
)
}
@ -318,70 +362,40 @@ object SettingsBackupScreen : SearchableSettings {
}
@Composable
private fun getAutomaticBackupGroup(
backupPreferences: BackupPreferences,
): Preference.PreferenceGroup {
private fun getDataGroup(): Preference.PreferenceGroup {
val scope = rememberCoroutineScope()
val context = LocalContext.current
val backupIntervalPref = backupPreferences.backupInterval()
val backupInterval by backupIntervalPref.collectAsState()
val backupDirPref = backupPreferences.backupsDirectory()
val backupDir by backupDirPref.collectAsState()
val pickBackupLocation = rememberLauncherForActivityResult(
contract = ActivityResultContracts.OpenDocumentTree(),
) { uri ->
if (uri != null) {
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
val libraryPreferences = remember { Injekt.get<LibraryPreferences>() }
context.contentResolver.takePersistableUriPermission(uri, flags)
val file = UniFile.fromUri(context, uri)
backupDirPref.set(file.uri.toString())
}
}
val chapterCache = remember { Injekt.get<ChapterCache>() }
var readableSizeSema by remember { mutableIntStateOf(0) }
val readableSize = remember(readableSizeSema) { chapterCache.readableSize }
return Preference.PreferenceGroup(
title = stringResource(R.string.pref_backup_service_category),
title = stringResource(R.string.label_data),
preferenceItems = listOf(
Preference.PreferenceItem.ListPreference(
pref = backupIntervalPref,
title = stringResource(R.string.pref_backup_interval),
entries = mapOf(
0 to stringResource(R.string.off),
6 to stringResource(R.string.update_6hour),
12 to stringResource(R.string.update_12hour),
24 to stringResource(R.string.update_24hour),
48 to stringResource(R.string.update_48hour),
168 to stringResource(R.string.update_weekly),
),
onValueChanged = {
BackupCreateJob.setupTask(context, it)
true
},
),
Preference.PreferenceItem.TextPreference(
title = stringResource(R.string.pref_backup_directory),
enabled = backupInterval != 0,
subtitle = remember(backupDir) {
(UniFile.fromUri(context, backupDir.toUri())?.filePath)?.let {
"$it/automatic"
}
} ?: stringResource(R.string.invalid_location, backupDir),
title = stringResource(R.string.pref_clear_chapter_cache),
subtitle = stringResource(R.string.used_cache, readableSize),
onClick = {
scope.launchNonCancellable {
try {
pickBackupLocation.launch(null)
} catch (e: ActivityNotFoundException) {
context.toast(R.string.file_picker_error)
val deletedFiles = chapterCache.clear()
withUIContext {
context.toast(context.getString(R.string.cache_deleted, deletedFiles))
readableSizeSema++
}
} catch (e: Throwable) {
logcat(LogPriority.ERROR, e)
withUIContext { context.toast(R.string.cache_delete_error) }
}
}
},
),
Preference.PreferenceItem.ListPreference(
pref = backupPreferences.numberOfBackups(),
enabled = backupInterval != 0,
title = stringResource(R.string.pref_backup_slots),
entries = listOf(2, 3, 4, 5).associateWith { it.toString() },
Preference.PreferenceItem.SwitchPreference(
pref = libraryPreferences.autoClearChapterCache(),
title = stringResource(R.string.pref_auto_clear_chapter_cache),
),
Preference.PreferenceItem.InfoPreference(stringResource(R.string.backup_info)),
),
)
}

View File

@ -18,7 +18,7 @@ import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.outlined.Palette
import androidx.compose.material.icons.outlined.Search
import androidx.compose.material.icons.outlined.Security
import androidx.compose.material.icons.outlined.SettingsBackupRestore
import androidx.compose.material.icons.outlined.Storage
import androidx.compose.material.icons.outlined.Sync
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
@ -208,10 +208,10 @@ object SettingsMainScreen : Screen() {
screen = SettingsBrowseScreen,
),
Item(
titleRes = R.string.label_backup,
titleRes = R.string.label_data_storage,
subtitleRes = R.string.pref_backup_summary,
icon = Icons.Outlined.SettingsBackupRestore,
screen = SettingsBackupScreen,
icon = Icons.Outlined.Storage,
screen = SettingsDataScreen,
),
Item(
titleRes = R.string.pref_category_security,

View File

@ -291,7 +291,7 @@ private val settingScreens = listOf(
SettingsDownloadScreen,
SettingsTrackingScreen,
SettingsBrowseScreen,
SettingsBackupScreen,
SettingsDataScreen,
SettingsSecurityScreen,
SettingsAdvancedScreen,
)

View File

@ -71,7 +71,7 @@ object MoreTab : Tab {
onClickDownloadQueue = { navigator.push(DownloadQueueScreen) },
onClickCategories = { navigator.push(CategoryScreen()) },
onClickStats = { navigator.push(StatsScreen()) },
onClickBackupAndRestore = { navigator.push(SettingsScreen.toBackupScreen()) },
onClickDataAndStorage = { navigator.push(SettingsScreen.toDataAndStorageScreen()) },
onClickSettings = { navigator.push(SettingsScreen.toMainScreen()) },
onClickAbout = { navigator.push(SettingsScreen.toAboutScreen()) },
)

View File

@ -13,7 +13,7 @@ import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.presentation.more.settings.screen.SettingsAppearanceScreen
import eu.kanade.presentation.more.settings.screen.SettingsBackupScreen
import eu.kanade.presentation.more.settings.screen.SettingsDataScreen
import eu.kanade.presentation.more.settings.screen.SettingsMainScreen
import eu.kanade.presentation.more.settings.screen.about.AboutScreen
import eu.kanade.presentation.util.DefaultNavigatorScreenTransition
@ -23,7 +23,7 @@ import eu.kanade.presentation.util.isTabletUi
import tachiyomi.presentation.core.components.TwoPanelBox
class SettingsScreen private constructor(
val toBackup: Boolean,
val toDataAndStorage: Boolean,
val toAbout: Boolean,
) : Screen() {
@ -32,8 +32,8 @@ class SettingsScreen private constructor(
val parentNavigator = LocalNavigator.currentOrThrow
if (!isTabletUi()) {
Navigator(
screen = if (toBackup) {
SettingsBackupScreen
screen = if (toDataAndStorage) {
SettingsDataScreen
} else if (toAbout) {
AboutScreen
} else {
@ -54,8 +54,8 @@ class SettingsScreen private constructor(
)
} else {
Navigator(
screen = if (toBackup) {
SettingsBackupScreen
screen = if (toDataAndStorage) {
SettingsDataScreen
} else if (toAbout) {
AboutScreen
} else {
@ -79,10 +79,10 @@ class SettingsScreen private constructor(
}
companion object {
fun toMainScreen() = SettingsScreen(toBackup = false, toAbout = false)
fun toMainScreen() = SettingsScreen(toDataAndStorage = false, toAbout = false)
fun toBackupScreen() = SettingsScreen(toBackup = true, toAbout = false)
fun toDataAndStorageScreen() = SettingsScreen(toDataAndStorage = true, toAbout = false)
fun toAboutScreen() = SettingsScreen(toBackup = false, toAbout = true)
fun toAboutScreen() = SettingsScreen(toDataAndStorage = false, toAbout = true)
}
}

View File

@ -24,6 +24,7 @@
<string name="label_recent_manga">History</string>
<string name="label_sources">Sources</string>
<string name="label_backup">Backup and restore</string>
<string name="label_data_storage">Data and storage</string>
<string name="label_stats">Statistics</string>
<string name="label_migration">Migrate</string>
<string name="label_extensions">Extensions</string>
@ -181,7 +182,7 @@
<string name="pref_downloads_summary">Automatic download, download ahead</string>
<string name="pref_tracking_summary">One-way progress sync, enhanced sync</string>
<string name="pref_browse_summary">Sources, extensions, global search</string>
<string name="pref_backup_summary">Manual &amp; automatic backups</string>
<string name="pref_backup_summary">Manual &amp; automatic backups, storage space</string>
<string name="pref_security_summary">App lock, secure screen</string>
<string name="pref_advanced_summary">Dump crash logs, battery optimizations</string>
@ -467,15 +468,14 @@
<!-- Browse section -->
<string name="pref_hide_in_library_items">Hide entries already in library</string>
<!-- Backup section -->
<!-- Data and storage section -->
<string name="pref_create_backup">Create backup</string>
<string name="pref_create_backup_summ">Can be used to restore current library</string>
<string name="pref_restore_backup">Restore backup</string>
<string name="pref_restore_backup_summ">Restore library from backup file</string>
<string name="pref_backup_directory">Backup location</string>
<string name="pref_backup_service_category">Automatic backups</string>
<string name="pref_backup_interval">Backup frequency</string>
<string name="pref_backup_slots">Maximum backups</string>
<string name="pref_backup_interval">Automatic backup frequency</string>
<string name="pref_backup_slots">Maximum automatic backups</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>
@ -509,7 +509,7 @@
<string name="library_sync_complete">Library sync complete</string>
<!-- Advanced section -->
<string name="label_network">Network</string>
<string name="label_network">Networking</string>
<string name="pref_clear_cookies">Clear cookies</string>
<string name="pref_dns_over_https">DNS over HTTPS (DoH)</string>
<string name="pref_user_agent_string">Default user agent string</string>