Add basic storage usage info to "Data and storage" settings screen
This commit is contained in:
parent
ce7bf396eb
commit
cb8ea5eab0
4 changed files with 71 additions and 11 deletions
|
@ -4,12 +4,15 @@ import android.content.ActivityNotFoundException
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import android.os.Environment
|
||||||
|
import android.text.format.Formatter
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
@ -32,6 +35,8 @@ 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 eu.kanade.presentation.more.settings.Preference
|
import eu.kanade.presentation.more.settings.Preference
|
||||||
|
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.permissions.PermissionRequestHelper
|
||||||
import eu.kanade.presentation.util.relativeTimeSpanString
|
import eu.kanade.presentation.util.relativeTimeSpanString
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
@ -41,6 +46,7 @@ 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.data.cache.ChapterCache
|
||||||
|
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
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
|
||||||
|
@ -373,22 +379,24 @@ object SettingsDataScreen : SearchableSettings {
|
||||||
val libraryPreferences = remember { Injekt.get<LibraryPreferences>() }
|
val libraryPreferences = remember { Injekt.get<LibraryPreferences>() }
|
||||||
|
|
||||||
val chapterCache = remember { Injekt.get<ChapterCache>() }
|
val chapterCache = remember { Injekt.get<ChapterCache>() }
|
||||||
var readableSizeSema by remember { mutableIntStateOf(0) }
|
var cacheReadableSizeSema by remember { mutableIntStateOf(0) }
|
||||||
val readableSize = remember(readableSizeSema) { chapterCache.readableSize }
|
val cacheReadableSize = remember(cacheReadableSizeSema) { chapterCache.readableSize }
|
||||||
|
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
title = stringResource(R.string.label_data),
|
title = stringResource(R.string.label_data),
|
||||||
preferenceItems = listOf(
|
preferenceItems = listOf(
|
||||||
|
getStorageInfoPref(cacheReadableSize),
|
||||||
|
|
||||||
Preference.PreferenceItem.TextPreference(
|
Preference.PreferenceItem.TextPreference(
|
||||||
title = stringResource(R.string.pref_clear_chapter_cache),
|
title = stringResource(R.string.pref_clear_chapter_cache),
|
||||||
subtitle = stringResource(R.string.used_cache, readableSize),
|
subtitle = stringResource(R.string.used_cache, cacheReadableSize),
|
||||||
onClick = {
|
onClick = {
|
||||||
scope.launchNonCancellable {
|
scope.launchNonCancellable {
|
||||||
try {
|
try {
|
||||||
val deletedFiles = chapterCache.clear()
|
val deletedFiles = chapterCache.clear()
|
||||||
withUIContext {
|
withUIContext {
|
||||||
context.toast(context.getString(R.string.cache_deleted, deletedFiles))
|
context.toast(context.getString(R.string.cache_deleted, deletedFiles))
|
||||||
readableSizeSema++
|
cacheReadableSizeSema++
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
logcat(LogPriority.ERROR, e)
|
logcat(LogPriority.ERROR, e)
|
||||||
|
@ -404,6 +412,33 @@ object SettingsDataScreen : SearchableSettings {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun getStorageInfoPref(
|
||||||
|
chapterCacheReadableSize: String,
|
||||||
|
): Preference.PreferenceItem.CustomPreference {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val available = remember {
|
||||||
|
Formatter.formatFileSize(context, DiskUtil.getAvailableStorageSpace(Environment.getDataDirectory()))
|
||||||
|
}
|
||||||
|
val total = remember {
|
||||||
|
Formatter.formatFileSize(context, DiskUtil.getTotalStorageSpace(Environment.getDataDirectory()))
|
||||||
|
}
|
||||||
|
|
||||||
|
return Preference.PreferenceItem.CustomPreference(
|
||||||
|
title = stringResource(R.string.pref_storage_usage),
|
||||||
|
) {
|
||||||
|
BasePreferenceWidget(
|
||||||
|
title = stringResource(R.string.pref_storage_usage),
|
||||||
|
subcomponent = {
|
||||||
|
// TODO: downloads, SD cards, bar representation?, i18n
|
||||||
|
Box(modifier = Modifier.padding(horizontal = PrefsHorizontalPadding)) {
|
||||||
|
Text(text = "Available: $available / $total (chapter cache: $chapterCacheReadableSize)")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class MissingRestoreComponents(
|
private data class MissingRestoreComponents(
|
||||||
|
|
|
@ -28,6 +28,30 @@ object DiskUtil {
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the total space for the disk that a file path points to, in bytes.
|
||||||
|
*/
|
||||||
|
fun getTotalStorageSpace(file: File): Long {
|
||||||
|
return try {
|
||||||
|
val stat = StatFs(file.absolutePath)
|
||||||
|
stat.blockCountLong * stat.blockSizeLong
|
||||||
|
} catch (_: Exception) {
|
||||||
|
-1L
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the available space for the disk that a file path points to, in bytes.
|
||||||
|
*/
|
||||||
|
fun getAvailableStorageSpace(file: File): Long {
|
||||||
|
return try {
|
||||||
|
val stat = StatFs(file.absolutePath)
|
||||||
|
stat.availableBlocksLong * stat.blockSizeLong
|
||||||
|
} catch (_: Exception) {
|
||||||
|
-1L
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the available space for the disk that a file path points to, in bytes.
|
* Gets the available space for the disk that a file path points to, in bytes.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -35,7 +35,7 @@ interface Preference<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A preference used for internal app state that isn't really a user preference
|
* A preference used for internal app state that isn't really a user preference
|
||||||
* and therefore should not be inplaces like backips.
|
* and therefore should not be in places like backups.
|
||||||
*/
|
*/
|
||||||
fun isAppState(key: String): Boolean {
|
fun isAppState(key: String): Boolean {
|
||||||
return key.startsWith(APP_STATE_PREFIX)
|
return key.startsWith(APP_STATE_PREFIX)
|
||||||
|
|
|
@ -506,6 +506,13 @@
|
||||||
<string name="restoring_backup_canceled">Canceled restore</string>
|
<string name="restoring_backup_canceled">Canceled restore</string>
|
||||||
<string name="backup_info">You should keep copies of backups in other places as well. Backups may contain sensitive data including any stored passwords; be careful if sharing.</string>
|
<string name="backup_info">You should keep copies of backups in other places as well. Backups may contain sensitive data including any stored passwords; be careful if sharing.</string>
|
||||||
<string name="last_auto_backup_info">Last automatically backed up: %s</string>
|
<string name="last_auto_backup_info">Last automatically backed up: %s</string>
|
||||||
|
<string name="label_data">Data</string>
|
||||||
|
<string name="pref_storage_usage">Storage usage</string>
|
||||||
|
<string name="pref_clear_chapter_cache">Clear chapter cache</string>
|
||||||
|
<string name="used_cache">Used: %1$s</string>
|
||||||
|
<string name="cache_deleted">Cache cleared. %1$d files have been deleted</string>
|
||||||
|
<string name="cache_delete_error">Error occurred while clearing</string>
|
||||||
|
<string name="pref_auto_clear_chapter_cache">Clear chapter cache on app launch</string>
|
||||||
|
|
||||||
<!-- Sync section -->
|
<!-- Sync section -->
|
||||||
<string name="syncing_library">Syncing library</string>
|
<string name="syncing_library">Syncing library</string>
|
||||||
|
@ -521,12 +528,6 @@
|
||||||
<string name="pref_reset_user_agent_string">Reset default user agent string</string>
|
<string name="pref_reset_user_agent_string">Reset default user agent string</string>
|
||||||
<string name="requires_app_restart">Requires app restart to take effect</string>
|
<string name="requires_app_restart">Requires app restart to take effect</string>
|
||||||
<string name="cookies_cleared">Cookies cleared</string>
|
<string name="cookies_cleared">Cookies cleared</string>
|
||||||
<string name="label_data">Data</string>
|
|
||||||
<string name="pref_clear_chapter_cache">Clear chapter cache</string>
|
|
||||||
<string name="used_cache">Used: %1$s</string>
|
|
||||||
<string name="cache_deleted">Cache cleared. %1$d files have been deleted</string>
|
|
||||||
<string name="cache_delete_error">Error occurred while clearing</string>
|
|
||||||
<string name="pref_auto_clear_chapter_cache">Clear chapter cache on app launch</string>
|
|
||||||
<string name="pref_invalidate_download_cache">Invalidate downloads index</string>
|
<string name="pref_invalidate_download_cache">Invalidate downloads index</string>
|
||||||
<string name="pref_invalidate_download_cache_summary">Force app to recheck downloaded chapters</string>
|
<string name="pref_invalidate_download_cache_summary">Force app to recheck downloaded chapters</string>
|
||||||
<string name="download_cache_invalidated">Downloads index invalidated</string>
|
<string name="download_cache_invalidated">Downloads index invalidated</string>
|
||||||
|
|
Reference in a new issue