diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3f45e2c22e..b8240bb9b4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -254,7 +254,6 @@ dependencies { // UI libraries implementation(libs.material) - implementation(libs.androidprocessbutton) implementation(libs.flexible.adapter.core) implementation(libs.flexible.adapter.ui) implementation(libs.photoview) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/SettingsMainScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/SettingsMainScreen.kt deleted file mode 100644 index 90a5262870..0000000000 --- a/app/src/main/java/eu/kanade/presentation/more/settings/SettingsMainScreen.kt +++ /dev/null @@ -1,62 +0,0 @@ -package eu.kanade.presentation.more.settings - -import androidx.annotation.StringRes -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.Search -import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.res.stringResource -import eu.kanade.presentation.components.AppBar -import eu.kanade.presentation.components.AppBarActions -import eu.kanade.presentation.components.PreferenceRow -import eu.kanade.presentation.components.Scaffold -import eu.kanade.presentation.components.ScrollbarLazyColumn -import eu.kanade.tachiyomi.R - -@Composable -fun SettingsMainScreen( - navigateUp: () -> Unit, - sections: List, - onClickSearch: () -> Unit, -) { - Scaffold( - topBar = { scrollBehavior -> - AppBar( - title = stringResource(R.string.label_settings), - navigateUp = navigateUp, - actions = { - AppBarActions( - listOf( - AppBar.Action( - title = stringResource(R.string.action_search), - icon = Icons.Outlined.Search, - onClick = onClickSearch, - ), - ), - ) - }, - scrollBehavior = scrollBehavior, - ) - }, - ) { contentPadding -> - ScrollbarLazyColumn( - contentPadding = contentPadding, - ) { - sections.map { - item { - PreferenceRow( - title = stringResource(it.titleRes), - painter = it.painter, - onClick = it.onClick, - ) - } - } - } - } -} - -data class SettingsSection( - @StringRes val titleRes: Int, - val painter: Painter, - val onClick: () -> Unit, -) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/SettingsSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/SettingsSearchScreen.kt deleted file mode 100644 index bb66166b2c..0000000000 --- a/app/src/main/java/eu/kanade/presentation/more/settings/SettingsSearchScreen.kt +++ /dev/null @@ -1,116 +0,0 @@ -package eu.kanade.presentation.more.settings - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalFocusManager -import androidx.compose.ui.platform.LocalSoftwareKeyboardController -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.unit.dp -import eu.kanade.presentation.components.Scaffold -import eu.kanade.presentation.components.ScrollbarLazyColumn -import eu.kanade.presentation.components.SearchToolbar -import eu.kanade.presentation.util.horizontalPadding -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.ui.setting.SettingsController -import eu.kanade.tachiyomi.ui.setting.search.SettingsSearchHelper -import eu.kanade.tachiyomi.ui.setting.search.SettingsSearchPresenter -import kotlin.reflect.full.createInstance - -@Composable -fun SettingsSearchScreen( - navigateUp: () -> Unit, - presenter: SettingsSearchPresenter, - onClickResult: (SettingsController) -> Unit, -) { - val results by presenter.state.collectAsState() - var query by remember { mutableStateOf("") } - - val keyboardController = LocalSoftwareKeyboardController.current - val focusManager = LocalFocusManager.current - - Scaffold( - topBar = { scrollBehavior -> - SearchToolbar( - searchQuery = query, - onChangeSearchQuery = { - query = it - presenter.searchSettings(it) - }, - placeholderText = stringResource(R.string.action_search_settings), - onClickCloseSearch = navigateUp, - onClickResetSearch = { query = "" }, - scrollBehavior = scrollBehavior, - keyboardOptions = KeyboardOptions.Default.copy( - imeAction = ImeAction.Search, - ), - keyboardActions = KeyboardActions( - onSearch = { - focusManager.clearFocus() - keyboardController?.hide() - }, - ), - ) - }, - ) { contentPadding -> - ScrollbarLazyColumn( - contentPadding = contentPadding, - ) { - items( - items = results, - key = { it.key.toString() }, - ) { result -> - SearchResult(result, onClickResult) - } - } - } -} - -@Composable -private fun SearchResult( - result: SettingsSearchHelper.SettingsSearchResult, - onClickResult: (SettingsController) -> Unit, -) { - Column( - modifier = Modifier - .fillMaxWidth() - .clickable { - // Must pass a new Controller instance to avoid this error - // https://github.com/bluelinelabs/Conductor/issues/446 - val controller = result.searchController::class.createInstance() - controller.preferenceKey = result.key - onClickResult(controller) - } - .padding(horizontal = horizontalPadding, vertical = 8.dp), - ) { - Text( - text = result.title, - ) - - Text( - text = result.summary, - style = MaterialTheme.typography.bodySmall.copy( - color = MaterialTheme.colorScheme.outline, - ), - ) - - Text( - text = result.breadcrumb, - style = MaterialTheme.typography.bodySmall, - ) - } -} diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/database/ClearDatabaseScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/database/ClearDatabaseScreen.kt deleted file mode 100644 index 29472a5f12..0000000000 --- a/app/src/main/java/eu/kanade/presentation/more/settings/database/ClearDatabaseScreen.kt +++ /dev/null @@ -1,53 +0,0 @@ -package eu.kanade.presentation.more.settings.database - -import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext -import eu.kanade.presentation.components.Scaffold -import eu.kanade.presentation.more.settings.database.components.ClearDatabaseContent -import eu.kanade.presentation.more.settings.database.components.ClearDatabaseDeleteDialog -import eu.kanade.presentation.more.settings.database.components.ClearDatabaseToolbar -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.ui.setting.database.ClearDatabasePresenter -import eu.kanade.tachiyomi.util.system.toast - -@Composable -fun ClearDatabaseScreen( - presenter: ClearDatabasePresenter, - navigateUp: () -> Unit, -) { - val context = LocalContext.current - Scaffold( - topBar = { scrollBehavior -> - ClearDatabaseToolbar( - state = presenter, - navigateUp = navigateUp, - onClickSelectAll = { presenter.selectAll() }, - onClickInvertSelection = { presenter.invertSelection() }, - scrollBehavior = scrollBehavior, - ) - }, - ) { paddingValues -> - ClearDatabaseContent( - state = presenter, - contentPadding = paddingValues, - onClickSelection = { source -> - presenter.toggleSelection(source) - }, - onClickDelete = { - presenter.dialog = ClearDatabasePresenter.Dialog.Delete(presenter.selection) - }, - ) - } - val dialog = presenter.dialog - if (dialog is ClearDatabasePresenter.Dialog.Delete) { - ClearDatabaseDeleteDialog( - onDismissRequest = { presenter.dialog = null }, - onDelete = { - presenter.removeMangaBySourceId(dialog.sourceIds) - presenter.clearSelection() - presenter.dialog = null - context.toast(R.string.clear_database_completed) - }, - ) - } -} diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/database/ClearDatabaseState.kt b/app/src/main/java/eu/kanade/presentation/more/settings/database/ClearDatabaseState.kt index 34281eab82..f0b791e74f 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/database/ClearDatabaseState.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/database/ClearDatabaseState.kt @@ -6,14 +6,13 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import eu.kanade.domain.source.model.SourceWithCount -import eu.kanade.tachiyomi.ui.setting.database.ClearDatabasePresenter @Stable interface ClearDatabaseState { val items: List val selection: List val isEmpty: Boolean - var dialog: ClearDatabasePresenter.Dialog? + var dialog: Dialog? } fun ClearDatabaseState(): ClearDatabaseState { @@ -24,5 +23,9 @@ class ClearDatabaseStateImpl : ClearDatabaseState { override var items: List by mutableStateOf(emptyList()) override var selection: List by mutableStateOf(emptyList()) override val isEmpty: Boolean by derivedStateOf { items.isEmpty() } - override var dialog: ClearDatabasePresenter.Dialog? by mutableStateOf(null) + override var dialog: Dialog? by mutableStateOf(null) +} + +sealed class Dialog { + data class Delete(val sourceIds: List) : Dialog() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt deleted file mode 100644 index 778592899e..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt +++ /dev/null @@ -1,401 +0,0 @@ -package eu.kanade.tachiyomi.ui.setting - -import android.annotation.SuppressLint -import android.content.ActivityNotFoundException -import android.content.Intent -import android.provider.Settings -import android.webkit.WebStorage -import android.webkit.WebView -import androidx.core.net.toUri -import androidx.preference.PreferenceScreen -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import eu.kanade.domain.library.service.LibraryPreferences -import eu.kanade.domain.manga.repository.MangaRepository -import eu.kanade.domain.ui.UiPreferences -import eu.kanade.domain.ui.model.TabletUiMode -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.cache.ChapterCache -import eu.kanade.tachiyomi.data.library.LibraryUpdateService -import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Target -import eu.kanade.tachiyomi.data.preference.PreferenceValues -import eu.kanade.tachiyomi.data.track.TrackManager -import eu.kanade.tachiyomi.network.NetworkHelper -import eu.kanade.tachiyomi.network.NetworkPreferences -import eu.kanade.tachiyomi.network.PREF_DOH_360 -import eu.kanade.tachiyomi.network.PREF_DOH_ADGUARD -import eu.kanade.tachiyomi.network.PREF_DOH_ALIDNS -import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE -import eu.kanade.tachiyomi.network.PREF_DOH_CONTROLD -import eu.kanade.tachiyomi.network.PREF_DOH_DNSPOD -import eu.kanade.tachiyomi.network.PREF_DOH_GOOGLE -import eu.kanade.tachiyomi.network.PREF_DOH_MULLVAD -import eu.kanade.tachiyomi.network.PREF_DOH_NJALLA -import eu.kanade.tachiyomi.network.PREF_DOH_QUAD101 -import eu.kanade.tachiyomi.network.PREF_DOH_QUAD9 -import eu.kanade.tachiyomi.ui.base.controller.openInBrowser -import eu.kanade.tachiyomi.ui.base.controller.pushController -import eu.kanade.tachiyomi.ui.setting.database.ClearDatabaseController -import eu.kanade.tachiyomi.util.CrashLogUtil -import eu.kanade.tachiyomi.util.lang.launchNonCancellable -import eu.kanade.tachiyomi.util.lang.withUIContext -import eu.kanade.tachiyomi.util.preference.bindTo -import eu.kanade.tachiyomi.util.preference.defaultValue -import eu.kanade.tachiyomi.util.preference.editTextPreference -import eu.kanade.tachiyomi.util.preference.entriesRes -import eu.kanade.tachiyomi.util.preference.intListPreference -import eu.kanade.tachiyomi.util.preference.listPreference -import eu.kanade.tachiyomi.util.preference.onChange -import eu.kanade.tachiyomi.util.preference.onClick -import eu.kanade.tachiyomi.util.preference.preference -import eu.kanade.tachiyomi.util.preference.preferenceCategory -import eu.kanade.tachiyomi.util.preference.summaryRes -import eu.kanade.tachiyomi.util.preference.switchPreference -import eu.kanade.tachiyomi.util.preference.titleRes -import eu.kanade.tachiyomi.util.system.DeviceUtil -import eu.kanade.tachiyomi.util.system.isDevFlavor -import eu.kanade.tachiyomi.util.system.isPackageInstalled -import eu.kanade.tachiyomi.util.system.logcat -import eu.kanade.tachiyomi.util.system.powerManager -import eu.kanade.tachiyomi.util.system.setDefaultSettings -import eu.kanade.tachiyomi.util.system.toast -import logcat.LogPriority -import rikka.sui.Sui -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get -import uy.kohesive.injekt.injectLazy -import java.io.File - -class SettingsAdvancedController( - private val mangaRepository: MangaRepository = Injekt.get(), -) : SettingsController() { - - private val network: NetworkHelper by injectLazy() - private val chapterCache: ChapterCache by injectLazy() - private val trackManager: TrackManager by injectLazy() - private val networkPreferences: NetworkPreferences by injectLazy() - private val libraryPreferences: LibraryPreferences by injectLazy() - private val uiPreferences: UiPreferences by injectLazy() - - @SuppressLint("BatteryLife") - override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply { - titleRes = R.string.pref_category_advanced - - if (isDevFlavor.not()) { - switchPreference { - key = "acra.enable" - titleRes = R.string.pref_enable_acra - summaryRes = R.string.pref_acra_summary - defaultValue = true - } - } - - preference { - key = "dump_crash_logs" - titleRes = R.string.pref_dump_crash_logs - summaryRes = R.string.pref_dump_crash_logs_summary - - onClick { - viewScope.launchNonCancellable { - CrashLogUtil(context).dumpLogs() - } - } - } - - switchPreference { - key = networkPreferences.verboseLogging().key() - titleRes = R.string.pref_verbose_logging - summaryRes = R.string.pref_verbose_logging_summary - defaultValue = isDevFlavor - - onChange { - activity?.toast(R.string.requires_app_restart) - true - } - } - - preferenceCategory { - titleRes = R.string.label_background_activity - - preference { - key = "pref_disable_battery_optimization" - titleRes = R.string.pref_disable_battery_optimization - summaryRes = R.string.pref_disable_battery_optimization_summary - - onClick { - val packageName: String = context.packageName - if (!context.powerManager.isIgnoringBatteryOptimizations(packageName)) { - try { - val intent = Intent().apply { - action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS - data = "package:$packageName".toUri() - } - startActivity(intent) - } catch (e: ActivityNotFoundException) { - context.toast(R.string.battery_optimization_setting_activity_not_found) - } - } else { - context.toast(R.string.battery_optimization_disabled) - } - } - } - - preference { - key = "pref_dont_kill_my_app" - title = "Don't kill my app!" - summaryRes = R.string.about_dont_kill_my_app - - onClick { - openInBrowser("https://dontkillmyapp.com/") - } - } - } - - preferenceCategory { - titleRes = R.string.label_data - - preference { - key = CLEAR_CACHE_KEY - titleRes = R.string.pref_clear_chapter_cache - summary = context.getString(R.string.used_cache, chapterCache.readableSize) - - onClick { clearChapterCache() } - } - switchPreference { - bindTo(libraryPreferences.autoClearChapterCache()) - titleRes = R.string.pref_auto_clear_chapter_cache - } - preference { - key = "pref_clear_database" - titleRes = R.string.pref_clear_database - summaryRes = R.string.pref_clear_database_summary - - onClick { - router.pushController(ClearDatabaseController()) - } - } - } - - preferenceCategory { - titleRes = R.string.label_network - - preference { - key = "pref_clear_cookies" - titleRes = R.string.pref_clear_cookies - - onClick { - network.cookieManager.removeAll() - activity?.toast(R.string.cookies_cleared) - } - } - preference { - key = "pref_clear_webview_data" - titleRes = R.string.pref_clear_webview_data - - onClick { clearWebViewData() } - } - intListPreference { - key = networkPreferences.dohProvider().key() - titleRes = R.string.pref_dns_over_https - entries = arrayOf( - context.getString(R.string.disabled), - "Cloudflare", - "Google", - "AdGuard", - "Quad9", - "AliDNS", - "DNSPod", - "360", - "Quad 101", - "Mullvad", - "Control D", - "Njalla", - ) - entryValues = arrayOf( - "-1", - PREF_DOH_CLOUDFLARE.toString(), - PREF_DOH_GOOGLE.toString(), - PREF_DOH_ADGUARD.toString(), - PREF_DOH_QUAD9.toString(), - PREF_DOH_ALIDNS.toString(), - PREF_DOH_DNSPOD.toString(), - PREF_DOH_360.toString(), - PREF_DOH_QUAD101.toString(), - PREF_DOH_MULLVAD.toString(), - PREF_DOH_CONTROLD.toString(), - PREF_DOH_NJALLA.toString(), - ) - defaultValue = "-1" - summary = "%s" - - onChange { - activity?.toast(R.string.requires_app_restart) - true - } - } - val defaultUserAgent = networkPreferences.defaultUserAgent() - editTextPreference { - key = defaultUserAgent.key() - titleRes = R.string.pref_user_agent_string - text = defaultUserAgent.get() - summary = network.defaultUserAgent - - onChange { - if (it.toString().isBlank()) { - activity?.toast(R.string.error_user_agent_string_blank) - } else { - text = it.toString().trim() - activity?.toast(R.string.requires_app_restart) - } - false - } - } - preference { - key = "pref_reset_user_agent" - titleRes = R.string.pref_reset_user_agent_string - - visibleIf(defaultUserAgent) { it != defaultUserAgent.defaultValue() } - - onClick { - defaultUserAgent.delete() - activity?.toast(R.string.requires_app_restart) - } - } - } - - preferenceCategory { - titleRes = R.string.label_library - - preference { - key = "pref_refresh_library_covers" - titleRes = R.string.pref_refresh_library_covers - - onClick { LibraryUpdateService.start(context, target = Target.COVERS) } - } - if (trackManager.hasLoggedServices()) { - preference { - key = "pref_refresh_library_tracking" - titleRes = R.string.pref_refresh_library_tracking - summaryRes = R.string.pref_refresh_library_tracking_summary - - onClick { LibraryUpdateService.start(context, target = Target.TRACKING) } - } - } - preference { - key = "pref_reset_viewer_flags" - titleRes = R.string.pref_reset_viewer_flags - summaryRes = R.string.pref_reset_viewer_flags_summary - - onClick { resetViewerFlags() } - } - } - - preferenceCategory { - titleRes = R.string.label_extensions - - listPreference { - bindTo(preferences.extensionInstaller()) - titleRes = R.string.ext_installer_pref - summary = "%s" - - // PackageInstaller doesn't work on MIUI properly for non-allowlisted apps - val values = if (DeviceUtil.isMiui) { - PreferenceValues.ExtensionInstaller.values() - .filter { it != PreferenceValues.ExtensionInstaller.PACKAGEINSTALLER } - } else { - PreferenceValues.ExtensionInstaller.values().toList() - } - - entriesRes = values.map { it.titleResId }.toTypedArray() - entryValues = values.map { it.name }.toTypedArray() - - onChange { - if (it == PreferenceValues.ExtensionInstaller.SHIZUKU.name && - !(context.isPackageInstalled("moe.shizuku.privileged.api") || Sui.isSui()) - ) { - MaterialAlertDialogBuilder(context) - .setTitle(R.string.ext_installer_shizuku) - .setMessage(R.string.ext_installer_shizuku_unavailable_dialog) - .setPositiveButton(android.R.string.ok) { _, _ -> - openInBrowser("https://shizuku.rikka.app/download") - } - .setNegativeButton(android.R.string.cancel, null) - .show() - false - } else { - true - } - } - } - } - - preferenceCategory { - titleRes = R.string.pref_category_display - - listPreference { - bindTo(uiPreferences.tabletUiMode()) - titleRes = R.string.pref_tablet_ui_mode - summary = "%s" - entriesRes = TabletUiMode.values().map { it.titleResId }.toTypedArray() - entryValues = TabletUiMode.values().map { it.name }.toTypedArray() - - onChange { - activity?.toast(R.string.requires_app_restart) - true - } - } - } - } - - private fun clearChapterCache() { - val activity = activity ?: return - viewScope.launchNonCancellable { - try { - val deletedFiles = chapterCache.clear() - withUIContext { - activity.toast(resources?.getString(R.string.cache_deleted, deletedFiles)) - findPreference(CLEAR_CACHE_KEY)?.summary = - resources?.getString(R.string.used_cache, chapterCache.readableSize) - } - } catch (e: Throwable) { - logcat(LogPriority.ERROR, e) - withUIContext { activity.toast(R.string.cache_delete_error) } - } - } - } - - private fun clearWebViewData() { - val activity = activity ?: return - try { - WebView(activity).run { - setDefaultSettings() - clearCache(true) - clearFormData() - clearHistory() - clearSslPreferences() - } - WebStorage.getInstance().deleteAllData() - activity.applicationInfo?.dataDir?.let { File("$it/app_webview/").deleteRecursively() } - activity.toast(R.string.webview_data_deleted) - } catch (e: Throwable) { - logcat(LogPriority.ERROR, e) - activity.toast(R.string.cache_delete_error) - } - } - - private fun resetViewerFlags() { - val activity = activity ?: return - viewScope.launchNonCancellable { - val success = mangaRepository.resetViewerFlags() - withUIContext { - val message = if (success) { - R.string.pref_reset_viewer_flags_success - } else { - R.string.pref_reset_viewer_flags_error - } - activity.toast(message) - } - } - } -} - -private const val CLEAR_CACHE_KEY = "pref_clear_cache_key" diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAppearanceController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAppearanceController.kt deleted file mode 100644 index 9de77183c2..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAppearanceController.kt +++ /dev/null @@ -1,173 +0,0 @@ -package eu.kanade.tachiyomi.ui.setting - -import android.os.Build -import android.os.Bundle -import android.view.View -import androidx.core.app.ActivityCompat -import androidx.preference.PreferenceScreen -import eu.kanade.domain.ui.UiPreferences -import eu.kanade.domain.ui.model.AppTheme -import eu.kanade.domain.ui.model.ThemeMode -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.util.preference.bindTo -import eu.kanade.tachiyomi.util.preference.entriesRes -import eu.kanade.tachiyomi.util.preference.initThenAdd -import eu.kanade.tachiyomi.util.preference.intListPreference -import eu.kanade.tachiyomi.util.preference.listPreference -import eu.kanade.tachiyomi.util.preference.onChange -import eu.kanade.tachiyomi.util.preference.preferenceCategory -import eu.kanade.tachiyomi.util.preference.switchPreference -import eu.kanade.tachiyomi.util.preference.titleRes -import eu.kanade.tachiyomi.util.system.DeviceUtil -import eu.kanade.tachiyomi.util.system.isDynamicColorAvailable -import eu.kanade.tachiyomi.util.system.isTablet -import eu.kanade.tachiyomi.widget.preference.ThemesPreference -import uy.kohesive.injekt.injectLazy -import java.util.Date - -class SettingsAppearanceController : SettingsController() { - - private var themesPreference: ThemesPreference? = null - private val uiPreferences: UiPreferences by injectLazy() - - override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply { - titleRes = R.string.pref_category_appearance - - preferenceCategory { - titleRes = R.string.pref_category_theme - - listPreference { - bindTo(uiPreferences.themeMode()) - titleRes = R.string.pref_theme_mode - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - entriesRes = arrayOf( - R.string.theme_system, - R.string.theme_light, - R.string.theme_dark, - ) - entryValues = arrayOf( - ThemeMode.SYSTEM.name, - ThemeMode.LIGHT.name, - ThemeMode.DARK.name, - ) - } else { - entriesRes = arrayOf( - R.string.theme_light, - R.string.theme_dark, - ) - entryValues = arrayOf( - ThemeMode.LIGHT.name, - ThemeMode.DARK.name, - ) - } - - summary = "%s" - } - themesPreference = initThenAdd(ThemesPreference(context)) { - bindTo(uiPreferences.appTheme()) - titleRes = R.string.pref_app_theme - - val appThemes = AppTheme.values().filter { - val monetFilter = if (it == AppTheme.MONET) { - DeviceUtil.isDynamicColorAvailable - } else { - true - } - it.titleResId != null && monetFilter - } - entries = appThemes - - onChange { - activity?.let { ActivityCompat.recreate(it) } - true - } - } - switchPreference { - bindTo(uiPreferences.themeDarkAmoled()) - titleRes = R.string.pref_dark_theme_pure_black - - visibleIf(uiPreferences.themeMode()) { it != ThemeMode.LIGHT } - - onChange { - activity?.let { ActivityCompat.recreate(it) } - true - } - } - } - - if (context.isTablet()) { - preferenceCategory { - titleRes = R.string.pref_category_navigation - - intListPreference { - bindTo(uiPreferences.sideNavIconAlignment()) - titleRes = R.string.pref_side_nav_icon_alignment - entriesRes = arrayOf( - R.string.alignment_top, - R.string.alignment_center, - R.string.alignment_bottom, - ) - entryValues = arrayOf("0", "1", "2") - summary = "%s" - } - } - } - - preferenceCategory { - titleRes = R.string.pref_category_timestamps - - intListPreference { - bindTo(uiPreferences.relativeTime()) - titleRes = R.string.pref_relative_format - val values = arrayOf("0", "2", "7") - entryValues = values - entries = values.map { - when (it) { - "0" -> context.getString(R.string.off) - "2" -> context.getString(R.string.pref_relative_time_short) - else -> context.getString(R.string.pref_relative_time_long) - } - }.toTypedArray() - summary = "%s" - } - - listPreference { - bindTo(uiPreferences.dateFormat()) - titleRes = R.string.pref_date_format - entryValues = arrayOf("", "MM/dd/yy", "dd/MM/yy", "yyyy-MM-dd", "dd MMM yyyy", "MMM dd, yyyy") - - val now = Date().time - entries = entryValues.map { value -> - val formattedDate = UiPreferences.dateFormat(value.toString()).format(now) - if (value == "") { - "${context.getString(R.string.label_default)} ($formattedDate)" - } else { - "$value ($formattedDate)" - } - }.toTypedArray() - - summary = "%s" - } - } - } - - override fun onSaveViewState(view: View, outState: Bundle) { - themesPreference?.let { - outState.putInt(THEMES_SCROLL_POSITION, it.lastScrollPosition ?: 0) - } - super.onSaveInstanceState(outState) - } - - override fun onRestoreViewState(view: View, savedViewState: Bundle) { - super.onRestoreViewState(view, savedViewState) - themesPreference?.lastScrollPosition = savedViewState.getInt(THEMES_SCROLL_POSITION, 0) - } - - override fun onDestroyView(view: View) { - super.onDestroyView(view) - themesPreference = null - } -} - -private const val THEMES_SCROLL_POSITION = "themesScrollPosition" diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt deleted file mode 100644 index e21b3a177f..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt +++ /dev/null @@ -1,306 +0,0 @@ -package eu.kanade.tachiyomi.ui.setting - -import android.Manifest.permission.WRITE_EXTERNAL_STORAGE -import android.app.Activity -import android.app.Dialog -import android.content.ActivityNotFoundException -import android.content.Intent -import android.net.Uri -import android.os.Bundle -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem -import android.view.View -import android.widget.Toast -import androidx.appcompat.app.AlertDialog -import androidx.core.net.toUri -import androidx.core.os.bundleOf -import androidx.preference.PreferenceScreen -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.hippo.unifile.UniFile -import eu.kanade.domain.backup.service.BackupPreferences -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.backup.BackupConst -import eu.kanade.tachiyomi.data.backup.BackupCreatorJob -import eu.kanade.tachiyomi.data.backup.BackupFileValidator -import eu.kanade.tachiyomi.data.backup.BackupRestoreService -import eu.kanade.tachiyomi.data.backup.models.Backup -import eu.kanade.tachiyomi.ui.base.controller.DialogController -import eu.kanade.tachiyomi.ui.base.controller.requestPermissionsSafe -import eu.kanade.tachiyomi.util.preference.bindTo -import eu.kanade.tachiyomi.util.preference.entriesRes -import eu.kanade.tachiyomi.util.preference.infoPreference -import eu.kanade.tachiyomi.util.preference.intListPreference -import eu.kanade.tachiyomi.util.preference.onChange -import eu.kanade.tachiyomi.util.preference.onClick -import eu.kanade.tachiyomi.util.preference.preference -import eu.kanade.tachiyomi.util.preference.preferenceCategory -import eu.kanade.tachiyomi.util.preference.summaryRes -import eu.kanade.tachiyomi.util.preference.titleRes -import eu.kanade.tachiyomi.util.system.DeviceUtil -import eu.kanade.tachiyomi.util.system.getParcelableCompat -import eu.kanade.tachiyomi.util.system.openInBrowser -import eu.kanade.tachiyomi.util.system.toast -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import uy.kohesive.injekt.injectLazy - -class SettingsBackupController : SettingsController() { - - /** - * Flags containing information of what to backup. - */ - private var backupFlags = 0 - - private val backupPreferences: BackupPreferences by injectLazy() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - requestPermissionsSafe(arrayOf(WRITE_EXTERNAL_STORAGE), 500) - } - - override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply { - titleRes = R.string.label_backup - - preference { - key = "pref_create_backup" - titleRes = R.string.pref_create_backup - summaryRes = R.string.pref_create_backup_summ - - onClick { - if (DeviceUtil.isMiui && DeviceUtil.isMiuiOptimizationDisabled()) { - context.toast(R.string.restore_miui_warning, Toast.LENGTH_LONG) - } - - if (!BackupCreatorJob.isManualJobRunning(context)) { - val ctrl = CreateBackupDialog() - ctrl.targetController = this@SettingsBackupController - ctrl.showDialog(router) - } else { - context.toast(R.string.backup_in_progress) - } - } - } - preference { - key = "pref_restore_backup" - titleRes = R.string.pref_restore_backup - summaryRes = R.string.pref_restore_backup_summ - - onClick { - if (DeviceUtil.isMiui && DeviceUtil.isMiuiOptimizationDisabled()) { - context.toast(R.string.restore_miui_warning, Toast.LENGTH_LONG) - } - - if (!BackupRestoreService.isRunning(context)) { - val intent = Intent(Intent.ACTION_GET_CONTENT).apply { - addCategory(Intent.CATEGORY_OPENABLE) - type = "*/*" - } - val title = resources?.getString(R.string.file_select_backup) - val chooser = Intent.createChooser(intent, title) - startActivityForResult(chooser, CODE_BACKUP_RESTORE) - } else { - context.toast(R.string.restore_in_progress) - } - } - } - - preferenceCategory { - titleRes = R.string.pref_backup_service_category - - intListPreference { - bindTo(backupPreferences.backupInterval()) - titleRes = R.string.pref_backup_interval - entriesRes = arrayOf( - R.string.update_6hour, - R.string.update_12hour, - R.string.update_24hour, - R.string.update_48hour, - R.string.update_weekly, - ) - entryValues = arrayOf("6", "12", "24", "48", "168") - summary = "%s" - - onChange { newValue -> - val interval = (newValue as String).toInt() - BackupCreatorJob.setupTask(context, interval) - true - } - } - preference { - bindTo(backupPreferences.backupsDirectory()) - titleRes = R.string.pref_backup_directory - - onClick { - try { - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) - startActivityForResult(intent, CODE_BACKUP_DIR) - } catch (e: ActivityNotFoundException) { - activity?.toast(R.string.file_picker_error) - } - } - - backupPreferences.backupsDirectory().changes() - .onEach { path -> - val dir = UniFile.fromUri(context, path.toUri()) - summary = dir.filePath + "/automatic" - } - .launchIn(viewScope) - } - intListPreference { - bindTo(backupPreferences.numberOfBackups()) - titleRes = R.string.pref_backup_slots - entries = arrayOf("2", "3", "4", "5") - entryValues = entries - summary = "%s" - } - } - - infoPreference(R.string.backup_info) - } - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - inflater.inflate(R.menu.settings_backup, menu) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - R.id.action_backup_help -> activity?.openInBrowser(HELP_URL) - } - return super.onOptionsItemSelected(item) - } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - if (data != null && resultCode == Activity.RESULT_OK) { - val activity = activity ?: return - val uri = data.data - - if (uri == null) { - activity.toast(R.string.backup_restore_invalid_uri) - return - } - - when (requestCode) { - CODE_BACKUP_DIR -> { - // Get UriPermission so it's possible to write files - val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or - Intent.FLAG_GRANT_WRITE_URI_PERMISSION - - activity.contentResolver.takePersistableUriPermission(uri, flags) - backupPreferences.backupsDirectory().set(uri.toString()) - } - CODE_BACKUP_CREATE -> { - val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or - Intent.FLAG_GRANT_WRITE_URI_PERMISSION - - activity.contentResolver.takePersistableUriPermission(uri, flags) - BackupCreatorJob.startNow(activity, uri, backupFlags) - } - CODE_BACKUP_RESTORE -> { - RestoreBackupDialog(uri).showDialog(router) - } - } - } - } - - fun createBackup(flags: Int) { - backupFlags = flags - try { - val intent = Intent(Intent.ACTION_CREATE_DOCUMENT) - .addCategory(Intent.CATEGORY_OPENABLE) - .setType("application/*") - .putExtra(Intent.EXTRA_TITLE, Backup.getBackupFilename()) - - startActivityForResult(intent, CODE_BACKUP_CREATE) - } catch (e: ActivityNotFoundException) { - activity?.toast(R.string.file_picker_error) - } - } - - class CreateBackupDialog(bundle: Bundle? = null) : DialogController(bundle) { - override fun onCreateDialog(savedViewState: Bundle?): Dialog { - val activity = activity!! - val options = arrayOf( - R.string.manga, - R.string.categories, - R.string.chapters, - R.string.track, - R.string.history, - ) - .map { activity.getString(it) } - val selected = options.map { true }.toBooleanArray() - - return MaterialAlertDialogBuilder(activity) - .setTitle(R.string.backup_choice) - .setMultiChoiceItems(options.toTypedArray(), selected) { dialog, which, checked -> - if (which == 0) { - (dialog as AlertDialog).listView.setItemChecked(which, true) - } else { - selected[which] = checked - } - } - .setPositiveButton(R.string.action_create) { _, _ -> - var flags = 0 - selected.forEachIndexed { i, checked -> - if (checked) { - when (i) { - 1 -> flags = flags or BackupConst.BACKUP_CATEGORY - 2 -> flags = flags or BackupConst.BACKUP_CHAPTER - 3 -> flags = flags or BackupConst.BACKUP_TRACK - 4 -> flags = flags or BackupConst.BACKUP_HISTORY - } - } - } - - (targetController as? SettingsBackupController)?.createBackup(flags) - } - .setNegativeButton(android.R.string.cancel, null) - .create() - } - } - - class RestoreBackupDialog(bundle: Bundle? = null) : DialogController(bundle) { - constructor(uri: Uri) : this( - bundleOf(KEY_URI to uri), - ) - - override fun onCreateDialog(savedViewState: Bundle?): Dialog { - val activity = activity!! - val uri = args.getParcelableCompat(KEY_URI)!! - - return try { - val results = BackupFileValidator().validate(activity, uri) - - var message = activity.getString(R.string.backup_restore_content_full) - if (results.missingSources.isNotEmpty()) { - message += "\n\n${activity.getString(R.string.backup_restore_missing_sources)}\n${results.missingSources.joinToString("\n") { "- $it" }}" - } - if (results.missingTrackers.isNotEmpty()) { - message += "\n\n${activity.getString(R.string.backup_restore_missing_trackers)}\n${results.missingTrackers.joinToString("\n") { "- $it" }}" - } - - MaterialAlertDialogBuilder(activity) - .setTitle(R.string.pref_restore_backup) - .setMessage(message) - .setPositiveButton(R.string.action_restore) { _, _ -> - BackupRestoreService.start(activity, uri) - } - .create() - } catch (e: Exception) { - MaterialAlertDialogBuilder(activity) - .setTitle(R.string.invalid_backup_file) - .setMessage(e.message) - .setPositiveButton(android.R.string.cancel, null) - .create() - } - } - } -} - -private const val KEY_URI = "RestoreBackupDialog.uri" - -private const val CODE_BACKUP_DIR = 503 -private const val CODE_BACKUP_CREATE = 504 -private const val CODE_BACKUP_RESTORE = 505 - -private const val HELP_URL = "https://tachiyomi.org/help/guides/backups/" diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBrowseController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBrowseController.kt deleted file mode 100644 index ede9d6f00c..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBrowseController.kt +++ /dev/null @@ -1,80 +0,0 @@ -package eu.kanade.tachiyomi.ui.setting - -import androidx.fragment.app.FragmentActivity -import androidx.preference.PreferenceScreen -import eu.kanade.domain.source.service.SourcePreferences -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.extension.ExtensionUpdateJob -import eu.kanade.tachiyomi.util.preference.bindTo -import eu.kanade.tachiyomi.util.preference.infoPreference -import eu.kanade.tachiyomi.util.preference.onChange -import eu.kanade.tachiyomi.util.preference.preferenceCategory -import eu.kanade.tachiyomi.util.preference.requireAuthentication -import eu.kanade.tachiyomi.util.preference.summaryRes -import eu.kanade.tachiyomi.util.preference.switchPreference -import eu.kanade.tachiyomi.util.preference.titleRes -import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.isAuthenticationSupported -import uy.kohesive.injekt.injectLazy - -class SettingsBrowseController : SettingsController() { - - private val sourcePreferences: SourcePreferences by injectLazy() - - override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply { - titleRes = R.string.browse - - preferenceCategory { - titleRes = R.string.label_sources - - switchPreference { - bindTo(sourcePreferences.duplicatePinnedSources()) - titleRes = R.string.pref_duplicate_pinned_sources - summaryRes = R.string.pref_duplicate_pinned_sources_summary - } - } - - preferenceCategory { - titleRes = R.string.label_extensions - - switchPreference { - bindTo(preferences.automaticExtUpdates()) - titleRes = R.string.pref_enable_automatic_extension_updates - - onChange { newValue -> - val checked = newValue as Boolean - ExtensionUpdateJob.setupTask(activity!!, checked) - true - } - } - } - - preferenceCategory { - titleRes = R.string.action_global_search - - switchPreference { - bindTo(sourcePreferences.searchPinnedSourcesOnly()) - titleRes = R.string.pref_search_pinned_sources_only - } - } - - preferenceCategory { - titleRes = R.string.pref_category_nsfw_content - - switchPreference { - bindTo(sourcePreferences.showNsfwSource()) - titleRes = R.string.pref_show_nsfw_source - summaryRes = R.string.requires_app_restart - - if (context.isAuthenticationSupported() && activity != null) { - requireAuthentication( - activity as? FragmentActivity, - context.getString(R.string.pref_category_nsfw_content), - context.getString(R.string.confirm_lock_change), - ) - } - } - - infoPreference(R.string.parental_controls_info) - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsController.kt deleted file mode 100644 index ecef08a430..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsController.kt +++ /dev/null @@ -1,124 +0,0 @@ -package eu.kanade.tachiyomi.ui.setting - -import android.animation.ArgbEvaluator -import android.animation.ValueAnimator -import android.content.Context -import android.graphics.Color -import android.os.Bundle -import android.util.TypedValue -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.view.ContextThemeWrapper -import androidx.core.animation.doOnEnd -import androidx.preference.Preference -import androidx.preference.PreferenceController -import androidx.preference.PreferenceGroup -import androidx.preference.PreferenceScreen -import com.bluelinelabs.conductor.ControllerChangeHandler -import com.bluelinelabs.conductor.ControllerChangeType -import dev.chrisbanes.insetter.applyInsetter -import eu.kanade.domain.base.BasePreferences -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.util.preference.asHotFlow -import eu.kanade.tachiyomi.util.system.getResourceColor -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.MainScope -import kotlinx.coroutines.cancel -import kotlinx.coroutines.flow.launchIn -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get - -abstract class SettingsController : PreferenceController() { - - var preferenceKey: String? = null - val preferences: BasePreferences = Injekt.get() - val viewScope: CoroutineScope = MainScope() - private var themedContext: Context? = null - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View { - val view = super.onCreateView(inflater, container, savedInstanceState) - - listView.applyInsetter { - type(navigationBars = true) { - padding() - } - } - - return view - } - - override fun onAttach(view: View) { - super.onAttach(view) - - preferenceKey?.let { prefKey -> - val adapter = listView.adapter - scrollToPreference(prefKey) - - listView.post { - if (adapter is PreferenceGroup.PreferencePositionCallback) { - val pos = adapter.getPreferenceAdapterPosition(prefKey) - listView.findViewHolderForAdapterPosition(pos)?.let { - animatePreferenceHighlight(it.itemView) - } - } - - // Explicitly clear it to avoid re-scrolling/animating on activity recreations - preferenceKey = null - } - } - } - - override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) { - if (type.isEnter) { - setTitle() - } - setHasOptionsMenu(type.isEnter) - super.onChangeStarted(handler, type) - } - - override fun onDestroyView(view: View) { - super.onDestroyView(view) - viewScope.cancel() - themedContext = null - } - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - val tv = TypedValue() - activity!!.theme.resolveAttribute(R.attr.preferenceTheme, tv, true) - themedContext = ContextThemeWrapper(activity, tv.resourceId) - - val screen = preferenceManager.createPreferenceScreen(themedContext!!) - preferenceScreen = screen - setupPreferenceScreen(screen) - } - - abstract fun setupPreferenceScreen(screen: PreferenceScreen): PreferenceScreen - - private fun animatePreferenceHighlight(view: View) { - val origBackground = view.background - ValueAnimator - .ofObject(ArgbEvaluator(), Color.TRANSPARENT, view.context.getResourceColor(R.attr.colorControlHighlight)) - .apply { - duration = 200L - repeatCount = 5 - repeatMode = ValueAnimator.REVERSE - addUpdateListener { animator -> view.setBackgroundColor(animator.animatedValue as Int) } - start() - } - .doOnEnd { - // Restore original ripple - view.background = origBackground - } - } - - private fun setTitle() { - (activity as? AppCompatActivity)?.supportActionBar?.title = preferenceScreen?.title?.toString() - } - - inline fun Preference.visibleIf(preference: eu.kanade.tachiyomi.core.preference.Preference, crossinline block: (T) -> Boolean) { - preference.asHotFlow { isVisible = block(it) } - .launchIn(viewScope) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt deleted file mode 100644 index 1ad9f997d3..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt +++ /dev/null @@ -1,315 +0,0 @@ -package eu.kanade.tachiyomi.ui.setting - -import android.app.Activity -import android.app.Dialog -import android.content.ActivityNotFoundException -import android.content.Intent -import android.os.Bundle -import android.os.Environment -import androidx.core.net.toUri -import androidx.core.text.buildSpannedString -import androidx.preference.PreferenceScreen -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.hippo.unifile.UniFile -import eu.kanade.domain.category.interactor.GetCategories -import eu.kanade.domain.download.service.DownloadPreferences -import eu.kanade.presentation.category.visualName -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.ui.base.controller.DialogController -import eu.kanade.tachiyomi.util.preference.bindTo -import eu.kanade.tachiyomi.util.preference.entriesRes -import eu.kanade.tachiyomi.util.preference.infoPreference -import eu.kanade.tachiyomi.util.preference.intListPreference -import eu.kanade.tachiyomi.util.preference.multiSelectListPreference -import eu.kanade.tachiyomi.util.preference.onClick -import eu.kanade.tachiyomi.util.preference.preference -import eu.kanade.tachiyomi.util.preference.preferenceCategory -import eu.kanade.tachiyomi.util.preference.summaryRes -import eu.kanade.tachiyomi.util.preference.switchPreference -import eu.kanade.tachiyomi.util.preference.titleRes -import eu.kanade.tachiyomi.util.system.toast -import eu.kanade.tachiyomi.widget.materialdialogs.QuadStateTextView -import eu.kanade.tachiyomi.widget.materialdialogs.setQuadStateMultiChoiceItems -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.runBlocking -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get -import uy.kohesive.injekt.injectLazy -import java.io.File - -class SettingsDownloadController : SettingsController() { - - private val getCategories: GetCategories by injectLazy() - private val downloadPreferences: DownloadPreferences by injectLazy() - - override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply { - titleRes = R.string.pref_category_downloads - - val categories = runBlocking { getCategories.await() } - - preference { - bindTo(downloadPreferences.downloadsDirectory()) - titleRes = R.string.pref_download_directory - onClick { - val ctrl = DownloadDirectoriesDialog() - ctrl.targetController = this@SettingsDownloadController - ctrl.showDialog(router) - } - - downloadPreferences.downloadsDirectory().changes() - .onEach { path -> - val dir = UniFile.fromUri(context, path.toUri()) - summary = dir.filePath ?: path - } - .launchIn(viewScope) - } - switchPreference { - bindTo(downloadPreferences.downloadOnlyOverWifi()) - titleRes = R.string.connected_to_wifi - } - switchPreference { - bindTo(downloadPreferences.saveChaptersAsCBZ()) - titleRes = R.string.save_chapter_as_cbz - } - switchPreference { - bindTo(downloadPreferences.splitTallImages()) - titleRes = R.string.split_tall_images - summaryRes = R.string.split_tall_images_summary - } - - preferenceCategory { - titleRes = R.string.pref_category_delete_chapters - - switchPreference { - bindTo(downloadPreferences.removeAfterMarkedAsRead()) - titleRes = R.string.pref_remove_after_marked_as_read - } - intListPreference { - bindTo(downloadPreferences.removeAfterReadSlots()) - titleRes = R.string.pref_remove_after_read - entriesRes = arrayOf( - R.string.disabled, - R.string.last_read_chapter, - R.string.second_to_last, - R.string.third_to_last, - R.string.fourth_to_last, - R.string.fifth_to_last, - ) - entryValues = arrayOf("-1", "0", "1", "2", "3", "4") - summary = "%s" - } - switchPreference { - bindTo(downloadPreferences.removeBookmarkedChapters()) - titleRes = R.string.pref_remove_bookmarked_chapters - } - multiSelectListPreference { - bindTo(downloadPreferences.removeExcludeCategories()) - titleRes = R.string.pref_remove_exclude_categories - entries = categories.map { it.visualName(context) }.toTypedArray() - entryValues = categories.map { it.id.toString() }.toTypedArray() - - downloadPreferences.removeExcludeCategories().changes() - .onEach { mutable -> - val selected = mutable - .mapNotNull { id -> categories.find { it.id == id.toLong() } } - .sortedBy { it.order } - - summary = if (selected.isEmpty()) { - resources?.getString(R.string.none) - } else { - selected.joinToString { it.visualName(context) } - } - }.launchIn(viewScope) - } - } - - preferenceCategory { - titleRes = R.string.pref_download_new - - switchPreference { - bindTo(downloadPreferences.downloadNewChapters()) - titleRes = R.string.pref_download_new - } - preference { - bindTo(downloadPreferences.downloadNewChapterCategories()) - titleRes = R.string.categories - onClick { - DownloadCategoriesDialog().showDialog(router) - } - - visibleIf(downloadPreferences.downloadNewChapters()) { it } - - fun updateSummary() { - val selectedCategories = downloadPreferences.downloadNewChapterCategories().get() - .mapNotNull { id -> categories.find { it.id == id.toLong() } } - .sortedBy { it.order } - val includedItemsText = if (selectedCategories.isEmpty()) { - context.getString(R.string.all) - } else { - selectedCategories.joinToString { it.visualName(context) } - } - - val excludedCategories = downloadPreferences.downloadNewChapterCategoriesExclude().get() - .mapNotNull { id -> categories.find { it.id == id.toLong() } } - .sortedBy { it.order } - val excludedItemsText = if (excludedCategories.isEmpty()) { - context.getString(R.string.none) - } else { - excludedCategories.joinToString { it.visualName(context) } - } - - summary = buildSpannedString { - append(context.getString(R.string.include, includedItemsText)) - appendLine() - append(context.getString(R.string.exclude, excludedItemsText)) - } - } - - downloadPreferences.downloadNewChapterCategories().changes() - .onEach { updateSummary() } - .launchIn(viewScope) - downloadPreferences.downloadNewChapterCategoriesExclude().changes() - .onEach { updateSummary() } - .launchIn(viewScope) - } - } - - preferenceCategory { - titleRes = R.string.download_ahead - - intListPreference { - bindTo(downloadPreferences.autoDownloadWhileReading()) - titleRes = R.string.auto_download_while_reading - entries = arrayOf( - context.getString(R.string.disabled), - context.resources.getQuantityString(R.plurals.next_unread_chapters, 2, 2), - context.resources.getQuantityString(R.plurals.next_unread_chapters, 3, 3), - context.resources.getQuantityString(R.plurals.next_unread_chapters, 5, 5), - context.resources.getQuantityString(R.plurals.next_unread_chapters, 10, 10), - ) - entryValues = arrayOf("0", "2", "3", "5", "10") - summary = "%s" - } - infoPreference(R.string.download_ahead_info) - } - } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - when (requestCode) { - DOWNLOAD_DIR -> if (data != null && resultCode == Activity.RESULT_OK) { - val context = applicationContext ?: return - val uri = data.data - val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or - Intent.FLAG_GRANT_WRITE_URI_PERMISSION - - if (uri != null) { - @Suppress("NewApi") - context.contentResolver.takePersistableUriPermission(uri, flags) - } - - val file = UniFile.fromUri(context, uri) - downloadPreferences.downloadsDirectory().set(file.uri.toString()) - } - } - } - - fun predefinedDirectorySelected(selectedDir: String) { - val path = File(selectedDir).toUri() - downloadPreferences.downloadsDirectory().set(path.toString()) - } - - fun customDirectorySelected() { - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) - try { - startActivityForResult(intent, DOWNLOAD_DIR) - } catch (e: ActivityNotFoundException) { - activity?.toast(R.string.file_picker_error) - } - } - - class DownloadDirectoriesDialog : DialogController() { - - private val downloadPreferences: DownloadPreferences = Injekt.get() - - override fun onCreateDialog(savedViewState: Bundle?): Dialog { - val activity = activity!! - val currentDir = downloadPreferences.downloadsDirectory().get() - val externalDirs = listOf(getDefaultDownloadDir(), File(activity.getString(R.string.custom_dir))).map(File::toString) - var selectedIndex = externalDirs.indexOfFirst { it in currentDir } - - return MaterialAlertDialogBuilder(activity) - .setTitle(R.string.pref_download_directory) - .setSingleChoiceItems(externalDirs.toTypedArray(), selectedIndex) { _, which -> - selectedIndex = which - } - .setPositiveButton(android.R.string.ok) { _, _ -> - val target = targetController as? SettingsDownloadController - if (selectedIndex == externalDirs.lastIndex) { - target?.customDirectorySelected() - } else { - target?.predefinedDirectorySelected(externalDirs[selectedIndex]) - } - } - .create() - } - - private fun getDefaultDownloadDir(): File { - val defaultDir = Environment.getExternalStorageDirectory().absolutePath + - File.separator + resources?.getString(R.string.app_name) + - File.separator + "downloads" - - return File(defaultDir) - } - } - - class DownloadCategoriesDialog : DialogController() { - - private val downloadPreferences: DownloadPreferences = Injekt.get() - private val getCategories: GetCategories = Injekt.get() - - override fun onCreateDialog(savedViewState: Bundle?): Dialog { - val categories = runBlocking { getCategories.await() } - - val items = categories.map { it.visualName(activity!!) } - var selected = categories - .map { - when (it.id.toString()) { - in downloadPreferences.downloadNewChapterCategories().get() -> QuadStateTextView.State.CHECKED.ordinal - in downloadPreferences.downloadNewChapterCategoriesExclude().get() -> QuadStateTextView.State.INVERSED.ordinal - else -> QuadStateTextView.State.UNCHECKED.ordinal - } - } - .toIntArray() - - return MaterialAlertDialogBuilder(activity!!) - .setTitle(R.string.categories) - .setQuadStateMultiChoiceItems( - message = R.string.pref_download_new_categories_details, - items = items, - initialSelected = selected, - ) { selections -> - selected = selections - } - .setPositiveButton(android.R.string.ok) { _, _ -> - val included = selected - .mapIndexed { index, value -> if (value == QuadStateTextView.State.CHECKED.ordinal) index else null } - .filterNotNull() - .map { categories[it].id.toString() } - .toSet() - val excluded = selected - .mapIndexed { index, value -> if (value == QuadStateTextView.State.INVERSED.ordinal) index else null } - .filterNotNull() - .map { categories[it].id.toString() } - .toSet() - - downloadPreferences.downloadNewChapterCategories().set(included) - downloadPreferences.downloadNewChapterCategoriesExclude().set(excluded) - } - .setNegativeButton(android.R.string.cancel, null) - .create() - } - } -} - -private const val DOWNLOAD_DIR = 104 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt deleted file mode 100644 index 220f785a19..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt +++ /dev/null @@ -1,92 +0,0 @@ -package eu.kanade.tachiyomi.ui.setting - -import android.content.Intent -import android.os.Build -import android.provider.Settings -import androidx.appcompat.app.AppCompatDelegate -import androidx.core.os.LocaleListCompat -import androidx.preference.PreferenceScreen -import eu.kanade.domain.library.service.LibraryPreferences -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.util.preference.bindTo -import eu.kanade.tachiyomi.util.preference.listPreference -import eu.kanade.tachiyomi.util.preference.onChange -import eu.kanade.tachiyomi.util.preference.onClick -import eu.kanade.tachiyomi.util.preference.preference -import eu.kanade.tachiyomi.util.preference.switchPreference -import eu.kanade.tachiyomi.util.preference.titleRes -import eu.kanade.tachiyomi.util.system.LocaleHelper -import org.xmlpull.v1.XmlPullParser -import uy.kohesive.injekt.injectLazy - -class SettingsGeneralController : SettingsController() { - - private val libraryPreferences: LibraryPreferences by injectLazy() - - override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply { - titleRes = R.string.pref_category_general - - switchPreference { - bindTo(libraryPreferences.showUpdatesNavBadge()) - titleRes = R.string.pref_library_update_show_tab_badge - } - switchPreference { - bindTo(preferences.confirmExit()) - titleRes = R.string.pref_confirm_exit - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - preference { - key = "pref_manage_notifications" - titleRes = R.string.pref_manage_notifications - onClick { - val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { - putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) - } - startActivity(intent) - } - } - } - listPreference { - key = "app_lang" - isPersistent = false - titleRes = R.string.pref_app_language - - val langs = mutableListOf>() - - val parser = context.resources.getXml(R.xml.locales_config) - var eventType = parser.eventType - while (eventType != XmlPullParser.END_DOCUMENT) { - if (eventType == XmlPullParser.START_TAG && parser.name == "locale") { - for (i in 0 until parser.attributeCount) { - if (parser.getAttributeName(i) == "name") { - val langTag = parser.getAttributeValue(i) - val displayName = LocaleHelper.getDisplayName(langTag) - if (displayName.isNotEmpty()) { - langs.add(Pair(langTag, displayName)) - } - } - } - } - eventType = parser.next() - } - - langs.sortBy { it.second } - langs.add(0, Pair("", context.getString(R.string.label_default))) - - entryValues = langs.map { it.first }.toTypedArray() - entries = langs.map { it.second }.toTypedArray() - summary = "%s" - value = AppCompatDelegate.getApplicationLocales().get(0)?.toLanguageTag() ?: "" - - onChange { newValue -> - val locale = if ((newValue as String).isEmpty()) { - LocaleListCompat.getEmptyLocaleList() - } else { - LocaleListCompat.forLanguageTags(newValue) - } - AppCompatDelegate.setApplicationLocales(locale) - true - } - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt deleted file mode 100644 index 26698302ee..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt +++ /dev/null @@ -1,388 +0,0 @@ -package eu.kanade.tachiyomi.ui.setting - -import android.app.Dialog -import android.os.Bundle -import android.view.LayoutInflater -import androidx.core.content.ContextCompat -import androidx.core.text.buildSpannedString -import androidx.preference.PreferenceScreen -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import eu.kanade.domain.category.interactor.GetCategories -import eu.kanade.domain.category.interactor.ResetCategoryFlags -import eu.kanade.domain.category.model.Category -import eu.kanade.domain.library.service.LibraryPreferences -import eu.kanade.presentation.category.visualName -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.library.LibraryUpdateJob -import eu.kanade.tachiyomi.data.preference.DEVICE_BATTERY_NOT_LOW -import eu.kanade.tachiyomi.data.preference.DEVICE_CHARGING -import eu.kanade.tachiyomi.data.preference.DEVICE_NETWORK_NOT_METERED -import eu.kanade.tachiyomi.data.preference.DEVICE_ONLY_ON_WIFI -import eu.kanade.tachiyomi.data.preference.MANGA_HAS_UNREAD -import eu.kanade.tachiyomi.data.preference.MANGA_NON_COMPLETED -import eu.kanade.tachiyomi.data.preference.MANGA_NON_READ -import eu.kanade.tachiyomi.data.track.TrackManager -import eu.kanade.tachiyomi.databinding.PrefLibraryColumnsBinding -import eu.kanade.tachiyomi.ui.base.controller.DialogController -import eu.kanade.tachiyomi.ui.base.controller.pushController -import eu.kanade.tachiyomi.ui.category.CategoryController -import eu.kanade.tachiyomi.util.preference.bindTo -import eu.kanade.tachiyomi.util.preference.defaultValue -import eu.kanade.tachiyomi.util.preference.entriesRes -import eu.kanade.tachiyomi.util.preference.intListPreference -import eu.kanade.tachiyomi.util.preference.multiSelectListPreference -import eu.kanade.tachiyomi.util.preference.onChange -import eu.kanade.tachiyomi.util.preference.onClick -import eu.kanade.tachiyomi.util.preference.preference -import eu.kanade.tachiyomi.util.preference.preferenceCategory -import eu.kanade.tachiyomi.util.preference.summaryRes -import eu.kanade.tachiyomi.util.preference.switchPreference -import eu.kanade.tachiyomi.util.preference.titleRes -import eu.kanade.tachiyomi.widget.materialdialogs.QuadStateTextView -import eu.kanade.tachiyomi.widget.materialdialogs.setQuadStateMultiChoiceItems -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.runBlocking -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get -import uy.kohesive.injekt.injectLazy - -class SettingsLibraryController : SettingsController() { - - private val getCategories: GetCategories by injectLazy() - private val trackManager: TrackManager by injectLazy() - private val resetCategoryFlags: ResetCategoryFlags by injectLazy() - private val libraryPreferences: LibraryPreferences by injectLazy() - - override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply { - titleRes = R.string.pref_category_library - - val allCategories = runBlocking { getCategories.await() } - val userCategories = allCategories.filterNot(Category::isSystemCategory) - - preferenceCategory { - titleRes = R.string.pref_category_display - - preference { - key = "pref_library_columns" - titleRes = R.string.pref_library_columns - onClick { - LibraryColumnsDialog().showDialog(router) - } - - fun getColumnValue(value: Int): String { - return if (value == 0) { - context.getString(R.string.label_default) - } else { - value.toString() - } - } - - combine(libraryPreferences.portraitColumns().changes(), libraryPreferences.landscapeColumns().changes()) { portraitCols, landscapeCols -> Pair(portraitCols, landscapeCols) } - .onEach { (portraitCols, landscapeCols) -> - val portrait = getColumnValue(portraitCols) - val landscape = getColumnValue(landscapeCols) - summary = "${context.getString(R.string.portrait)}: $portrait, " + - "${context.getString(R.string.landscape)}: $landscape" - } - .launchIn(viewScope) - } - } - - preferenceCategory { - titleRes = R.string.categories - - preference { - key = "pref_action_edit_categories" - titleRes = R.string.action_edit_categories - - val catCount = userCategories.size - summary = context.resources.getQuantityString(R.plurals.num_categories, catCount, catCount) - - onClick { - router.pushController(CategoryController()) - } - } - - intListPreference { - val defaultCategory = libraryPreferences.defaultCategory() - bindTo(defaultCategory) - titleRes = R.string.default_category - - entries = arrayOf(context.getString(R.string.default_category_summary)) + - allCategories.map { it.visualName(context) }.toTypedArray() - entryValues = arrayOf(defaultCategory.defaultValue().toString()) + allCategories.map { it.id.toString() }.toTypedArray() - - val selectedCategory = allCategories.find { it.id == defaultCategory.get().toLong() } - summary = selectedCategory?.visualName(context) - ?: context.getString(R.string.default_category_summary) - onChange { newValue -> - summary = allCategories.find { - it.id == (newValue as String).toLong() - }?.visualName(context) ?: context.getString(R.string.default_category_summary) - true - } - } - - switchPreference { - bindTo(libraryPreferences.categorizedDisplaySettings()) - titleRes = R.string.categorized_display_settings - - libraryPreferences.categorizedDisplaySettings().changes() - .onEach { - if (it.not()) { - resetCategoryFlags.await() - } - } - .launchIn(viewScope) - } - } - - preferenceCategory { - titleRes = R.string.pref_category_library_update - - intListPreference { - bindTo(libraryPreferences.libraryUpdateInterval()) - titleRes = R.string.pref_library_update_interval - entriesRes = arrayOf( - R.string.update_never, - R.string.update_12hour, - R.string.update_24hour, - R.string.update_48hour, - R.string.update_72hour, - R.string.update_weekly, - ) - entryValues = arrayOf("0", "12", "24", "48", "72", "168") - summary = "%s" - - onChange { newValue -> - val interval = (newValue as String).toInt() - LibraryUpdateJob.setupTask(context, interval) - true - } - } - multiSelectListPreference { - bindTo(libraryPreferences.libraryUpdateDeviceRestriction()) - titleRes = R.string.pref_library_update_restriction - entriesRes = arrayOf(R.string.connected_to_wifi, R.string.network_not_metered, R.string.charging, R.string.battery_not_low) - entryValues = arrayOf(DEVICE_ONLY_ON_WIFI, DEVICE_NETWORK_NOT_METERED, DEVICE_CHARGING, DEVICE_BATTERY_NOT_LOW) - - visibleIf(libraryPreferences.libraryUpdateInterval()) { it > 0 } - - onChange { - // Post to event looper to allow the preference to be updated. - ContextCompat.getMainExecutor(context).execute { LibraryUpdateJob.setupTask(context) } - true - } - - fun updateSummary() { - val restrictions = libraryPreferences.libraryUpdateDeviceRestriction().get() - .sorted() - .map { - when (it) { - DEVICE_ONLY_ON_WIFI -> context.getString(R.string.connected_to_wifi) - DEVICE_NETWORK_NOT_METERED -> context.getString(R.string.network_not_metered) - DEVICE_CHARGING -> context.getString(R.string.charging) - DEVICE_BATTERY_NOT_LOW -> context.getString(R.string.battery_not_low) - else -> it - } - } - val restrictionsText = if (restrictions.isEmpty()) { - context.getString(R.string.none) - } else { - restrictions.joinToString() - } - - summary = context.getString(R.string.restrictions, restrictionsText) - } - - libraryPreferences.libraryUpdateDeviceRestriction().changes() - .onEach { updateSummary() } - .launchIn(viewScope) - } - multiSelectListPreference { - bindTo(libraryPreferences.libraryUpdateMangaRestriction()) - titleRes = R.string.pref_library_update_manga_restriction - entriesRes = arrayOf(R.string.pref_update_only_completely_read, R.string.pref_update_only_started, R.string.pref_update_only_non_completed) - entryValues = arrayOf(MANGA_HAS_UNREAD, MANGA_NON_READ, MANGA_NON_COMPLETED) - - fun updateSummary() { - val restrictions = libraryPreferences.libraryUpdateMangaRestriction().get().sorted() - .map { - when (it) { - MANGA_NON_READ -> context.getString(R.string.pref_update_only_started) - MANGA_HAS_UNREAD -> context.getString(R.string.pref_update_only_completely_read) - MANGA_NON_COMPLETED -> context.getString(R.string.pref_update_only_non_completed) - else -> it - } - } - val restrictionsText = if (restrictions.isEmpty()) { - context.getString(R.string.none) - } else { - restrictions.joinToString() - } - - summary = restrictionsText - } - - libraryPreferences.libraryUpdateMangaRestriction().changes() - .onEach { updateSummary() } - .launchIn(viewScope) - } - preference { - bindTo(libraryPreferences.libraryUpdateCategories()) - titleRes = R.string.categories - - onClick { - LibraryGlobalUpdateCategoriesDialog().showDialog(router) - } - - fun updateSummary() { - val includedCategories = libraryPreferences.libraryUpdateCategories().get() - .mapNotNull { id -> allCategories.find { it.id == id.toLong() } } - .sortedBy { it.order } - val excludedCategories = libraryPreferences.libraryUpdateCategoriesExclude().get() - .mapNotNull { id -> allCategories.find { it.id == id.toLong() } } - .sortedBy { it.order } - - val allExcluded = excludedCategories.size == allCategories.size - - val includedItemsText = when { - // Some selected, but not all - includedCategories.isNotEmpty() && includedCategories.size != allCategories.size -> includedCategories.joinToString { it.visualName(context) } - // All explicitly selected - includedCategories.size == allCategories.size -> context.getString(R.string.all) - allExcluded -> context.getString(R.string.none) - else -> context.getString(R.string.all) - } - val excludedItemsText = when { - excludedCategories.isEmpty() -> context.getString(R.string.none) - allExcluded -> context.getString(R.string.all) - else -> excludedCategories.joinToString { it.visualName(context) } - } - - summary = buildSpannedString { - append(context.getString(R.string.include, includedItemsText)) - appendLine() - append(context.getString(R.string.exclude, excludedItemsText)) - } - } - - libraryPreferences.libraryUpdateCategories().changes() - .onEach { updateSummary() } - .launchIn(viewScope) - libraryPreferences.libraryUpdateCategoriesExclude().changes() - .onEach { updateSummary() } - .launchIn(viewScope) - } - switchPreference { - bindTo(libraryPreferences.autoUpdateMetadata()) - titleRes = R.string.pref_library_update_refresh_metadata - summaryRes = R.string.pref_library_update_refresh_metadata_summary - } - if (trackManager.hasLoggedServices()) { - switchPreference { - bindTo(libraryPreferences.autoUpdateTrackers()) - titleRes = R.string.pref_library_update_refresh_trackers - summaryRes = R.string.pref_library_update_refresh_trackers_summary - } - } - } - } - - class LibraryColumnsDialog : DialogController() { - - private val preferences: LibraryPreferences = Injekt.get() - - private var portrait = preferences.portraitColumns().get() - private var landscape = preferences.landscapeColumns().get() - - override fun onCreateDialog(savedViewState: Bundle?): Dialog { - val binding = PrefLibraryColumnsBinding.inflate(LayoutInflater.from(activity!!)) - onViewCreated(binding) - return MaterialAlertDialogBuilder(activity!!) - .setTitle(R.string.pref_library_columns) - .setView(binding.root) - .setPositiveButton(android.R.string.ok) { _, _ -> - preferences.portraitColumns().set(portrait) - preferences.landscapeColumns().set(landscape) - } - .setNegativeButton(android.R.string.cancel, null) - .create() - } - - fun onViewCreated(binding: PrefLibraryColumnsBinding) { - with(binding.portraitColumns) { - displayedValues = arrayOf(context.getString(R.string.label_default)) + - IntRange(1, 10).map(Int::toString) - value = portrait - - setOnValueChangedListener { _, _, newValue -> - portrait = newValue - } - } - with(binding.landscapeColumns) { - displayedValues = arrayOf(context.getString(R.string.label_default)) + - IntRange(1, 10).map(Int::toString) - value = landscape - - setOnValueChangedListener { _, _, newValue -> - landscape = newValue - } - } - } - } - - class LibraryGlobalUpdateCategoriesDialog : DialogController() { - - private val preferences: LibraryPreferences = Injekt.get() - private val getCategories: GetCategories = Injekt.get() - - override fun onCreateDialog(savedViewState: Bundle?): Dialog { - val categories = runBlocking { getCategories.await() } - - val items = categories.map { it.visualName(activity!!) } - var selected = categories - .map { - when (it.id.toString()) { - in preferences.libraryUpdateCategories() - .get(), - -> QuadStateTextView.State.CHECKED.ordinal - in preferences.libraryUpdateCategoriesExclude() - .get(), - -> QuadStateTextView.State.INVERSED.ordinal - else -> QuadStateTextView.State.UNCHECKED.ordinal - } - } - .toIntArray() - - return MaterialAlertDialogBuilder(activity!!) - .setTitle(R.string.categories) - .setQuadStateMultiChoiceItems( - message = R.string.pref_library_update_categories_details, - items = items, - initialSelected = selected, - ) { selections -> - selected = selections - } - .setPositiveButton(android.R.string.ok) { _, _ -> - val included = selected - .mapIndexed { index, value -> if (value == QuadStateTextView.State.CHECKED.ordinal) index else null } - .filterNotNull() - .map { categories[it].id.toString() } - .toSet() - val excluded = selected - .mapIndexed { index, value -> if (value == QuadStateTextView.State.INVERSED.ordinal) index else null } - .filterNotNull() - .map { categories[it].id.toString() } - .toSet() - - preferences.libraryUpdateCategories().set(included) - preferences.libraryUpdateCategoriesExclude().set(excluded) - } - .setNegativeButton(android.R.string.cancel, null) - .create() - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt deleted file mode 100644 index 0c8c83ff15..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt +++ /dev/null @@ -1,325 +0,0 @@ -package eu.kanade.tachiyomi.ui.setting - -import android.os.Build -import androidx.preference.PreferenceScreen -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.preference.PreferenceValues -import eu.kanade.tachiyomi.data.preference.PreferenceValues.TappingInvertMode -import eu.kanade.tachiyomi.ui.reader.setting.OrientationType -import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences -import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType -import eu.kanade.tachiyomi.util.preference.bindTo -import eu.kanade.tachiyomi.util.preference.entriesRes -import eu.kanade.tachiyomi.util.preference.intListPreference -import eu.kanade.tachiyomi.util.preference.listPreference -import eu.kanade.tachiyomi.util.preference.preferenceCategory -import eu.kanade.tachiyomi.util.preference.summaryRes -import eu.kanade.tachiyomi.util.preference.switchPreference -import eu.kanade.tachiyomi.util.preference.titleRes -import eu.kanade.tachiyomi.util.system.hasDisplayCutout -import uy.kohesive.injekt.injectLazy - -class SettingsReaderController : SettingsController() { - - private val readerPreferences: ReaderPreferences by injectLazy() - - override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply { - titleRes = R.string.pref_category_reader - - intListPreference { - bindTo(readerPreferences.defaultReadingMode()) - titleRes = R.string.pref_viewer_type - entriesRes = arrayOf( - R.string.left_to_right_viewer, - R.string.right_to_left_viewer, - R.string.vertical_viewer, - R.string.webtoon_viewer, - R.string.vertical_plus_viewer, - ) - entryValues = ReadingModeType.values().drop(1) - .map { value -> "${value.flagValue}" }.toTypedArray() - summary = "%s" - } - intListPreference { - bindTo(readerPreferences.doubleTapAnimSpeed()) - titleRes = R.string.pref_double_tap_anim_speed - entries = arrayOf(context.getString(R.string.double_tap_anim_speed_0), context.getString(R.string.double_tap_anim_speed_normal), context.getString(R.string.double_tap_anim_speed_fast)) - entryValues = arrayOf("1", "500", "250") // using a value of 0 breaks the image viewer, so min is 1 - summary = "%s" - } - switchPreference { - bindTo(readerPreferences.showReadingMode()) - titleRes = R.string.pref_show_reading_mode - summaryRes = R.string.pref_show_reading_mode_summary - } - switchPreference { - bindTo(readerPreferences.showNavigationOverlayOnStart()) - titleRes = R.string.pref_show_navigation_mode - summaryRes = R.string.pref_show_navigation_mode_summary - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - switchPreference { - bindTo(readerPreferences.trueColor()) - titleRes = R.string.pref_true_color - summaryRes = R.string.pref_true_color_summary - } - } - switchPreference { - bindTo(readerPreferences.pageTransitions()) - titleRes = R.string.pref_page_transitions - } - - preferenceCategory { - titleRes = R.string.pref_category_display - - intListPreference { - bindTo(readerPreferences.defaultOrientationType()) - titleRes = R.string.pref_rotation_type - entriesRes = arrayOf( - R.string.rotation_free, - R.string.rotation_portrait, - R.string.rotation_reverse_portrait, - R.string.rotation_landscape, - R.string.rotation_force_portrait, - R.string.rotation_force_landscape, - ) - entryValues = OrientationType.values().drop(1) - .map { value -> "${value.flagValue}" }.toTypedArray() - summary = "%s" - } - intListPreference { - bindTo(readerPreferences.readerTheme()) - titleRes = R.string.pref_reader_theme - entriesRes = arrayOf(R.string.black_background, R.string.gray_background, R.string.white_background, R.string.automatic_background) - entryValues = arrayOf("1", "2", "0", "3") - summary = "%s" - } - switchPreference { - bindTo(readerPreferences.fullscreen()) - titleRes = R.string.pref_fullscreen - } - - if (activity?.hasDisplayCutout() == true) { - switchPreference { - bindTo(readerPreferences.cutoutShort()) - titleRes = R.string.pref_cutout_short - - visibleIf(readerPreferences.fullscreen()) { it } - } - } - - switchPreference { - bindTo(readerPreferences.keepScreenOn()) - titleRes = R.string.pref_keep_screen_on - } - switchPreference { - bindTo(readerPreferences.showPageNumber()) - titleRes = R.string.pref_show_page_number - } - } - - preferenceCategory { - titleRes = R.string.pref_category_reading - - switchPreference { - bindTo(readerPreferences.skipRead()) - titleRes = R.string.pref_skip_read_chapters - } - switchPreference { - bindTo(readerPreferences.skipFiltered()) - titleRes = R.string.pref_skip_filtered_chapters - } - switchPreference { - bindTo(readerPreferences.alwaysShowChapterTransition()) - titleRes = R.string.pref_always_show_chapter_transition - } - } - - preferenceCategory { - titleRes = R.string.pager_viewer - - intListPreference { - bindTo(readerPreferences.navigationModePager()) - titleRes = R.string.pref_viewer_nav - entries = context.resources.getStringArray(R.array.pager_nav).also { values -> - entryValues = values.indices.map { index -> "$index" }.toTypedArray() - } - summary = "%s" - } - listPreference { - bindTo(readerPreferences.pagerNavInverted()) - titleRes = R.string.pref_read_with_tapping_inverted - entriesRes = arrayOf( - R.string.tapping_inverted_none, - R.string.tapping_inverted_horizontal, - R.string.tapping_inverted_vertical, - R.string.tapping_inverted_both, - ) - entryValues = arrayOf( - TappingInvertMode.NONE.name, - TappingInvertMode.HORIZONTAL.name, - TappingInvertMode.VERTICAL.name, - TappingInvertMode.BOTH.name, - ) - summary = "%s" - visibleIf(readerPreferences.navigationModePager()) { it != 5 } - } - switchPreference { - bindTo(readerPreferences.navigateToPan()) - titleRes = R.string.pref_navigate_pan - visibleIf(readerPreferences.navigationModePager()) { it != 5 } - } - intListPreference { - bindTo(readerPreferences.imageScaleType()) - titleRes = R.string.pref_image_scale_type - entriesRes = arrayOf( - R.string.scale_type_fit_screen, - R.string.scale_type_stretch, - R.string.scale_type_fit_width, - R.string.scale_type_fit_height, - R.string.scale_type_original_size, - R.string.scale_type_smart_fit, - ) - entryValues = arrayOf("1", "2", "3", "4", "5", "6") - summary = "%s" - } - switchPreference { - bindTo(readerPreferences.landscapeZoom()) - titleRes = R.string.pref_landscape_zoom - visibleIf(readerPreferences.imageScaleType()) { it == 1 } - } - intListPreference { - bindTo(readerPreferences.zoomStart()) - titleRes = R.string.pref_zoom_start - entriesRes = arrayOf( - R.string.zoom_start_automatic, - R.string.zoom_start_left, - R.string.zoom_start_right, - R.string.zoom_start_center, - ) - entryValues = arrayOf("1", "2", "3", "4") - summary = "%s" - } - switchPreference { - bindTo(readerPreferences.cropBorders()) - titleRes = R.string.pref_crop_borders - } - switchPreference { - bindTo(readerPreferences.dualPageSplitPaged()) - titleRes = R.string.pref_dual_page_split - } - switchPreference { - bindTo(readerPreferences.dualPageInvertPaged()) - titleRes = R.string.pref_dual_page_invert - summaryRes = R.string.pref_dual_page_invert_summary - visibleIf(readerPreferences.dualPageSplitPaged()) { it } - } - } - - preferenceCategory { - titleRes = R.string.webtoon_viewer - - intListPreference { - bindTo(readerPreferences.navigationModeWebtoon()) - titleRes = R.string.pref_viewer_nav - entries = context.resources.getStringArray(R.array.webtoon_nav).also { values -> - entryValues = values.indices.map { index -> "$index" }.toTypedArray() - } - summary = "%s" - } - listPreference { - bindTo(readerPreferences.webtoonNavInverted()) - titleRes = R.string.pref_read_with_tapping_inverted - entriesRes = arrayOf( - R.string.tapping_inverted_none, - R.string.tapping_inverted_horizontal, - R.string.tapping_inverted_vertical, - R.string.tapping_inverted_both, - ) - entryValues = arrayOf( - TappingInvertMode.NONE.name, - TappingInvertMode.HORIZONTAL.name, - TappingInvertMode.VERTICAL.name, - TappingInvertMode.BOTH.name, - ) - summary = "%s" - visibleIf(readerPreferences.navigationModeWebtoon()) { it != 5 } - } - intListPreference { - bindTo(readerPreferences.webtoonSidePadding()) - titleRes = R.string.pref_webtoon_side_padding - entriesRes = arrayOf( - R.string.webtoon_side_padding_0, - R.string.webtoon_side_padding_5, - R.string.webtoon_side_padding_10, - R.string.webtoon_side_padding_15, - R.string.webtoon_side_padding_20, - R.string.webtoon_side_padding_25, - ) - entryValues = arrayOf("0", "5", "10", "15", "20", "25") - summary = "%s" - } - listPreference { - bindTo(readerPreferences.readerHideThreshold()) - titleRes = R.string.pref_hide_threshold - entriesRes = arrayOf( - R.string.pref_highest, - R.string.pref_high, - R.string.pref_low, - R.string.pref_lowest, - ) - entryValues = PreferenceValues.ReaderHideThreshold.values() - .map { it.name } - .toTypedArray() - summary = "%s" - } - switchPreference { - bindTo(readerPreferences.cropBordersWebtoon()) - titleRes = R.string.pref_crop_borders - } - switchPreference { - bindTo(readerPreferences.dualPageSplitWebtoon()) - titleRes = R.string.pref_dual_page_split - } - switchPreference { - bindTo(readerPreferences.dualPageInvertWebtoon()) - titleRes = R.string.pref_dual_page_invert - summaryRes = R.string.pref_dual_page_invert_summary - visibleIf(readerPreferences.dualPageSplitWebtoon()) { it } - } - switchPreference { - bindTo(readerPreferences.longStripSplitWebtoon()) - titleRes = R.string.pref_long_strip_split - summaryRes = R.string.split_tall_images_summary - } - } - - preferenceCategory { - titleRes = R.string.pref_reader_navigation - - switchPreference { - bindTo(readerPreferences.readWithVolumeKeys()) - titleRes = R.string.pref_read_with_volume_keys - } - switchPreference { - bindTo(readerPreferences.readWithVolumeKeysInverted()) - titleRes = R.string.pref_read_with_volume_keys_inverted - visibleIf(readerPreferences.readWithVolumeKeys()) { it } - } - } - - preferenceCategory { - titleRes = R.string.pref_reader_actions - - switchPreference { - bindTo(readerPreferences.readWithLongTap()) - titleRes = R.string.pref_read_with_long_tap - } - switchPreference { - bindTo(readerPreferences.folderPerManga()) - titleRes = R.string.pref_create_folder_per_manga - summaryRes = R.string.pref_create_folder_per_manga_summary - } - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSecurityController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSecurityController.kt deleted file mode 100644 index 4d8aa0095a..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSecurityController.kt +++ /dev/null @@ -1,102 +0,0 @@ -package eu.kanade.tachiyomi.ui.setting - -import androidx.biometric.BiometricPrompt -import androidx.fragment.app.FragmentActivity -import androidx.preference.Preference -import androidx.preference.PreferenceScreen -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.core.security.SecurityPreferences -import eu.kanade.tachiyomi.util.preference.bindTo -import eu.kanade.tachiyomi.util.preference.entriesRes -import eu.kanade.tachiyomi.util.preference.infoPreference -import eu.kanade.tachiyomi.util.preference.intListPreference -import eu.kanade.tachiyomi.util.preference.listPreference -import eu.kanade.tachiyomi.util.preference.requireAuthentication -import eu.kanade.tachiyomi.util.preference.switchPreference -import eu.kanade.tachiyomi.util.preference.titleRes -import eu.kanade.tachiyomi.util.system.AuthenticatorUtil -import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.isAuthenticationSupported -import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.startAuthentication -import eu.kanade.tachiyomi.util.system.toast -import uy.kohesive.injekt.injectLazy - -class SettingsSecurityController : SettingsController() { - - private val securityPreferences: SecurityPreferences by injectLazy() - - override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply { - titleRes = R.string.pref_category_security - - if (context.isAuthenticationSupported()) { - switchPreference { - bindTo(securityPreferences.useAuthenticator()) - titleRes = R.string.lock_with_biometrics - - requireAuthentication( - activity as? FragmentActivity, - context.getString(R.string.lock_with_biometrics), - context.getString(R.string.confirm_lock_change), - ) - } - - intListPreference { - bindTo(securityPreferences.lockAppAfter()) - titleRes = R.string.lock_when_idle - val values = arrayOf("0", "1", "2", "5", "10", "-1") - entries = values.mapNotNull { - when (it) { - "-1" -> context.getString(R.string.lock_never) - "0" -> context.getString(R.string.lock_always) - else -> resources?.getQuantityString(R.plurals.lock_after_mins, it.toInt(), it) - } - }.toTypedArray() - entryValues = values - summary = "%s" - onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> - if (value == newValue) return@OnPreferenceChangeListener false - - (activity as? FragmentActivity)?.startAuthentication( - activity!!.getString(R.string.lock_when_idle), - activity!!.getString(R.string.confirm_lock_change), - callback = object : AuthenticatorUtil.AuthenticationCallback() { - override fun onAuthenticationSucceeded( - activity: FragmentActivity?, - result: BiometricPrompt.AuthenticationResult, - ) { - super.onAuthenticationSucceeded(activity, result) - value = newValue as String - } - - override fun onAuthenticationError( - activity: FragmentActivity?, - errorCode: Int, - errString: CharSequence, - ) { - super.onAuthenticationError(activity, errorCode, errString) - activity?.toast(errString.toString()) - } - }, - ) - false - } - - visibleIf(securityPreferences.useAuthenticator()) { it } - } - } - - switchPreference { - bindTo(securityPreferences.hideNotificationContent()) - titleRes = R.string.hide_notification_content - } - - listPreference { - bindTo(securityPreferences.secureScreen()) - titleRes = R.string.secure_screen - summary = "%s" - entriesRes = SecurityPreferences.SecureScreenMode.values().map { it.titleResId }.toTypedArray() - entryValues = SecurityPreferences.SecureScreenMode.values().map { it.name }.toTypedArray() - } - - infoPreference(R.string.secure_screen_summary) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsTrackingController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsTrackingController.kt deleted file mode 100644 index d6af368c32..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsTrackingController.kt +++ /dev/null @@ -1,163 +0,0 @@ -package eu.kanade.tachiyomi.ui.setting - -import android.app.Activity -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem -import android.widget.Toast -import androidx.preference.PreferenceGroup -import androidx.preference.PreferenceScreen -import eu.kanade.domain.track.service.TrackPreferences -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.track.NoLoginTrackService -import eu.kanade.tachiyomi.data.track.TrackManager -import eu.kanade.tachiyomi.data.track.TrackService -import eu.kanade.tachiyomi.data.track.anilist.AnilistApi -import eu.kanade.tachiyomi.data.track.bangumi.BangumiApi -import eu.kanade.tachiyomi.data.track.myanimelist.MyAnimeListApi -import eu.kanade.tachiyomi.data.track.shikimori.ShikimoriApi -import eu.kanade.tachiyomi.source.SourceManager -import eu.kanade.tachiyomi.ui.setting.track.TrackLoginDialog -import eu.kanade.tachiyomi.ui.setting.track.TrackLogoutDialog -import eu.kanade.tachiyomi.util.preference.add -import eu.kanade.tachiyomi.util.preference.bindTo -import eu.kanade.tachiyomi.util.preference.iconRes -import eu.kanade.tachiyomi.util.preference.infoPreference -import eu.kanade.tachiyomi.util.preference.onClick -import eu.kanade.tachiyomi.util.preference.preferenceCategory -import eu.kanade.tachiyomi.util.preference.switchPreference -import eu.kanade.tachiyomi.util.preference.titleRes -import eu.kanade.tachiyomi.util.system.openInBrowser -import eu.kanade.tachiyomi.util.system.toast -import eu.kanade.tachiyomi.widget.preference.TrackerPreference -import uy.kohesive.injekt.injectLazy - -class SettingsTrackingController : - SettingsController(), - TrackLoginDialog.Listener, - TrackLogoutDialog.Listener { - - private val trackManager: TrackManager by injectLazy() - private val trackPreferences: TrackPreferences by injectLazy() - private val sourceManager: SourceManager by injectLazy() - - override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply { - titleRes = R.string.pref_category_tracking - - switchPreference { - bindTo(trackPreferences.autoUpdateTrack()) - titleRes = R.string.pref_auto_update_manga_sync - } - - preferenceCategory { - titleRes = R.string.services - - trackPreference(trackManager.myAnimeList) { - activity?.openInBrowser(MyAnimeListApi.authUrl(), forceDefaultBrowser = true) - } - trackPreference(trackManager.aniList) { - activity?.openInBrowser(AnilistApi.authUrl(), forceDefaultBrowser = true) - } - trackPreference(trackManager.kitsu) { - val dialog = TrackLoginDialog(trackManager.kitsu, R.string.email) - dialog.targetController = this@SettingsTrackingController - dialog.showDialog(router) - } - trackPreference(trackManager.mangaUpdates) { - val dialog = TrackLoginDialog(trackManager.mangaUpdates, R.string.username) - dialog.targetController = this@SettingsTrackingController - dialog.showDialog(router) - } - trackPreference(trackManager.shikimori) { - activity?.openInBrowser(ShikimoriApi.authUrl(), forceDefaultBrowser = true) - } - trackPreference(trackManager.bangumi) { - activity?.openInBrowser(BangumiApi.authUrl(), forceDefaultBrowser = true) - } - infoPreference(R.string.tracking_info) - } - - preferenceCategory { - titleRes = R.string.enhanced_services - - trackPreference(trackManager.komga) { - val acceptedSources = trackManager.komga.getAcceptedSources() - val hasValidSourceInstalled = sourceManager.getCatalogueSources() - .any { it::class.qualifiedName in acceptedSources } - - if (hasValidSourceInstalled) { - trackManager.komga.loginNoop() - updatePreference(trackManager.komga.id) - } else { - context.toast(R.string.tracker_komga_warning, Toast.LENGTH_LONG) - } - } - - infoPreference(R.string.enhanced_tracking_info) - } - } - - private inline fun PreferenceGroup.trackPreference( - service: TrackService, - crossinline login: () -> Unit, - ): TrackerPreference { - return add( - TrackerPreference(context).apply { - key = TrackPreferences.trackUsername(service.id) - titleRes = service.nameRes() - iconRes = service.getLogo() - iconColor = service.getLogoColor() - onClick { - if (service.isLogged) { - if (service is NoLoginTrackService) { - service.logout() - updatePreference(service.id) - } else { - val dialog = TrackLogoutDialog(service) - dialog.targetController = this@SettingsTrackingController - dialog.showDialog(router) - } - } else { - login() - } - } - }, - ) - } - - override fun onActivityResumed(activity: Activity) { - super.onActivityResumed(activity) - - // Manually refresh OAuth trackers' holders - updatePreference(trackManager.myAnimeList.id) - updatePreference(trackManager.aniList.id) - updatePreference(trackManager.shikimori.id) - updatePreference(trackManager.bangumi.id) - } - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - inflater.inflate(R.menu.settings_tracking, menu) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - R.id.action_tracking_help -> activity?.openInBrowser(HELP_URL) - } - return super.onOptionsItemSelected(item) - } - - private fun updatePreference(id: Long) { - val pref = findPreference(TrackPreferences.trackUsername(id)) as? TrackerPreference - pref?.notifyChanged() - } - - override fun trackLoginDialogClosed(service: TrackService) { - updatePreference(service.id) - } - - override fun trackLogoutDialogClosed(service: TrackService) { - updatePreference(service.id) - } -} - -private const val HELP_URL = "https://tachiyomi.org/help/guides/tracking/" diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabaseController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabaseController.kt deleted file mode 100644 index 7aff3fdecd..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabaseController.kt +++ /dev/null @@ -1,20 +0,0 @@ -package eu.kanade.tachiyomi.ui.setting.database - -import androidx.compose.runtime.Composable -import eu.kanade.presentation.more.settings.database.ClearDatabaseScreen -import eu.kanade.tachiyomi.ui.base.controller.FullComposeController - -class ClearDatabaseController : FullComposeController() { - - override fun createPresenter(): ClearDatabasePresenter { - return ClearDatabasePresenter() - } - - @Composable - override fun ComposeContent() { - ClearDatabaseScreen( - presenter = presenter, - navigateUp = { router.popCurrentController() }, - ) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabasePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabasePresenter.kt deleted file mode 100644 index 27c9bda306..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabasePresenter.kt +++ /dev/null @@ -1,62 +0,0 @@ -package eu.kanade.tachiyomi.ui.setting.database - -import android.os.Bundle -import eu.kanade.domain.source.interactor.GetSourcesWithNonLibraryManga -import eu.kanade.domain.source.model.Source -import eu.kanade.presentation.more.settings.database.ClearDatabaseState -import eu.kanade.presentation.more.settings.database.ClearDatabaseStateImpl -import eu.kanade.tachiyomi.Database -import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter -import eu.kanade.tachiyomi.util.lang.launchIO -import kotlinx.coroutines.flow.collectLatest -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get - -class ClearDatabasePresenter( - private val state: ClearDatabaseStateImpl = ClearDatabaseState() as ClearDatabaseStateImpl, - private val database: Database = Injekt.get(), - private val getSourcesWithNonLibraryManga: GetSourcesWithNonLibraryManga = Injekt.get(), -) : BasePresenter(), ClearDatabaseState by state { - - override fun onCreate(savedState: Bundle?) { - super.onCreate(savedState) - - presenterScope.launchIO { - getSourcesWithNonLibraryManga.subscribe() - .collectLatest { list -> - state.items = list.sortedBy { it.name } - } - } - } - - fun removeMangaBySourceId(sourceIds: List) { - database.mangasQueries.deleteMangasNotInLibraryBySourceIds(sourceIds) - database.historyQueries.removeResettedHistory() - } - - fun toggleSelection(source: Source) { - val mutableList = state.selection.toMutableList() - if (mutableList.contains(source.id)) { - mutableList.remove(source.id) - } else { - mutableList.add(source.id) - } - state.selection = mutableList - } - - fun clearSelection() { - state.selection = emptyList() - } - - fun selectAll() { - state.selection = state.items.map { it.id } - } - - fun invertSelection() { - state.selection = state.items.map { it.id }.filterNot { it in state.selection } - } - - sealed class Dialog { - data class Delete(val sourceIds: List) : Dialog() - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/search/SettingsSearchController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/search/SettingsSearchController.kt deleted file mode 100644 index dae22adb2a..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/search/SettingsSearchController.kt +++ /dev/null @@ -1,20 +0,0 @@ -package eu.kanade.tachiyomi.ui.setting.search - -import androidx.compose.runtime.Composable -import eu.kanade.presentation.more.settings.SettingsSearchScreen -import eu.kanade.tachiyomi.ui.base.controller.FullComposeController -import eu.kanade.tachiyomi.ui.base.controller.pushController - -class SettingsSearchController : FullComposeController() { - - override fun createPresenter() = SettingsSearchPresenter() - - @Composable - override fun ComposeContent() { - SettingsSearchScreen( - navigateUp = router::popCurrentController, - presenter = presenter, - onClickResult = { router.pushController(it) }, - ) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/search/SettingsSearchHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/search/SettingsSearchHelper.kt deleted file mode 100644 index 0f95d7efec..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/search/SettingsSearchHelper.kt +++ /dev/null @@ -1,138 +0,0 @@ -package eu.kanade.tachiyomi.ui.setting.search - -import android.annotation.SuppressLint -import android.content.Context -import android.content.res.Resources -import androidx.preference.Preference -import androidx.preference.PreferenceCategory -import androidx.preference.PreferenceGroup -import androidx.preference.PreferenceManager -import androidx.preference.forEach -import androidx.preference.get -import eu.kanade.tachiyomi.ui.setting.SettingsAdvancedController -import eu.kanade.tachiyomi.ui.setting.SettingsAppearanceController -import eu.kanade.tachiyomi.ui.setting.SettingsBackupController -import eu.kanade.tachiyomi.ui.setting.SettingsBrowseController -import eu.kanade.tachiyomi.ui.setting.SettingsController -import eu.kanade.tachiyomi.ui.setting.SettingsDownloadController -import eu.kanade.tachiyomi.ui.setting.SettingsGeneralController -import eu.kanade.tachiyomi.ui.setting.SettingsLibraryController -import eu.kanade.tachiyomi.ui.setting.SettingsReaderController -import eu.kanade.tachiyomi.ui.setting.SettingsSecurityController -import eu.kanade.tachiyomi.ui.setting.SettingsTrackingController -import eu.kanade.tachiyomi.util.lang.launchNow -import eu.kanade.tachiyomi.util.system.isLTR -import kotlin.reflect.KClass -import kotlin.reflect.full.createInstance - -object SettingsSearchHelper { - private var prefSearchResultList: MutableList = mutableListOf() - - /** - * All subclasses of `SettingsController` should be listed here, in order to have their preferences searchable. - */ - private val settingControllersList: List> = listOf( - SettingsAdvancedController::class, - SettingsAppearanceController::class, - SettingsBackupController::class, - SettingsBrowseController::class, - SettingsDownloadController::class, - SettingsGeneralController::class, - SettingsLibraryController::class, - SettingsReaderController::class, - SettingsSecurityController::class, - SettingsTrackingController::class, - ) - - /** - * Must be called to populate `prefSearchResultList` - */ - @SuppressLint("RestrictedApi") - fun initPreferenceSearchResults(context: Context) { - val preferenceManager = PreferenceManager(context) - prefSearchResultList.clear() - - launchNow { - settingControllersList.forEach { kClass -> - val ctrl = kClass.createInstance() - val settingsPrefScreen = ctrl.setupPreferenceScreen(preferenceManager.createPreferenceScreen(context)) - val prefCount = settingsPrefScreen.preferenceCount - for (i in 0 until prefCount) { - val rootPref = settingsPrefScreen[i] - if (rootPref.title == null) continue // no title, not a preference. (note: only info notes appear to not have titles) - getSettingSearchResult(ctrl, rootPref, "${settingsPrefScreen.title}") - } - } - } - } - - fun getFilteredResults(query: String): List { - return prefSearchResultList.filter { - val inTitle = it.title.contains(query, true) - val inSummary = it.summary.contains(query, true) - val inBreadcrumb = it.breadcrumb.contains(query, true) - - return@filter inTitle || inSummary || inBreadcrumb - } - } - - /** - * Extracts the data needed from a `Preference` to create a `SettingsSearchResult`, and then adds it to `prefSearchResultList` - * Future enhancement: make bold the text matched by the search query. - */ - private fun getSettingSearchResult( - ctrl: SettingsController, - pref: Preference, - breadcrumbs: String = "", - ) { - when { - pref is PreferenceGroup -> { - val breadcrumbsStr = addLocalizedBreadcrumb(breadcrumbs, "${pref.title}") - pref.forEach { - getSettingSearchResult(ctrl, it, breadcrumbsStr) // recursion - } - } - pref is PreferenceCategory -> { - val breadcrumbsStr = addLocalizedBreadcrumb(breadcrumbs, "${pref.title}") - pref.forEach { - getSettingSearchResult(ctrl, it, breadcrumbsStr) // recursion - } - } - (pref.title != null && pref.isVisible) -> { - // Is an actual preference - val title = pref.title.toString() - // ListPreferences occasionally run into ArrayIndexOutOfBoundsException issues - val summary = try { pref.summary?.toString() ?: "" } catch (e: Throwable) { "" } - val breadcrumbsStr = addLocalizedBreadcrumb(breadcrumbs, "${pref.title}") - - prefSearchResultList.add( - SettingsSearchResult( - key = pref.key, - title = title, - summary = summary, - breadcrumb = breadcrumbsStr, - searchController = ctrl, - ), - ) - } - } - } - - private fun addLocalizedBreadcrumb(path: String, node: String): String { - return if (Resources.getSystem().isLTR) { - // This locale reads left to right. - "$path > $node" - } else { - // This locale reads right to left. - "$node < $path" - } - } - - data class SettingsSearchResult( - val key: String?, - val title: String, - val summary: String, - val breadcrumb: String, - val searchController: SettingsController, - ) -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/search/SettingsSearchPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/search/SettingsSearchPresenter.kt deleted file mode 100644 index 8b41612703..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/search/SettingsSearchPresenter.kt +++ /dev/null @@ -1,33 +0,0 @@ -package eu.kanade.tachiyomi.ui.setting.search - -import android.os.Bundle -import eu.kanade.domain.base.BasePreferences -import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get - -class SettingsSearchPresenter( - private val preferences: BasePreferences = Injekt.get(), -) : BasePresenter() { - - private val _state: MutableStateFlow> = - MutableStateFlow(emptyList()) - val state: StateFlow> = _state.asStateFlow() - - override fun onCreate(savedState: Bundle?) { - super.onCreate(savedState) - - SettingsSearchHelper.initPreferenceSearchResults(preferences.context) - } - - fun searchSettings(query: String?) { - _state.value = if (!query.isNullOrBlank()) { - SettingsSearchHelper.getFilteredResults(query) - } else { - emptyList() - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/TrackLoginDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/TrackLoginDialog.kt deleted file mode 100644 index 39f891c562..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/TrackLoginDialog.kt +++ /dev/null @@ -1,66 +0,0 @@ -package eu.kanade.tachiyomi.ui.setting.track - -import android.os.Bundle -import android.view.View -import androidx.annotation.StringRes -import androidx.core.os.bundleOf -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.track.TrackManager -import eu.kanade.tachiyomi.data.track.TrackService -import eu.kanade.tachiyomi.util.lang.launchIO -import eu.kanade.tachiyomi.util.lang.withUIContext -import eu.kanade.tachiyomi.util.system.toast -import eu.kanade.tachiyomi.widget.preference.LoginDialogPreference -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get - -class TrackLoginDialog( - @StringRes usernameLabelRes: Int? = null, - bundle: Bundle? = null, -) : LoginDialogPreference(usernameLabelRes, bundle) { - - private val service = Injekt.get().getService(args.getLong("serviceId"))!! - - constructor(service: TrackService, @StringRes usernameLabelRes: Int?) : - this(usernameLabelRes, bundleOf("serviceId" to service.id)) - - @StringRes - override fun getTitleName(): Int = service.nameRes() - - override fun setCredentialsOnView(view: View) { - binding?.username?.setText(service.getUsername()) - binding?.password?.setText(service.getPassword()) - } - - override fun checkLogin() { - if (binding!!.username.text.isNullOrEmpty() || binding!!.password.text.isNullOrEmpty()) { - return - } - - binding!!.login.progress = 1 - val user = binding!!.username.text.toString() - val pass = binding!!.password.text.toString() - - launchIO { - try { - service.login(user, pass) - dialog?.dismiss() - withUIContext { view?.context?.toast(R.string.login_success) } - } catch (e: Throwable) { - service.logout() - binding?.login?.progress = -1 - binding?.login?.setText(R.string.unknown_error) - withUIContext { e.message?.let { view?.context?.toast(it) } } - } - } - } - - override fun onDialogClosed() { - super.onDialogClosed() - (targetController as? Listener)?.trackLoginDialogClosed(service) - } - - interface Listener { - fun trackLoginDialogClosed(service: TrackService) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/TrackLogoutDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/TrackLogoutDialog.kt deleted file mode 100644 index 78462c0545..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/TrackLogoutDialog.kt +++ /dev/null @@ -1,37 +0,0 @@ -package eu.kanade.tachiyomi.ui.setting.track - -import android.app.Dialog -import android.os.Bundle -import androidx.core.os.bundleOf -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.track.TrackManager -import eu.kanade.tachiyomi.data.track.TrackService -import eu.kanade.tachiyomi.ui.base.controller.DialogController -import eu.kanade.tachiyomi.util.system.toast -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get - -class TrackLogoutDialog(bundle: Bundle? = null) : DialogController(bundle) { - - private val service = Injekt.get().getService(args.getLong("serviceId"))!! - - constructor(service: TrackService) : this(bundleOf("serviceId" to service.id)) - - override fun onCreateDialog(savedViewState: Bundle?): Dialog { - val serviceName = activity!!.getString(service.nameRes()) - return MaterialAlertDialogBuilder(activity!!) - .setTitle(activity!!.getString(R.string.logout_title, serviceName)) - .setPositiveButton(R.string.logout) { _, _ -> - service.logout() - (targetController as? Listener)?.trackLogoutDialogClosed(service) - activity?.toast(R.string.logout_success) - } - .setNegativeButton(android.R.string.cancel, null) - .create() - } - - interface Listener { - fun trackLogoutDialogClosed(service: TrackService) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/preference/PreferenceDSL.kt b/app/src/main/java/eu/kanade/tachiyomi/util/preference/PreferenceDSL.kt deleted file mode 100644 index d8f9b1f2b5..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/util/preference/PreferenceDSL.kt +++ /dev/null @@ -1,198 +0,0 @@ -@file:Suppress("NOTHING_TO_INLINE") - -package eu.kanade.tachiyomi.util.preference - -import androidx.annotation.StringRes -import androidx.appcompat.content.res.AppCompatResources -import androidx.biometric.BiometricPrompt -import androidx.fragment.app.FragmentActivity -import androidx.preference.CheckBoxPreference -import androidx.preference.EditTextPreference -import androidx.preference.ListPreference -import androidx.preference.MultiSelectListPreference -import androidx.preference.Preference -import androidx.preference.PreferenceCategory -import androidx.preference.PreferenceGroup -import androidx.preference.PreferenceManager -import androidx.preference.PreferenceScreen -import androidx.preference.SwitchPreferenceCompat -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.util.system.AuthenticatorUtil -import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.isAuthenticationSupported -import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.startAuthentication -import eu.kanade.tachiyomi.util.system.getResourceColor -import eu.kanade.tachiyomi.util.system.toast -import eu.kanade.tachiyomi.widget.preference.AdaptiveTitlePreferenceCategory -import eu.kanade.tachiyomi.widget.preference.IntListPreference - -@DslMarker -@Target(AnnotationTarget.TYPE) -annotation class DSL - -inline fun PreferenceManager.newScreen(block: (@DSL PreferenceScreen).() -> Unit): PreferenceScreen { - return createPreferenceScreen(context).also { it.block() } -} - -inline fun PreferenceGroup.preference(block: (@DSL Preference).() -> Unit): Preference { - return initThenAdd(Preference(context), block) -} - -inline fun PreferenceGroup.infoPreference(@StringRes infoRes: Int): Preference { - return add( - Preference(context).apply { - iconRes = R.drawable.ic_info_24dp - iconTint = context.getResourceColor(android.R.attr.textColorHint) - summaryRes = infoRes - isSelectable = false - }, - ) -} - -inline fun PreferenceGroup.switchPreference(block: (@DSL SwitchPreferenceCompat).() -> Unit): SwitchPreferenceCompat { - return initThenAdd(SwitchPreferenceCompat(context), block) -} - -inline fun PreferenceGroup.checkBoxPreference(block: (@DSL CheckBoxPreference).() -> Unit): CheckBoxPreference { - return initThenAdd(CheckBoxPreference(context), block) -} - -inline fun PreferenceGroup.editTextPreference(block: (@DSL EditTextPreference).() -> Unit): EditTextPreference { - return initThenAdd(EditTextPreference(context), block) -} - -inline fun PreferenceGroup.listPreference(block: (@DSL ListPreference).() -> Unit): ListPreference { - return initThenAdd(ListPreference(context), block) -} - -inline fun PreferenceGroup.intListPreference(block: (@DSL IntListPreference).() -> Unit): IntListPreference { - return initThenAdd(IntListPreference(context), block) -} - -inline fun PreferenceGroup.multiSelectListPreference(block: (@DSL MultiSelectListPreference).() -> Unit): MultiSelectListPreference { - return initThenAdd(MultiSelectListPreference(context), block) -} - -inline fun PreferenceScreen.preferenceCategory(block: (@DSL PreferenceCategory).() -> Unit): PreferenceCategory { - return addThenInit(AdaptiveTitlePreferenceCategory(context), block) -} - -inline fun PreferenceScreen.preferenceScreen(block: (@DSL PreferenceScreen).() -> Unit): PreferenceScreen { - return addThenInit(preferenceManager.createPreferenceScreen(context), block) -} - -inline fun

PreferenceGroup.add(p: P): P { - return p.apply { - this.isIconSpaceReserved = false - this.isSingleLineTitle = false - addPreference(this) - } -} - -inline fun

PreferenceGroup.initThenAdd(p: P, block: P.() -> Unit): P { - return p.apply { - block() - this.isIconSpaceReserved = false - this.isSingleLineTitle = false - addPreference(this) - } -} - -inline fun

PreferenceGroup.addThenInit(p: P, block: P.() -> Unit): P { - return p.apply { - this.isIconSpaceReserved = false - this.isSingleLineTitle = false - addPreference(this) - block() - } -} - -inline fun Preference.bindTo(preference: eu.kanade.tachiyomi.core.preference.Preference) { - key = preference.key() - defaultValue = preference.defaultValue() -} - -inline fun ListPreference.bindTo(preference: eu.kanade.tachiyomi.core.preference.Preference) { - key = preference.key() - defaultValue = preference.defaultValue().toString() -} - -inline fun Preference.onClick(crossinline block: () -> Unit) { - setOnPreferenceClickListener { block(); true } -} - -inline fun Preference.onChange(crossinline block: (Any?) -> Boolean) { - setOnPreferenceChangeListener { _, newValue -> block(newValue) } -} - -inline fun SwitchPreferenceCompat.requireAuthentication(activity: FragmentActivity?, title: String, subtitle: String?) { - onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> - if (context.isAuthenticationSupported()) { - activity?.startAuthentication( - title, - subtitle, - callback = object : AuthenticatorUtil.AuthenticationCallback() { - override fun onAuthenticationSucceeded( - activity: FragmentActivity?, - result: BiometricPrompt.AuthenticationResult, - ) { - super.onAuthenticationSucceeded(activity, result) - isChecked = newValue as Boolean - } - - override fun onAuthenticationError( - activity: FragmentActivity?, - errorCode: Int, - errString: CharSequence, - ) { - super.onAuthenticationError(activity, errorCode, errString) - activity?.toast(errString.toString()) - } - }, - ) - } - - false - } -} - -var Preference.defaultValue: Any? - get() = null // set only - set(value) { - setDefaultValue(value) - } - -var Preference.titleRes: Int - get() = 0 // set only - set(value) { - setTitle(value) - } - -var Preference.iconRes: Int - get() = 0 // set only - set(value) { - icon = AppCompatResources.getDrawable(context, value) - } - -var Preference.summaryRes: Int - get() = 0 // set only - set(value) { - setSummary(value) - } - -var Preference.iconTint: Int - get() = 0 // set only - set(value) { - icon?.setTint(value) - } - -var ListPreference.entriesRes: Array - get() = emptyArray() // set only - set(value) { - entries = value.map { context.getString(it) }.toTypedArray() - } - -var MultiSelectListPreference.entriesRes: Array - get() = emptyArray() // set only - set(value) { - entries = value.map { context.getString(it) }.toTypedArray() - } diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/materialdialogs/MaterialAlertDialogBuilderExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/materialdialogs/MaterialAlertDialogBuilderExtensions.kt deleted file mode 100644 index 7c0ed2c496..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/materialdialogs/MaterialAlertDialogBuilderExtensions.kt +++ /dev/null @@ -1,67 +0,0 @@ -package eu.kanade.tachiyomi.widget.materialdialogs - -import android.view.LayoutInflater -import androidx.annotation.StringRes -import androidx.appcompat.app.AlertDialog -import androidx.core.view.isVisible -import androidx.recyclerview.widget.LinearLayoutManager -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import eu.kanade.tachiyomi.databinding.DialogStubQuadstatemultichoiceBinding -import kotlinx.coroutines.suspendCancellableCoroutine -import kotlin.coroutines.resume - -/** - * Sets a list of items with checkboxes that supports 4 states. - * - * @see eu.kanade.tachiyomi.widget.materialdialogs.QuadStateTextView - */ -fun MaterialAlertDialogBuilder.setQuadStateMultiChoiceItems( - @StringRes message: Int? = null, - isActionList: Boolean = true, - items: List, - initialSelected: IntArray, - disabledIndices: IntArray? = null, - selection: QuadStateMultiChoiceListener, -): MaterialAlertDialogBuilder { - val binding = DialogStubQuadstatemultichoiceBinding.inflate(LayoutInflater.from(context)) - binding.list.layoutManager = LinearLayoutManager(context) - binding.list.adapter = QuadStateMultiChoiceDialogAdapter( - items = items, - disabledItems = disabledIndices, - initialSelected = initialSelected, - isActionList = isActionList, - listener = selection, - ) - val updateScrollIndicators = { - binding.scrollIndicatorUp.isVisible = binding.list.canScrollVertically(-1) - binding.scrollIndicatorDown.isVisible = binding.list.canScrollVertically(1) - } - binding.list.setOnScrollChangeListener { _, _, _, _, _ -> - updateScrollIndicators() - } - binding.list.post { - updateScrollIndicators() - } - - if (message != null) { - binding.message.setText(message) - binding.message.isVisible = true - } - return setView(binding.root) -} - -suspend fun MaterialAlertDialogBuilder.await( - @StringRes positiveLabelId: Int, - @StringRes negativeLabelId: Int, - @StringRes neutralLabelId: Int? = null, -) = suspendCancellableCoroutine { cont -> - setPositiveButton(positiveLabelId) { _, _ -> cont.resume(AlertDialog.BUTTON_POSITIVE) } - setNegativeButton(negativeLabelId) { _, _ -> cont.resume(AlertDialog.BUTTON_NEGATIVE) } - if (neutralLabelId != null) { - setNeutralButton(neutralLabelId) { _, _ -> cont.resume(AlertDialog.BUTTON_NEUTRAL) } - } - setOnDismissListener { cont.cancel() } - - val dialog = show() - cont.invokeOnCancellation { dialog.dismiss() } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/materialdialogs/QuadStateMultiChoiceDialogAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/materialdialogs/QuadStateMultiChoiceDialogAdapter.kt deleted file mode 100644 index e9152f2482..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/materialdialogs/QuadStateMultiChoiceDialogAdapter.kt +++ /dev/null @@ -1,128 +0,0 @@ -package eu.kanade.tachiyomi.widget.materialdialogs - -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.recyclerview.widget.RecyclerView -import eu.kanade.tachiyomi.databinding.DialogQuadstatemultichoiceItemBinding - -private object CheckPayload -private object InverseCheckPayload -private object UncheckPayload -private object IndeterminatePayload - -typealias QuadStateMultiChoiceListener = (indices: IntArray) -> Unit - -// isAction state: Uncheck-> Check-> Invert else Uncheck-> Indeterminate (only if initial so)-> Check -// isAction for list of action to operate on like filter include, exclude -internal class QuadStateMultiChoiceDialogAdapter( - internal var items: List, - disabledItems: IntArray?, - private var initialSelected: IntArray, - internal var listener: QuadStateMultiChoiceListener, - val isActionList: Boolean = true, -) : RecyclerView.Adapter() { - - private val states = QuadStateTextView.State.values() - - private var currentSelection: IntArray = initialSelected - set(value) { - val previousSelection = field - field = value - previousSelection.forEachIndexed { index, previous -> - val current = value[index] - when { - current == QuadStateTextView.State.CHECKED.ordinal && previous != QuadStateTextView.State.CHECKED.ordinal -> { - // This value was selected - notifyItemChanged(index, CheckPayload) - } - current == QuadStateTextView.State.INVERSED.ordinal && previous != QuadStateTextView.State.INVERSED.ordinal -> { - // This value was inverse selected - notifyItemChanged(index, InverseCheckPayload) - } - current == QuadStateTextView.State.UNCHECKED.ordinal && previous != QuadStateTextView.State.UNCHECKED.ordinal -> { - // This value was unselected - notifyItemChanged(index, UncheckPayload) - } - current == QuadStateTextView.State.INDETERMINATE.ordinal && previous != QuadStateTextView.State.INDETERMINATE.ordinal -> { - // This value was set back to Indeterminate - notifyItemChanged(index, IndeterminatePayload) - } - } - } - } - private var disabledIndices: IntArray = disabledItems ?: IntArray(0) - internal fun itemActionClicked(index: Int) { - val newSelection = this.currentSelection.toMutableList() - newSelection[index] = when (currentSelection[index]) { - QuadStateTextView.State.CHECKED.ordinal -> QuadStateTextView.State.INVERSED.ordinal - QuadStateTextView.State.INVERSED.ordinal -> QuadStateTextView.State.UNCHECKED.ordinal - // INDETERMINATE or UNCHECKED - else -> QuadStateTextView.State.CHECKED.ordinal - } - this.currentSelection = newSelection.toIntArray() - listener(currentSelection) - } - - internal fun itemDisplayClicked(index: Int) { - val newSelection = this.currentSelection.toMutableList() - newSelection[index] = when (currentSelection[index]) { - QuadStateTextView.State.UNCHECKED.ordinal -> QuadStateTextView.State.CHECKED.ordinal - QuadStateTextView.State.CHECKED.ordinal -> when (initialSelected[index]) { - QuadStateTextView.State.INDETERMINATE.ordinal -> QuadStateTextView.State.INDETERMINATE.ordinal - else -> QuadStateTextView.State.UNCHECKED.ordinal - } - // INDETERMINATE or UNCHECKED - else -> QuadStateTextView.State.UNCHECKED.ordinal - } - this.currentSelection = newSelection.toIntArray() - listener(currentSelection) - } - - override fun onCreateViewHolder( - parent: ViewGroup, - viewType: Int, - ): QuadStateMultiChoiceViewHolder { - return QuadStateMultiChoiceViewHolder( - itemBinding = DialogQuadstatemultichoiceItemBinding - .inflate(LayoutInflater.from(parent.context), parent, false), - adapter = this, - ) - } - - override fun getItemCount() = items.size - - override fun onBindViewHolder( - holder: QuadStateMultiChoiceViewHolder, - position: Int, - ) { - holder.isEnabled = !disabledIndices.contains(position) - holder.controlView.state = states[currentSelection[position]] - holder.controlView.text = items[position] - } - - override fun onBindViewHolder( - holder: QuadStateMultiChoiceViewHolder, - position: Int, - payloads: MutableList, - ) { - when (payloads.firstOrNull()) { - CheckPayload -> { - holder.controlView.state = QuadStateTextView.State.CHECKED - return - } - InverseCheckPayload -> { - holder.controlView.state = QuadStateTextView.State.INVERSED - return - } - UncheckPayload -> { - holder.controlView.state = QuadStateTextView.State.UNCHECKED - return - } - IndeterminatePayload -> { - holder.controlView.state = QuadStateTextView.State.INDETERMINATE - return - } - } - super.onBindViewHolder(holder, position, payloads) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/materialdialogs/QuadStateMultiChoiceViewHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/materialdialogs/QuadStateMultiChoiceViewHolder.kt deleted file mode 100644 index c75c216045..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/materialdialogs/QuadStateMultiChoiceViewHolder.kt +++ /dev/null @@ -1,28 +0,0 @@ -package eu.kanade.tachiyomi.widget.materialdialogs - -import android.view.View -import androidx.recyclerview.widget.RecyclerView -import eu.kanade.tachiyomi.databinding.DialogQuadstatemultichoiceItemBinding - -internal class QuadStateMultiChoiceViewHolder( - itemBinding: DialogQuadstatemultichoiceItemBinding, - private val adapter: QuadStateMultiChoiceDialogAdapter, -) : RecyclerView.ViewHolder(itemBinding.root), View.OnClickListener { - init { - itemView.setOnClickListener(this) - } - - val controlView = itemBinding.quadStateControl - - var isEnabled: Boolean - get() = itemView.isEnabled - set(value) { - itemView.isEnabled = value - controlView.isEnabled = value - } - - override fun onClick(view: View) = when (adapter.isActionList) { - true -> adapter.itemActionClicked(bindingAdapterPosition) - false -> adapter.itemDisplayClicked(bindingAdapterPosition) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/materialdialogs/QuadStateTextView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/materialdialogs/QuadStateTextView.kt deleted file mode 100644 index e8e9fe77f6..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/materialdialogs/QuadStateTextView.kt +++ /dev/null @@ -1,46 +0,0 @@ -package eu.kanade.tachiyomi.widget.materialdialogs - -import android.content.Context -import android.content.res.ColorStateList -import android.util.AttributeSet -import androidx.appcompat.widget.AppCompatTextView -import androidx.core.widget.TextViewCompat -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.util.system.getThemeColor - -class QuadStateTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - AppCompatTextView(context, attrs) { - - var state: State = State.UNCHECKED - set(value) { - field = value - updateDrawable() - } - - private fun updateDrawable() { - val drawableStartId = when (state) { - State.UNCHECKED -> R.drawable.ic_check_box_outline_blank_24dp - State.INDETERMINATE -> R.drawable.ic_indeterminate_check_box_24dp - State.CHECKED -> R.drawable.ic_check_box_24dp - State.INVERSED -> R.drawable.ic_check_box_x_24dp - } - setCompoundDrawablesRelativeWithIntrinsicBounds(drawableStartId, 0, 0, 0) - - val tint = if (state == State.UNCHECKED) { - context.getThemeColor(R.attr.colorControlNormal) - } else { - context.getThemeColor(R.attr.colorPrimary) - } - if (tint != 0) { - TextViewCompat.setCompoundDrawableTintList(this, ColorStateList.valueOf(tint)) - } - } - - enum class State { - UNCHECKED, - INDETERMINATE, - CHECKED, - INVERSED, - ; - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/AdaptiveTitlePreferenceCategory.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/AdaptiveTitlePreferenceCategory.kt deleted file mode 100644 index d0448549d7..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/AdaptiveTitlePreferenceCategory.kt +++ /dev/null @@ -1,22 +0,0 @@ -package eu.kanade.tachiyomi.widget.preference - -import android.content.Context -import androidx.core.view.updateLayoutParams -import androidx.preference.PreferenceCategory -import androidx.preference.PreferenceViewHolder -import androidx.recyclerview.widget.RecyclerView - -/** - * PreferenceCategory that hides the title placeholder layout if the title is unset - */ -class AdaptiveTitlePreferenceCategory(context: Context) : PreferenceCategory(context) { - override fun onBindViewHolder(holder: PreferenceViewHolder) { - super.onBindViewHolder(holder) - if (title.isNullOrBlank()) { - holder.itemView.updateLayoutParams { - height = 0 - topMargin = 0 - } - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/IntListPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/IntListPreference.kt deleted file mode 100644 index 63b52eb2a9..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/IntListPreference.kt +++ /dev/null @@ -1,26 +0,0 @@ -package eu.kanade.tachiyomi.widget.preference - -import android.content.Context -import android.util.AttributeSet -import androidx.preference.ListPreference - -class IntListPreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - ListPreference(context, attrs) { - - override fun persistString(value: String?): Boolean { - return value != null && persistInt(value.toInt()) - } - - override fun getPersistedString(defaultReturnValue: String?): String? { - // When the underlying preference is using a PreferenceDataStore, there's no way (for now) - // to check if a value is in the store, so we use a most likely unused value as workaround - val defaultIntValue = Int.MIN_VALUE + 1 - - val value = getPersistedInt(defaultIntValue) - return if (value != defaultIntValue) { - value.toString() - } else { - defaultReturnValue - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginDialogPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginDialogPreference.kt deleted file mode 100644 index 4374c6da2d..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginDialogPreference.kt +++ /dev/null @@ -1,67 +0,0 @@ -package eu.kanade.tachiyomi.widget.preference - -import android.app.Dialog -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import androidx.annotation.StringRes -import com.bluelinelabs.conductor.ControllerChangeHandler -import com.bluelinelabs.conductor.ControllerChangeType -import com.dd.processbutton.iml.ActionProcessButton -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import eu.kanade.domain.base.BasePreferences -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.databinding.PrefAccountLoginBinding -import eu.kanade.tachiyomi.ui.base.controller.DialogController -import uy.kohesive.injekt.injectLazy - -abstract class LoginDialogPreference( - @StringRes private val usernameLabelRes: Int? = null, - bundle: Bundle? = null, -) : DialogController(bundle) { - - var binding: PrefAccountLoginBinding? = null - private set - - val preferences: BasePreferences by injectLazy() - - override fun onCreateDialog(savedViewState: Bundle?): Dialog { - binding = PrefAccountLoginBinding.inflate(LayoutInflater.from(activity!!)) - onViewCreated(binding!!.root) - val titleName = activity!!.getString(getTitleName()) - return MaterialAlertDialogBuilder(activity!!) - .setTitle(activity!!.getString(R.string.login_title, titleName)) - .setView(binding!!.root) - .setNegativeButton(android.R.string.cancel, null) - .create() - } - - fun onViewCreated(view: View) { - if (usernameLabelRes != null) { - binding!!.usernameLabel.hint = view.context.getString(usernameLabelRes) - } - - binding!!.login.setMode(ActionProcessButton.Mode.ENDLESS) - binding!!.login.setOnClickListener { checkLogin() } - - setCredentialsOnView(view) - } - - override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) { - super.onChangeStarted(handler, type) - if (!type.isEnter) { - onDialogClosed() - } - } - - open fun onDialogClosed() { - binding = null - } - - @StringRes - protected abstract fun getTitleName(): Int - - protected abstract fun checkLogin() - - protected abstract fun setCredentialsOnView(view: View) -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ThemesPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ThemesPreference.kt deleted file mode 100644 index 10bcb688db..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ThemesPreference.kt +++ /dev/null @@ -1,76 +0,0 @@ -package eu.kanade.tachiyomi.widget.preference - -import android.content.Context -import android.util.AttributeSet -import androidx.preference.ListPreference -import androidx.preference.PreferenceViewHolder -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import eu.kanade.domain.ui.model.AppTheme -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.util.system.dpToPx - -class ThemesPreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - ListPreference(context, attrs), - ThemesPreferenceAdapter.OnItemClickListener { - - private var recycler: RecyclerView? = null - private val adapter = ThemesPreferenceAdapter(this) - - var lastScrollPosition: Int? = null - - var entries: List = emptyList() - set(value) { - field = value - adapter.setItems(value) - } - - init { - layoutResource = R.layout.pref_themes_list - } - - override fun onBindViewHolder(holder: PreferenceViewHolder) { - super.onBindViewHolder(holder) - - recycler = holder.findViewById(R.id.themes_list) as RecyclerView - recycler?.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) - recycler?.adapter = adapter - - // Retain scroll position on activity recreate after changing theme - recycler?.addOnScrollListener( - object : RecyclerView.OnScrollListener() { - override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { - super.onScrolled(recyclerView, dx, dy) - lastScrollPosition = recyclerView.computeHorizontalScrollOffset() - } - }, - ) - lastScrollPosition?.let { scrollToOffset(it) } - } - - override fun onItemClick(position: Int) { - if (position !in 0..entries.size) { - return - } - - callChangeListener(value) - value = entries[position].name - } - - override fun onClick() { - // no-op; not actually a DialogPreference - } - - private fun scrollToOffset(lX: Int) { - recycler?.let { - (it.layoutManager as LinearLayoutManager).apply { - scrollToPositionWithOffset( - // 114dp is the width of the pref_theme_item layout - lX / 114.dpToPx, - -lX % 114.dpToPx, - ) - } - lastScrollPosition = it.computeHorizontalScrollOffset() - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ThemesPreferenceAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ThemesPreferenceAdapter.kt deleted file mode 100644 index f4169257f4..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ThemesPreferenceAdapter.kt +++ /dev/null @@ -1,75 +0,0 @@ -package eu.kanade.tachiyomi.widget.preference - -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.appcompat.view.ContextThemeWrapper -import androidx.recyclerview.widget.RecyclerView -import eu.kanade.domain.ui.UiPreferences -import eu.kanade.domain.ui.model.AppTheme -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.databinding.PrefThemeItemBinding -import eu.kanade.tachiyomi.ui.base.delegate.ThemingDelegate -import eu.kanade.tachiyomi.util.system.getResourceColor -import uy.kohesive.injekt.injectLazy - -class ThemesPreferenceAdapter(private val clickListener: OnItemClickListener) : - RecyclerView.Adapter() { - - private val preferences: UiPreferences by injectLazy() - - private var themes = emptyList() - - private lateinit var binding: PrefThemeItemBinding - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ThemeViewHolder { - val themeResIds = ThemingDelegate.getThemeResIds(themes[viewType], preferences.themeDarkAmoled().get()) - val themedContext = themeResIds.fold(parent.context) { - context, themeResId -> - ContextThemeWrapper(context, themeResId) - } - - binding = PrefThemeItemBinding.inflate(LayoutInflater.from(themedContext), parent, false) - return ThemeViewHolder(binding.root) - } - - override fun getItemViewType(position: Int): Int = position - - override fun getItemCount(): Int = themes.size - - override fun onBindViewHolder(holder: ThemesPreferenceAdapter.ThemeViewHolder, position: Int) { - holder.bind(themes[position]) - } - - fun setItems(themes: List) { - this.themes = themes - notifyDataSetChanged() - } - - inner class ThemeViewHolder(private val view: View) : RecyclerView.ViewHolder(view) { - - private val selectedColor = view.context.getResourceColor(R.attr.colorAccent) - private val unselectedColor = view.context.getResourceColor(android.R.attr.divider) - - fun bind(appTheme: AppTheme) { - binding.name.text = view.context.getString(appTheme.titleResId!!) - - // For rounded corners - binding.badges.clipToOutline = true - - val isSelected = preferences.appTheme().get() == appTheme - binding.themeCard.isChecked = isSelected - binding.themeCard.strokeColor = if (isSelected) selectedColor else unselectedColor - - listOf(binding.root, binding.themeCard).forEach { - it.setOnClickListener { - clickListener.onItemClick(bindingAdapterPosition) - } - } - } - } - - interface OnItemClickListener { - fun onItemClick(position: Int) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/TrackerPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/TrackerPreference.kt deleted file mode 100644 index 2077744b99..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/TrackerPreference.kt +++ /dev/null @@ -1,41 +0,0 @@ -package eu.kanade.tachiyomi.widget.preference - -import android.content.Context -import android.graphics.Color -import android.util.AttributeSet -import android.widget.ImageView -import androidx.annotation.ColorInt -import androidx.core.view.isVisible -import androidx.preference.Preference -import androidx.preference.PreferenceViewHolder -import com.google.android.material.card.MaterialCardView -import eu.kanade.tachiyomi.R - -class TrackerPreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - Preference(context, attrs) { - - init { - layoutResource = R.layout.pref_tracker_item - } - - override fun onBindViewHolder(holder: PreferenceViewHolder) { - super.onBindViewHolder(holder) - - val logoContainer = holder.findViewById(R.id.logo_container) as MaterialCardView - val checkedIcon = holder.findViewById(R.id.checked_icon) as ImageView - - logoContainer.setCardBackgroundColor(iconColor) - checkedIcon.isVisible = !getPersistedString("").isNullOrEmpty() - } - - @ColorInt - var iconColor: Int = Color.TRANSPARENT - set(value) { - field = value - notifyChanged() - } - - public override fun notifyChanged() { - super.notifyChanged() - } -} diff --git a/app/src/main/res/drawable/ic_cloud_off_24dp.xml b/app/src/main/res/drawable/ic_cloud_off_24dp.xml deleted file mode 100644 index 003aaedc2e..0000000000 --- a/app/src/main/res/drawable/ic_cloud_off_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_done_green_24dp.xml b/app/src/main/res/drawable/ic_done_green_24dp.xml deleted file mode 100644 index d101f76257..0000000000 --- a/app/src/main/res/drawable/ic_done_green_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_flip_to_back_24dp.xml b/app/src/main/res/drawable/ic_flip_to_back_24dp.xml deleted file mode 100644 index 3269eb9ad4..0000000000 --- a/app/src/main/res/drawable/ic_flip_to_back_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_indeterminate_check_box_24dp.xml b/app/src/main/res/drawable/ic_indeterminate_check_box_24dp.xml deleted file mode 100644 index de8cfec85f..0000000000 --- a/app/src/main/res/drawable/ic_indeterminate_check_box_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_public_24dp.xml b/app/src/main/res/drawable/ic_public_24dp.xml deleted file mode 100644 index 7d1ca63826..0000000000 --- a/app/src/main/res/drawable/ic_public_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_select_all_24dp.xml b/app/src/main/res/drawable/ic_select_all_24dp.xml deleted file mode 100644 index 8ecfbb9089..0000000000 --- a/app/src/main/res/drawable/ic_select_all_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_sync_24dp.xml b/app/src/main/res/drawable/ic_sync_24dp.xml deleted file mode 100644 index 18db5e0493..0000000000 --- a/app/src/main/res/drawable/ic_sync_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_view_module_24dp.xml b/app/src/main/res/drawable/ic_view_module_24dp.xml deleted file mode 100644 index 7eb3216046..0000000000 --- a/app/src/main/res/drawable/ic_view_module_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/manga_backdrop_gradient.xml b/app/src/main/res/drawable/manga_backdrop_gradient.xml deleted file mode 100644 index 02692a50b0..0000000000 --- a/app/src/main/res/drawable/manga_backdrop_gradient.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/drawable/manga_info_gradient.xml b/app/src/main/res/drawable/manga_info_gradient.xml deleted file mode 100644 index 35e6c06eae..0000000000 --- a/app/src/main/res/drawable/manga_info_gradient.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/drawable/manga_info_more_gradient.xml b/app/src/main/res/drawable/manga_info_more_gradient.xml deleted file mode 100644 index 503ea5359c..0000000000 --- a/app/src/main/res/drawable/manga_info_more_gradient.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/layout/dialog_quadstatemultichoice_item.xml b/app/src/main/res/layout/dialog_quadstatemultichoice_item.xml deleted file mode 100644 index 0c7edc0798..0000000000 --- a/app/src/main/res/layout/dialog_quadstatemultichoice_item.xml +++ /dev/null @@ -1,18 +0,0 @@ - - diff --git a/app/src/main/res/layout/dialog_stub_quadstatemultichoice.xml b/app/src/main/res/layout/dialog_stub_quadstatemultichoice.xml deleted file mode 100644 index 15e74f7344..0000000000 --- a/app/src/main/res/layout/dialog_stub_quadstatemultichoice.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/pref_account_login.xml b/app/src/main/res/layout/pref_account_login.xml deleted file mode 100644 index f31b799ce9..0000000000 --- a/app/src/main/res/layout/pref_account_login.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/pref_library_columns.xml b/app/src/main/res/layout/pref_library_columns.xml deleted file mode 100644 index 059e33ebfb..0000000000 --- a/app/src/main/res/layout/pref_library_columns.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/pref_theme_item.xml b/app/src/main/res/layout/pref_theme_item.xml deleted file mode 100644 index 39e265d778..0000000000 --- a/app/src/main/res/layout/pref_theme_item.xml +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/pref_themes_list.xml b/app/src/main/res/layout/pref_themes_list.xml deleted file mode 100644 index 7b6dcec050..0000000000 --- a/app/src/main/res/layout/pref_themes_list.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/layout/pref_tracker_item.xml b/app/src/main/res/layout/pref_tracker_item.xml deleted file mode 100644 index 75d57e10b6..0000000000 --- a/app/src/main/res/layout/pref_tracker_item.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - diff --git a/app/src/main/res/menu/generic_selection.xml b/app/src/main/res/menu/generic_selection.xml deleted file mode 100644 index 10d32b675d..0000000000 --- a/app/src/main/res/menu/generic_selection.xml +++ /dev/null @@ -1,19 +0,0 @@ - -

- - - - - - diff --git a/app/src/main/res/menu/settings_backup.xml b/app/src/main/res/menu/settings_backup.xml deleted file mode 100644 index 28ff24c5f5..0000000000 --- a/app/src/main/res/menu/settings_backup.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/app/src/main/res/menu/settings_tracking.xml b/app/src/main/res/menu/settings_tracking.xml deleted file mode 100644 index 00d6074211..0000000000 --- a/app/src/main/res/menu/settings_tracking.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c97f3a1e6f..cbcc339f64 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -56,7 +56,6 @@ natural-comparator = "com.github.gpanther:java-nat-sort:natural-comparator-1.1" markwon = "io.noties.markwon:core:4.6.2" material = "com.google.android.material:material:1.7.0-rc01" -androidprocessbutton = "com.github.dmytrodanylyk.android-process-button:library:1.0.4" flexible-adapter-core = "com.github.arkon.FlexibleAdapter:flexible-adapter:c8013533" flexible-adapter-ui = "com.github.arkon.FlexibleAdapter:flexible-adapter-ui:c8013533" photoview = "com.github.chrisbanes:PhotoView:2.3.0"