From 26d3be95e3313f2a2250d4241a165c20fd4838ca Mon Sep 17 00:00:00 2001 From: Cuong-Tran <16017808+cuong-tran@users.noreply.github.com> Date: Thu, 16 Apr 2026 14:01:49 +0700 Subject: [PATCH] feat(UI): Mask WebDAV password while typing (#1564) * Refactor * feat(UI): Mask WebDAV password while typing * fix: allow space as password * use coroutines for asynchronous setting --- .../settings/screen/SettingsAdvancedScreen.kt | 4 +- .../settings/screen/SettingsBrowseScreen.kt | 2 +- .../settings/screen/SettingsDataScreen.kt | 44 ++++++++++++------- .../settings/screen/SettingsSecurityScreen.kt | 11 +++-- .../kanade/tachiyomi/data/sync/SyncManager.kt | 4 +- .../data/sync/service/WebDavSyncService.kt | 2 +- 6 files changed, 42 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt index 8878b3ba2..8cc4ef491 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt @@ -738,7 +738,7 @@ object SettingsAdvancedScreen : SearchableSettings { subtitle = stringResource(SYMR.strings.data_saver_image_quality_summary), enabled = dataSaver != DataSaver.NONE, ), - kotlin.run { + run { val dataSaverImageFormatJpeg by sourcePreferences.dataSaverImageFormatJpeg() .collectAsState() Preference.PreferenceItem.SwitchPreference( @@ -808,7 +808,7 @@ object SettingsAdvancedScreen : SearchableSettings { title = stringResource(SYMR.strings.log_level), subtitle = stringResource(SYMR.strings.log_level_summary), ), - kotlin.run { + run { var enableEncryptDatabase by rememberSaveable { mutableStateOf(false) } if (enableEncryptDatabase) { diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt index 6d6b64450..e96eb1e72 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt @@ -85,7 +85,7 @@ object SettingsBrowseScreen : SearchableSettings { enabled = sourcePreferences.relatedMangas().get(), ), // KMK <-- - kotlin.run { + run { val count by sourcePreferences.sourcesTabCategories().collectAsState() Preference.PreferenceItem.TextPreference( title = stringResource(MR.strings.action_edit_categories), diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt index aba5089e4..150c2b004 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt @@ -48,6 +48,7 @@ import com.journeyapps.barcodescanner.ScanContract import com.journeyapps.barcodescanner.ScanOptions import eu.kanade.domain.sync.SyncPreferences import eu.kanade.presentation.more.settings.Preference +import eu.kanade.presentation.more.settings.screen.SettingsSecurityScreen.PasswordDialog import eu.kanade.presentation.more.settings.screen.data.CreateBackupScreen import eu.kanade.presentation.more.settings.screen.data.RestoreBackupScreen import eu.kanade.presentation.more.settings.screen.data.StorageInfo @@ -562,7 +563,7 @@ object SettingsDataScreen : SearchableSettings { SyncManager.SyncService.SYNCYOMI.value to stringResource(SYMR.strings.syncyomi), SyncManager.SyncService.GOOGLE_DRIVE.value to stringResource(SYMR.strings.google_drive), // KMK --> - SyncManager.SyncService.WebDAV.value to stringResource(KMR.strings.web_dav), + SyncManager.SyncService.WEB_DAV.value to stringResource(KMR.strings.web_dav), // KMK <-- ), title = stringResource(SYMR.strings.pref_sync_service), @@ -606,7 +607,7 @@ object SettingsDataScreen : SearchableSettings { SyncManager.SyncService.SYNCYOMI -> getSelfHostPreferences(syncPreferences) SyncManager.SyncService.GOOGLE_DRIVE -> getGoogleDrivePreferences() // KMK --> - SyncManager.SyncService.WebDAV -> getWebDavPreferences(syncPreferences) + SyncManager.SyncService.WEB_DAV -> getWebDavPreferences(syncPreferences) // KMK <-- } @@ -759,7 +760,9 @@ object SettingsDataScreen : SearchableSettings { title = stringResource(SYMR.strings.pref_sync_api_key), subtitle = stringResource(SYMR.strings.pref_sync_api_key_summ), onConfirm = { - syncPreferences.clientAPIKey().set(it) + scope.launch { + syncPreferences.clientAPIKey().set(it) + } true }, icon = null, @@ -808,17 +811,28 @@ object SettingsDataScreen : SearchableSettings { true }, ), - Preference.PreferenceItem.EditTextPreference( - preference = syncPreferences.webDavPassword(), - title = stringResource(KMR.strings.pref_webdav_password), - subtitle = stringResource(KMR.strings.pref_webdav_password_summ), - onValueChanged = { newValue -> - scope.launch { - syncPreferences.webDavPassword().set(newValue) - } - true - }, - ), + run { + var dialogOpen by remember { mutableStateOf(false) } + if (dialogOpen) { + PasswordDialog( + onDismissRequest = { dialogOpen = false }, + onReturnPassword = { password -> + dialogOpen = false + scope.launch { + syncPreferences.webDavPassword().set(password.replace("\n", "")) + } + }, + title = KMR.strings.pref_webdav_password, + ) + } + Preference.PreferenceItem.TextPreference( + title = stringResource(KMR.strings.pref_webdav_password), + subtitle = stringResource(KMR.strings.pref_webdav_password_summ), + onClick = { + dialogOpen = true + }, + ) + }, Preference.PreferenceItem.EditTextPreference( preference = syncPreferences.webDavFolder(), title = stringResource(KMR.strings.pref_webdav_folder), @@ -832,7 +846,7 @@ object SettingsDataScreen : SearchableSettings { ), ) } - // MK <-- + // KMK <-- @Composable private fun getSyncNowPref(): Preference.PreferenceGroup { diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSecurityScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSecurityScreen.kt index 9df011f14..5b4ee07be 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSecurityScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSecurityScreen.kt @@ -155,7 +155,7 @@ object SettingsSecurityScreen : SearchableSettings { enabled = passwordProtectDownloads, ), - kotlin.run { + run { var dialogOpen by remember { mutableStateOf(false) } if (dialogOpen) { PasswordDialog( @@ -183,7 +183,7 @@ object SettingsSecurityScreen : SearchableSettings { securityPreferences.cbzPassword().set("") }, ), - kotlin.run { + run { val navigator = LocalNavigator.currentOrThrow val count by securityPreferences.authenticatorTimeRanges().collectAsState() Preference.PreferenceItem.TextPreference( @@ -199,7 +199,7 @@ object SettingsSecurityScreen : SearchableSettings { }, ) }, - kotlin.run { + run { val selection by securityPreferences.authenticatorDays().collectAsState() var dialogOpen by remember { mutableStateOf(false) } if (dialogOpen) { @@ -332,13 +332,16 @@ object SettingsSecurityScreen : SearchableSettings { fun PasswordDialog( onDismissRequest: () -> Unit, onReturnPassword: (String) -> Unit, + // KMK --> + title: StringResource = SYMR.strings.cbz_archive_password, + // KMK <-- ) { var password by rememberSaveable { mutableStateOf("") } var passwordVisibility by remember { mutableStateOf(false) } AlertDialog( onDismissRequest = onDismissRequest, - title = { Text(text = stringResource(SYMR.strings.cbz_archive_password)) }, + title = { Text(text = stringResource(title)) }, text = { TextField( value = password, diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/sync/SyncManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/sync/SyncManager.kt index a4dfb1815..ec289d2e7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/sync/SyncManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/sync/SyncManager.kt @@ -57,7 +57,7 @@ class SyncManager( SYNCYOMI(1), GOOGLE_DRIVE(2), // KMK --> - WebDAV(3), + WEB_DAV(3), // KMK <-- ; @@ -142,7 +142,7 @@ class SyncManager( } // KMK --> - SyncService.WebDAV -> { + SyncService.WEB_DAV -> { WebDavSyncService(context, json, syncPreferences, notifier) } // KMK <-- diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/sync/service/WebDavSyncService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/sync/service/WebDavSyncService.kt index cac0a49d9..40b3366a9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/sync/service/WebDavSyncService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/sync/service/WebDavSyncService.kt @@ -40,7 +40,7 @@ class WebDavSyncService( private val url: String = syncPreferences.webDavUrl().get().trim() private val folder: String = syncPreferences.webDavFolder().get().trim('/') private val username: String = syncPreferences.webDavUsername().get().trim() - private val password: String = syncPreferences.webDavPassword().get().trim() + private val password: String = syncPreferences.webDavPassword().get() private val credentials: String = Credentials.basic(username, password) private fun buildWebDavFileUrl(fileName: String = "backup.proto"): String {