feat: split "sync on add" into separate metadata and chapter fetch preferences (#1563)

* feat: split "sync on add" into separate metadata and chapter fetch preferences

* refactor: remove redundant SnackbarHostState and error snackbars when auto sync entries

* clean other languages strings
This commit is contained in:
Cuong-Tran 2026-03-17 13:09:48 +07:00 committed by GitHub
parent edaf975e21
commit 6f06974524
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 69 additions and 46 deletions

View file

@ -200,7 +200,7 @@ class SyncChaptersWithSource(
bookmark = chapter.chapterNumber in deletedBookmarkedChapterNumbers, bookmark = chapter.chapterNumber in deletedBookmarkedChapterNumbers,
) )
// Try to to use the fetch date of the original entry to not pollute 'Updates' tab // Try to use the fetch date of the original entry to not pollute 'Updates' tab
deletedChapterNumberDateFetchMap[chapter.chapterNumber]?.let { deletedChapterNumberDateFetchMap[chapter.chapterNumber]?.let {
chapter = chapter.copy(dateFetch = it) chapter = chapter.copy(dateFetch = it)
} }

View file

@ -293,9 +293,14 @@ object SettingsLibraryScreen : SearchableSettings {
title = stringResource(KMR.strings.pref_show_empty_categories_search), title = stringResource(KMR.strings.pref_show_empty_categories_search),
), ),
Preference.PreferenceItem.SwitchPreference( Preference.PreferenceItem.SwitchPreference(
preference = libraryPreferences.syncOnAdd(), preference = libraryPreferences.fetchMetadataOnAdd(),
title = stringResource(KMR.strings.pref_sync_manga_on_add), title = stringResource(KMR.strings.pref_fetch_manga_metadata_on_add),
subtitle = stringResource(KMR.strings.pref_sync_manga_on_add_description), subtitle = stringResource(KMR.strings.pref_fetch_manga_metadata_on_add_description),
),
Preference.PreferenceItem.SwitchPreference(
preference = libraryPreferences.fetchChaptersOnAdd(),
title = stringResource(KMR.strings.pref_fetch_manga_chapters_on_add),
subtitle = stringResource(KMR.strings.pref_fetch_manga_chapters_on_add_description),
), ),
// KMK <-- // KMK <--
), ),

View file

