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

View file

@ -14,7 +14,6 @@ import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope 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.advanced.ClearDatabaseScreen
import eu.kanade.presentation.more.settings.screen.debug.DebugInfoScreen import eu.kanade.presentation.more.settings.screen.debug.DebugInfoScreen
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.ChapterCache
import eu.kanade.tachiyomi.data.download.DownloadCache import eu.kanade.tachiyomi.data.download.DownloadCache
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkHelper
@ -61,7 +59,6 @@ import okhttp3.Headers
import tachiyomi.core.util.lang.launchNonCancellable import tachiyomi.core.util.lang.launchNonCancellable
import tachiyomi.core.util.lang.withUIContext import tachiyomi.core.util.lang.withUIContext
import tachiyomi.core.util.system.logcat import tachiyomi.core.util.system.logcat
import tachiyomi.domain.library.service.LibraryPreferences
import tachiyomi.domain.manga.repository.MangaRepository import tachiyomi.domain.manga.repository.MangaRepository
import tachiyomi.presentation.core.util.collectAsState import tachiyomi.presentation.core.util.collectAsState
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
@ -183,40 +180,12 @@ object SettingsAdvancedScreen : SearchableSettings {
@Composable @Composable
private fun getDataGroup(): Preference.PreferenceGroup { private fun getDataGroup(): Preference.PreferenceGroup {
val scope = rememberCoroutineScope()
val context = LocalContext.current val context = LocalContext.current
val navigator = LocalNavigator.currentOrThrow 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( return Preference.PreferenceGroup(
title = stringResource(R.string.label_data), title = stringResource(R.string.label_data),
preferenceItems = listOf( 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( Preference.PreferenceItem.TextPreference(
title = stringResource(R.string.pref_invalidate_download_cache), title = stringResource(R.string.pref_invalidate_download_cache),
subtitle = stringResource(R.string.pref_invalidate_download_cache_summary), 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.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource 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.more.settings.Preference
import eu.kanade.presentation.permissions.PermissionRequestHelper import eu.kanade.presentation.permissions.PermissionRequestHelper
import eu.kanade.tachiyomi.R 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.BackupFileValidator
import eu.kanade.tachiyomi.data.backup.BackupRestoreJob import eu.kanade.tachiyomi.data.backup.BackupRestoreJob
import eu.kanade.tachiyomi.data.backup.models.Backup 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.DeviceUtil
import eu.kanade.tachiyomi.util.system.copyToClipboard import eu.kanade.tachiyomi.util.system.copyToClipboard
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.launch 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.backup.service.BackupPreferences
import tachiyomi.domain.library.service.LibraryPreferences
import tachiyomi.presentation.core.components.LabeledCheckbox import tachiyomi.presentation.core.components.LabeledCheckbox
import tachiyomi.presentation.core.components.ScrollbarLazyColumn import tachiyomi.presentation.core.components.ScrollbarLazyColumn
import tachiyomi.presentation.core.util.collectAsState 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.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
object SettingsBackupScreen : SearchableSettings { object SettingsDataScreen : SearchableSettings {
@ReadOnlyComposable @ReadOnlyComposable
@Composable @Composable
@StringRes @StringRes
override fun getTitleRes() = R.string.label_backup override fun getTitleRes() = R.string.label_data_storage
@Composable @Composable
override fun getPreferences(): List<Preference> { override fun getPreferences(): List<Preference> {
@ -68,9 +72,49 @@ object SettingsBackupScreen : SearchableSettings {
PermissionRequestHelper.requestStoragePermission() PermissionRequestHelper.requestStoragePermission()
return listOf( return listOf(
getCreateBackupPref(), getBackupAndRestoreGroup(backupPreferences = backupPreferences),
getRestoreBackupPref(), getDataGroup(),
getAutomaticBackupGroup(backupPreferences = backupPreferences), )
}
@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(),
// 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 @Composable
private fun getAutomaticBackupGroup( private fun getDataGroup(): Preference.PreferenceGroup {
backupPreferences: BackupPreferences, val scope = rememberCoroutineScope()
): Preference.PreferenceGroup {
val context = LocalContext.current val context = LocalContext.current
val backupIntervalPref = backupPreferences.backupInterval() val libraryPreferences = remember { Injekt.get<LibraryPreferences>() }
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
context.contentResolver.takePersistableUriPermission(uri, flags) val chapterCache = remember { Injekt.get<ChapterCache>() }
var readableSizeSema by remember { mutableIntStateOf(0) }
val file = UniFile.fromUri(context, uri) val readableSize = remember(readableSizeSema) { chapterCache.readableSize }
backupDirPref.set(file.uri.toString())
}
}
return Preference.PreferenceGroup( return Preference.PreferenceGroup(
title = stringResource(R.string.pref_backup_service_category), title = stringResource(R.string.label_data),
preferenceItems = listOf( 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( Preference.PreferenceItem.TextPreference(
title = stringResource(R.string.pref_backup_directory), title = stringResource(R.string.pref_clear_chapter_cache),
enabled = backupInterval != 0, subtitle = stringResource(R.string.used_cache, readableSize),
subtitle = remember(backupDir) {
(UniFile.fromUri(context, backupDir.toUri())?.filePath)?.let {
"$it/automatic"
}
} ?: stringResource(R.string.invalid_location, backupDir),
onClick = { onClick = {
try { scope.launchNonCancellable {
pickBackupLocation.launch(null) try {
} catch (e: ActivityNotFoundException) { val deletedFiles = chapterCache.clear()
context.toast(R.string.file_picker_error) 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( Preference.PreferenceItem.SwitchPreference(
pref = backupPreferences.numberOfBackups(), pref = libraryPreferences.autoClearChapterCache(),
enabled = backupInterval != 0, title = stringResource(R.string.pref_auto_clear_chapter_cache),
title = stringResource(R.string.pref_backup_slots),
entries = listOf(2, 3, 4, 5).associateWith { it.toString() },
), ),
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.Palette
import androidx.compose.material.icons.outlined.Search import androidx.compose.material.icons.outlined.Search
import androidx.compose.material.icons.outlined.Security 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.material.icons.outlined.Sync
import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@ -208,10 +208,10 @@ object SettingsMainScreen : Screen() {
screen = SettingsBrowseScreen, screen = SettingsBrowseScreen,
), ),
Item( Item(
titleRes = R.string.label_backup, titleRes = R.string.label_data_storage,
subtitleRes = R.string.pref_backup_summary, subtitleRes = R.string.pref_backup_summary,
icon = Icons.Outlined.SettingsBackupRestore, icon = Icons.Outlined.Storage,
screen = SettingsBackupScreen, screen = SettingsDataScreen,
), ),
Item( Item(
titleRes = R.string.pref_category_security, titleRes = R.string.pref_category_security,

View file

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

View file

@ -71,7 +71,7 @@ object MoreTab : Tab {
onClickDownloadQueue = { navigator.push(DownloadQueueScreen) }, onClickDownloadQueue = { navigator.push(DownloadQueueScreen) },
onClickCategories = { navigator.push(CategoryScreen()) }, onClickCategories = { navigator.push(CategoryScreen()) },
onClickStats = { navigator.push(StatsScreen()) }, onClickStats = { navigator.push(StatsScreen()) },
onClickBackupAndRestore = { navigator.push(SettingsScreen.toBackupScreen()) }, onClickDataAndStorage = { navigator.push(SettingsScreen.toDataAndStorageScreen()) },
onClickSettings = { navigator.push(SettingsScreen.toMainScreen()) }, onClickSettings = { navigator.push(SettingsScreen.toMainScreen()) },
onClickAbout = { navigator.push(SettingsScreen.toAboutScreen()) }, 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.Navigator
import cafe.adriel.voyager.navigator.currentOrThrow import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.presentation.more.settings.screen.SettingsAppearanceScreen 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.SettingsMainScreen
import eu.kanade.presentation.more.settings.screen.about.AboutScreen import eu.kanade.presentation.more.settings.screen.about.AboutScreen
import eu.kanade.presentation.util.DefaultNavigatorScreenTransition import eu.kanade.presentation.util.DefaultNavigatorScreenTransition
@ -23,7 +23,7 @@ import eu.kanade.presentation.util.isTabletUi
import tachiyomi.presentation.core.components.TwoPanelBox import tachiyomi.presentation.core.components.TwoPanelBox
class SettingsScreen private constructor( class SettingsScreen private constructor(
val toBackup: Boolean, val toDataAndStorage: Boolean,
val toAbout: Boolean, val toAbout: Boolean,
) : Screen() { ) : Screen() {
@ -32,8 +32,8 @@ class SettingsScreen private constructor(
val parentNavigator = LocalNavigator.currentOrThrow val parentNavigator = LocalNavigator.currentOrThrow
if (!isTabletUi()) { if (!isTabletUi()) {
Navigator( Navigator(
screen = if (toBackup) { screen = if (toDataAndStorage) {
SettingsBackupScreen SettingsDataScreen
} else if (toAbout) { } else if (toAbout) {
AboutScreen AboutScreen
} else { } else {
@ -54,8 +54,8 @@ class SettingsScreen private constructor(
) )
} else { } else {
Navigator( Navigator(
screen = if (toBackup) { screen = if (toDataAndStorage) {
SettingsBackupScreen SettingsDataScreen
} else if (toAbout) { } else if (toAbout) {
AboutScreen AboutScreen
} else { } else {
@ -79,10 +79,10 @@ class SettingsScreen private constructor(
} }
companion object { 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_recent_manga">History</string>
<string name="label_sources">Sources</string> <string name="label_sources">Sources</string>
<string name="label_backup">Backup and restore</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_stats">Statistics</string>
<string name="label_migration">Migrate</string> <string name="label_migration">Migrate</string>
<string name="label_extensions">Extensions</string> <string name="label_extensions">Extensions</string>
@ -181,7 +182,7 @@
<string name="pref_downloads_summary">Automatic download, download ahead</string> <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_tracking_summary">One-way progress sync, enhanced sync</string>
<string name="pref_browse_summary">Sources, extensions, global search</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_security_summary">App lock, secure screen</string>
<string name="pref_advanced_summary">Dump crash logs, battery optimizations</string> <string name="pref_advanced_summary">Dump crash logs, battery optimizations</string>
@ -467,15 +468,14 @@
<!-- Browse section --> <!-- Browse section -->
<string name="pref_hide_in_library_items">Hide entries already in library</string> <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">Create backup</string>
<string name="pref_create_backup_summ">Can be used to restore current library</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">Restore backup</string>
<string name="pref_restore_backup_summ">Restore library from backup file</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_directory">Backup location</string>
<string name="pref_backup_service_category">Automatic backups</string> <string name="pref_backup_interval">Automatic backup frequency</string>
<string name="pref_backup_interval">Backup frequency</string> <string name="pref_backup_slots">Maximum automatic backups</string>
<string name="pref_backup_slots">Maximum backups</string>
<string name="backup_created">Backup created</string> <string name="backup_created">Backup created</string>
<string name="invalid_backup_file">Invalid backup file</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> <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> <string name="library_sync_complete">Library sync complete</string>
<!-- Advanced section --> <!-- 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_clear_cookies">Clear cookies</string>
<string name="pref_dns_over_https">DNS over HTTPS (DoH)</string> <string name="pref_dns_over_https">DNS over HTTPS (DoH)</string>
<string name="pref_user_agent_string">Default user agent string</string> <string name="pref_user_agent_string">Default user agent string</string>