@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.ui.browse package eu.kanade.tachiyomi.ui.browse
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import androidx.compose.ui.hapticfeedback.HapticFeedback import androidx.compose.ui.hapticfeedback.HapticFeedback
import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.hapticfeedback.HapticFeedbackType
@ -60,7 +59,6 @@ class BulkFavoriteScreenModel(
private val setMangaDefaultChapterFlags: SetMangaDefaultChapterFlags = Injekt.get(), private val setMangaDefaultChapterFlags: SetMangaDefaultChapterFlags = Injekt.get(),
private val addTracks: AddTracks = Injekt.get(), private val addTracks: AddTracks = Injekt.get(),
private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(), private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(),
val snackbarHostState: SnackbarHostState = SnackbarHostState(),
) : StateScreenModel<BulkFavoriteScreenModel.State>(initialState) { ) : StateScreenModel<BulkFavoriteScreenModel.State>(initialState) {
fun backHandler() { fun backHandler() {
@ -83,7 +81,7 @@ class BulkFavoriteScreenModel(
} }
/** /**
* @param toSelectedState set to true to only Select, set to false to only Unselect * @param toSelectedState set to `true` to only Select, set to `false` to only Unselect
*/ */
fun toggleSelection(manga: Manga, toSelectedState: Boolean? = null) { fun toggleSelection(manga: Manga, toSelectedState: Boolean? = null) {
mutableState.update { state -> mutableState.update { state ->
@ -131,7 +129,7 @@ class BulkFavoriteScreenModel(
if (entryWithDuplicates != null) { if (entryWithDuplicates != null) {
val (index, manga, duplicates) = entryWithDuplicates val (index, manga, duplicates) = entryWithDuplicates
if (state.value.selection.size == 1) { if (state.value.selection.size == 1) {
// If only one manga is selected, show the multiple duplicates dialog. // If only one manga is selected, show the multiple-duplicates dialog.
setDialog(Dialog.AddDuplicateManga(manga, duplicates)) setDialog(Dialog.AddDuplicateManga(manga, duplicates))
} else { } else {
setDialog(Dialog.BulkAllowDuplicate(manga, duplicates, index)) setDialog(Dialog.BulkAllowDuplicate(manga, duplicates, index))
@ -256,17 +254,22 @@ class BulkFavoriteScreenModel(
setMangaDefaultChapterFlags.await(manga) setMangaDefaultChapterFlags.await(manga)
addTracks.bindEnhancedTrackers(manga, source) addTracks.bindEnhancedTrackers(manga, source)
updateManga.awaitUpdateFavorite(manga.id, true) updateManga.awaitUpdateFavorite(manga.id, true)
if (libraryPreferences.syncOnAdd().get()) { val fetchMetadataOnAdd = libraryPreferences.fetchMetadataOnAdd().get()
val fetchChaptersOnAdd = libraryPreferences.fetchChaptersOnAdd().get()
if (fetchMetadataOnAdd || fetchChaptersOnAdd) {
val sManga = manga.toSManga() val sManga = manga.toSManga()
val remoteManga = source.getMangaDetails(sManga) if (fetchMetadataOnAdd) {
val chapters = source.getChapterList(sManga) val remoteMetadata = source.getMangaDetails(sManga)
// Use `manga` instead of `new` so its title got updated with source's `getMangaDetails` // Use `manga` instead of `new` so its title got updated with source's `getMangaDetails`
updateManga.awaitUpdateFromSource(manga, remoteManga, false, coverCache) updateManga.awaitUpdateFromSource(manga, remoteMetadata, false, coverCache)
}
if (fetchChaptersOnAdd) {
val chapters = source.getChapterList(sManga)
syncChaptersWithSource.await(chapters, manga, source, false) syncChaptersWithSource.await(chapters, manga, source, false)
} }
}
} catch (e: Exception) { } catch (e: Exception) {
logcat(LogPriority.ERROR, e) logcat(LogPriority.ERROR, e)
snackbarHostState.showSnackbar(message = "Failed to sync manga: ${e.message}")
} }
} }
} }
@ -351,18 +354,23 @@ class BulkFavoriteScreenModel(
} }
updateManga.await(new.toMangaUpdate()) updateManga.await(new.toMangaUpdate())
if (new.favorite && libraryPreferences.syncOnAdd().get()) { val fetchMetadataOnAdd = libraryPreferences.fetchMetadataOnAdd().get()
val fetchChaptersOnAdd = libraryPreferences.fetchChaptersOnAdd().get()
if (new.favorite && (fetchMetadataOnAdd || fetchChaptersOnAdd)) {
withIOContext { withIOContext {
try { try {
val sManga = manga.toSManga() val sManga = manga.toSManga()
val remoteManga = source.getMangaDetails(sManga) if (fetchMetadataOnAdd) {
val chapters = source.getChapterList(sManga) val remoteMetadata = source.getMangaDetails(sManga)
// Use `manga` instead of `new` so its title got updated with source's `getMangaDetails` // Use `manga` instead of `new` so its title got updated with source's `getMangaDetails`
updateManga.awaitUpdateFromSource(manga, remoteManga, false, coverCache) updateManga.awaitUpdateFromSource(manga, remoteMetadata, false, coverCache)
}
if (fetchChaptersOnAdd) {
val chapters = source.getChapterList(sManga)
syncChaptersWithSource.await(chapters, manga, source, false) syncChaptersWithSource.await(chapters, manga, source, false)
}
} catch (e: Exception) { } catch (e: Exception) {
logcat(LogPriority.ERROR, e) logcat(LogPriority.ERROR, e)
snackbarHostState.showSnackbar(message = "Failed to sync manga: ${e.message}")
} }
} }
} }

View file

@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.ui.browse.source.browse
import android.content.res.Configuration import android.content.res.Configuration
import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@ -120,7 +119,6 @@ open class BrowseSourceScreenModel(
private val toggleIncognito: ToggleIncognito = Injekt.get(), private val toggleIncognito: ToggleIncognito = Injekt.get(),
private val extensionManager: ExtensionManager = Injekt.get(), private val extensionManager: ExtensionManager = Injekt.get(),
private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(), private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(),
val snackbarHostState: SnackbarHostState = SnackbarHostState(),
// KMK <-- // KMK <--
// SY --> // SY -->
@ -424,20 +422,23 @@ open class BrowseSourceScreenModel(
updateManga.await(new.toMangaUpdate()) updateManga.await(new.toMangaUpdate())
// KMK --> // KMK -->
if (new.favorite && libraryPreferences.syncOnAdd().get()) { val fetchMetadataOnAdd = libraryPreferences.fetchMetadataOnAdd().get()
val fetchChaptersOnAdd = libraryPreferences.fetchChaptersOnAdd().get()
if (new.favorite && (fetchMetadataOnAdd || fetchChaptersOnAdd)) {
withIOContext { withIOContext {
try { try {
val sManga = manga.toSManga() val sManga = manga.toSManga()
val remoteManga = source.getMangaDetails(sManga) if (fetchMetadataOnAdd) {
val chapters = source.getChapterList(sManga) val remoteMetadata = source.getMangaDetails(sManga)
// Use `manga` instead of `new` so its title got updated with source's `getMangaDetails` // Use `manga` instead of `new` so its title got updated with source's `getMangaDetails`
updateManga.awaitUpdateFromSource(manga, remoteManga, false, coverCache) updateManga.awaitUpdateFromSource(manga, remoteMetadata, false, coverCache)
}
if (fetchChaptersOnAdd) {
val chapters = source.getChapterList(sManga)
syncChaptersWithSource.await(chapters, manga, source, false) syncChaptersWithSource.await(chapters, manga, source, false)
}
} catch (e: Exception) { } catch (e: Exception) {
logcat(LogPriority.ERROR, e) logcat(LogPriority.ERROR, e)
screenModelScope.launch {
snackbarHostState.showSnackbar(message = "Failed to sync manga: ${e.message}")
}
} }
} }
} }

View file

@ -74,7 +74,8 @@ class LibraryPreferences(
fun autoUpdateMetadata() = preferenceStore.getBoolean("auto_update_metadata", false) fun autoUpdateMetadata() = preferenceStore.getBoolean("auto_update_metadata", false)
// KMK --> // KMK -->
fun syncOnAdd() = preferenceStore.getBoolean("sync_on_add", false) fun fetchMetadataOnAdd() = preferenceStore.getBoolean("fetch_metadata_on_add", false)
fun fetchChaptersOnAdd() = preferenceStore.getBoolean("fetch_chapters_on_add", false)
// KMK <-- // KMK <--
fun showContinueReadingButton() = preferenceStore.getBoolean( fun showContinueReadingButton() = preferenceStore.getBoolean(

View file

@ -145,9 +145,11 @@
<string name="pref_library_filter_categories_details">لن يتم عرض العناصر في الفئات المستبعدة حتى لو كانت موجودة أيضًا في الفئات المشمولة.</string> <string name="pref_library_filter_categories_details">لن يتم عرض العناصر في الفئات المستبعدة حتى لو كانت موجودة أيضًا في الفئات المشمولة.</string>
<string name="updating">جاري التحديث</string> <string name="updating">جاري التحديث</string>
<string name="pref_show_empty_categories_search">عرض الفئات الفارغة أثناء البحث/التصفية</string> <string name="pref_show_empty_categories_search">عرض الفئات الفارغة أثناء البحث/التصفية</string>
<string name="pref_sync_manga_on_add">مزامنة المانجا عند إضافتها إلى المكتبة</string>
<string name="pref_sync_manga_on_add_description">يقوم تلقائيًا بجلب البيانات الوصفية وقائمة الفصول الخاصة بمانجا جديدة عند إضافتها إلى المكتبة</string>
<string name="pref_track_on_add_library">فتح قائمة المزامنة عند الإضافة للمكتبة</string> <string name="pref_track_on_add_library">فتح قائمة المزامنة عند الإضافة للمكتبة</string>
<string name="pref_fetch_manga_metadata_on_add">تحديث بيانات المانجا عند الإضافة للمكتبة</string>
<string name="pref_fetch_manga_metadata_on_add_description">جلب العنوان والوصف والعلامات وغيرها عند إضافة المانجا إلى المكتبة</string>
<string name="pref_fetch_manga_chapters_on_add">جلب الفصول عند الإضافة للمكتبة</string>
<string name="pref_fetch_manga_chapters_on_add_description">تحديث قائمة الفصول مباشرة بعد إضافة المانجا إلى المكتبة</string>
<string name="web_dav">WebDAV</string> <string name="web_dav">WebDAV</string>
<string name="pref_webdav_url">رابط سيرفر WebDAV</string> <string name="pref_webdav_url">رابط سيرفر WebDAV</string>
<string name="pref_webdav_url_summ">ادخل رابط سيرفر WebDAV</string> <string name="pref_webdav_url_summ">ادخل رابط سيرفر WebDAV</string>

View file

@ -96,8 +96,10 @@
<string name="pref_library_filter_categories_details">Entries in excluded categories will not be shown even if they are also in included categories.</string> <string name="pref_library_filter_categories_details">Entries in excluded categories will not be shown even if they are also in included categories.</string>
<string name="updating">Updating</string> <string name="updating">Updating</string>
<string name="pref_show_empty_categories_search">Show empty categories during search/filtering</string> <string name="pref_show_empty_categories_search">Show empty categories during search/filtering</string>
<string name="pref_sync_manga_on_add">Sync manga when adding to library</string> <string name="pref_fetch_manga_metadata_on_add">Fetch metadata when adding to library</string>
<string name="pref_sync_manga_on_add_description">Automatically fetches the metadata and chapter list of a new manga when adding it to the library</string> <string name="pref_fetch_manga_metadata_on_add_description">Automatically fetches the metadata of a new manga when adding it to the library</string>
<string name="pref_fetch_manga_chapters_on_add">Fetch chapters when adding to library</string>
<string name="pref_fetch_manga_chapters_on_add_description">Automatically fetches the chapter list of a new manga when adding it to the library</string>
<!-- Extension section --> <!-- Extension section -->
<string name="extensions_page_need_refresh">Refresh extension page to update list.</string> <string name="extensions_page_need_refresh">Refresh extension page to update list.</string>
<string name="extensions_page_more">More extensions...</string> <string name="extensions_page_more">More extensions...</string>

View file

@ -172,12 +172,14 @@
<string name="action_filter_unfinished_chapter">Di natapos na kabanata</string> <string name="action_filter_unfinished_chapter">Di natapos na kabanata</string>
<string name="action_filter_non_library_entries">Mga entry na wala sa aklatan</string> <string name="action_filter_non_library_entries">Mga entry na wala sa aklatan</string>
<string name="custom_theme_palette_casual">Kaswal</string> <string name="custom_theme_palette_casual">Kaswal</string>
<string name="pref_sync_manga_on_add">I-sync ang manga kapag nagdadagdag sa aklatan</string>
<string name="pref_sync_manga_on_add_description">Awtomatikong kinukuha ang metadata at listahan ng kabanata ng isang bagong manga kapag idinagdag ito sa aklatan</string>
<string name="pref_webdav_url">Server URL ng WebDAV</string> <string name="pref_webdav_url">Server URL ng WebDAV</string>
<string name="pref_webdav_url_summ">Ipasok ang address ng WebDAV server</string> <string name="pref_webdav_url_summ">Ipasok ang address ng WebDAV server</string>
<string name="pref_webdav_username_summ">Ipasok ang iyong username ng WebDAV account</string> <string name="pref_webdav_username_summ">Ipasok ang iyong username ng WebDAV account</string>
<string name="pref_webdav_password_summ">Ipasok ang iyong password ng WebDAV account</string> <string name="pref_webdav_password_summ">Ipasok ang iyong password ng WebDAV account</string>
<string name="pref_webdav_folder_summ">Ise-save ng aplikasyon ang data sa folder na ito</string> <string name="pref_webdav_folder_summ">Ise-save ng aplikasyon ang data sa folder na ito</string>
<string name="pref_discord_rpc">Rich Presence ng Discord</string> <string name="pref_discord_rpc">Rich Presence ng Discord</string>
<string name="pref_fetch_manga_metadata_on_add">Kunin ang metadata ng manga kapag idinadagdag sa aklatan</string>
<string name="pref_fetch_manga_metadata_on_add_description">Awtomatikong kunin at i-update ang metadata ng manga kapag idinagdag mo ito sa iyong aklatan</string>
<string name="pref_fetch_manga_chapters_on_add">Kunin ang mga kabanata kapag idinadagdag ang manga sa aklatan</string>
<string name="pref_fetch_manga_chapters_on_add_description">Awtomatikong i-scan ang source para sa mga kabanata kapag idinagdag ang manga sa iyong aklatan</string>
</resources> </resources>

View file

@ -173,7 +173,6 @@
<string name="pref_discord_configuration">Apri per configurare Discord RPC</string> <string name="pref_discord_configuration">Apri per configurare Discord RPC</string>
<string name="error_opening_folder">Impossibile aprire cartella</string> <string name="error_opening_folder">Impossibile aprire cartella</string>
<string name="pref_show_empty_categories_search">Mostra categorie vuote durante ricerca/filtraggio</string> <string name="pref_show_empty_categories_search">Mostra categorie vuote durante ricerca/filtraggio</string>
<string name="pref_sync_manga_on_add">Sincronizzare i manga quando vengono aggiunti alla libreria</string>
<string name="chapters_from_database">Capitoli e cronologia dal database</string> <string name="chapters_from_database">Capitoli e cronologia dal database</string>
<string name="job_failed_schedule_update_check">Pianificazione aggiornamento automatico libreria fallita: %s</string> <string name="job_failed_schedule_update_check">Pianificazione aggiornamento automatico libreria fallita: %s</string>
<string name="job_failed_schedule_backup_check">Pianificazione backup automatico fallito: %s</string> <string name="job_failed_schedule_backup_check">Pianificazione backup automatico fallito: %s</string>
@ -186,7 +185,6 @@
<string name="pref_top_align_cover_summary">Mostra copertina allineata in alto accanto alle informazioni sul manga</string> <string name="pref_top_align_cover_summary">Mostra copertina allineata in alto accanto alle informazioni sul manga</string>
<string name="theme_doom">Doom</string> <string name="theme_doom">Doom</string>
<string name="pref_library_filter_categories_details">Le voci nelle categorie escluse non verranno mostrate anche se presenti nelle categorie incluse.</string> <string name="pref_library_filter_categories_details">Le voci nelle categorie escluse non verranno mostrate anche se presenti nelle categorie incluse.</string>
<string name="pref_sync_manga_on_add_description">Recupera automaticamente i metadati e l\'elenco dei capitoli di un nuovo manga quando lo aggiungi alla libreria</string>
<string name="web_dav">WebDAV</string> <string name="web_dav">WebDAV</string>
<string name="migrationConfigScreen_smartSearchSingleEntrySubtitle">Se abilitato, seleziona automaticamente il risultato con la corrispondenza migliore. Altrimenti, mostra tutti i risultati della ricerca per la selezione manuale.</string> <string name="migrationConfigScreen_smartSearchSingleEntrySubtitle">Se abilitato, seleziona automaticamente il risultato con la corrispondenza migliore. Altrimenti, mostra tutti i risultati della ricerca per la selezione manuale.</string>
<string name="pref_connections_summary">Discord, altri in arrivo...</string> <string name="pref_connections_summary">Discord, altri in arrivo...</string>

View file

@ -204,8 +204,10 @@
<string name="action_filter_unfinished_manga">Незаконченные тайтлы</string> <string name="action_filter_unfinished_manga">Незаконченные тайтлы</string>
<string name="action_filter_unfinished_chapter">Незаконченные главы</string> <string name="action_filter_unfinished_chapter">Незаконченные главы</string>
<string name="action_filter_non_library_entries">Тайтлы не в библиотеке</string> <string name="action_filter_non_library_entries">Тайтлы не в библиотеке</string>
<string name="pref_sync_manga_on_add">Синхронизировать тайтлы при добавлении в библиотеку</string>
<string name="pref_sync_manga_on_add_description">Автоматически загружает метаданные и список глав при добавлении в библиотеку</string>
<string name="migrationConfigScreen_smartSearchSingleEntryTitle">Использовать умный поиск</string> <string name="migrationConfigScreen_smartSearchSingleEntryTitle">Использовать умный поиск</string>
<string name="migrationConfigScreen_smartSearchSingleEntrySubtitle">Если включено, автоматически выбирает наиболее совпадающий результат. Иначе, показывает все результаты поиска для ручного выбора.</string> <string name="migrationConfigScreen_smartSearchSingleEntrySubtitle">Если включено, автоматически выбирает наиболее совпадающий результат. Иначе, показывает все результаты поиска для ручного выбора.</string>
<string name="pref_fetch_manga_metadata_on_add">Получать метаданные манги при добавлении</string>
<string name="pref_fetch_manga_metadata_on_add_description">Автоматически загружать обложку, описание и другую информацию при добавлении манги в библиотеку</string>
<string name="pref_fetch_manga_chapters_on_add">Получать главы при добавлении</string>
<string name="pref_fetch_manga_chapters_on_add_description">Автоматически обновлять список глав при добавлении манги в библиотеку</string>
</resources> </resources>

View file

@ -195,8 +195,6 @@
<string name="action_filter_unfinished_manga">尚未讀完</string> <string name="action_filter_unfinished_manga">尚未讀完</string>
<string name="action_filter_unfinished_chapter">未讀完章節</string> <string name="action_filter_unfinished_chapter">未讀完章節</string>
<string name="action_filter_non_library_entries">未收藏項目</string> <string name="action_filter_non_library_entries">未收藏項目</string>
<string name="pref_sync_manga_on_add">新增至書庫時自動同步</string>
<string name="pref_sync_manga_on_add_description">將新漫畫加入書庫時,自動取得其元資料及章節列表</string>
<string name="web_dav">WebDAV</string> <string name="web_dav">WebDAV</string>
<string name="pref_webdav_url">WebDAV 伺服器 URL</string> <string name="pref_webdav_url">WebDAV 伺服器 URL</string>
<string name="pref_webdav_url_summ">輸入 WebDAV 伺服器地址</string> <string name="pref_webdav_url_summ">輸入 WebDAV 伺服器地址</string>
@ -208,4 +206,8 @@
<string name="pref_webdav_folder_summ">應用將把資料儲存在這個資料夾中</string> <string name="pref_webdav_folder_summ">應用將把資料儲存在這個資料夾中</string>
<string name="migrationConfigScreen_smartSearchSingleEntryTitle">使用智慧搜尋</string> <string name="migrationConfigScreen_smartSearchSingleEntryTitle">使用智慧搜尋</string>
<string name="migrationConfigScreen_smartSearchSingleEntrySubtitle">若已啟用,自動選取最佳匹配結果,否則顯示所有搜尋結果供手動選擇</string> <string name="migrationConfigScreen_smartSearchSingleEntrySubtitle">若已啟用,自動選取最佳匹配結果,否則顯示所有搜尋結果供手動選擇</string>
<string name="pref_fetch_manga_metadata_on_add">新增至書櫃時更新漫畫資料</string>
<string name="pref_fetch_manga_metadata_on_add_description">在將作品加入書櫃後,自動抓取標題、作者等最新漫畫資訊</string>
<string name="pref_fetch_manga_chapters_on_add">新增至書櫃時更新章節列表</string>
<string name="pref_fetch_manga_chapters_on_add_description">在將作品加入書櫃後,自動抓取最新章節列表</string>
</resources> </resources>