feat: Add saved filters to backup and restore

This commit adds support for backing up and restoring saved filters.

- Added a new `SAVED_FILTERS` section to the backup process.
- Implemented the logic to read filters from SharedPreferences during backup and write them back during restore.
This commit is contained in:
google-labs-jules[bot]
2025-10-22 10:42:23 +00:00
committed by Koitharu
parent dbada34a43
commit dec45f7851
3 changed files with 69 additions and 0 deletions

View File

@@ -26,6 +26,7 @@ import org.koitharu.kotatsu.backups.data.model.CategoryBackup
import org.koitharu.kotatsu.backups.data.model.FavouriteBackup
import org.koitharu.kotatsu.backups.data.model.HistoryBackup
import org.koitharu.kotatsu.backups.data.model.MangaBackup
import org.koitharu.kotatsu.backups.data.model.SavedFilterBackup
import org.koitharu.kotatsu.backups.data.model.ScrobblingBackup
import org.koitharu.kotatsu.backups.data.model.SourceBackup
import org.koitharu.kotatsu.backups.data.model.StatisticBackup
@@ -34,6 +35,8 @@ import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.CompositeResult
import org.koitharu.kotatsu.core.util.progress.Progress
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
import org.koitharu.kotatsu.filter.data.SavedFiltersRepository
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.reader.data.TapGridSettings
import java.io.InputStream
@@ -48,6 +51,8 @@ class BackupRepository @Inject constructor(
private val database: MangaDatabase,
private val settings: AppSettings,
private val tapGridSettings: TapGridSettings,
private val mangaSourcesRepository: MangaSourcesRepository,
private val savedFiltersRepository: SavedFiltersRepository,
) {
private val json = Json {
@@ -123,6 +128,18 @@ class BackupRepository @Inject constructor(
data = database.getStatsDao().dumpEnabled().map { StatisticBackup(it) },
serializer = serializer(),
)
BackupSection.SAVED_FILTERS -> {
val sources = mangaSourcesRepository.getEnabledSources()
val filters = sources.flatMap { source ->
savedFiltersRepository.getAll(source)
}
output.writeJsonArray(
section = BackupSection.SAVED_FILTERS,
data = filters.asFlow().map { SavedFilterBackup(it) },
serializer = serializer(),
)
}
}
progress?.emit(commonProgress)
commonProgress++
@@ -185,6 +202,15 @@ class BackupRepository @Inject constructor(
getStatsDao().upsert(it.toEntity())
}
BackupSection.SAVED_FILTERS -> input.readJsonArray<SavedFilterBackup>(serializer())
.restoreWithoutTransaction {
savedFiltersRepository.save(
source = it.source,
name = it.name,
filter = it.filter,
)
}
null -> CompositeResult.EMPTY // skip unknown entries
}
progress?.emit(commonProgress)
@@ -281,4 +307,12 @@ class BackupRepository @Inject constructor(
}
}
}
private suspend inline fun <T> Sequence<T>.restoreWithoutTransaction(crossinline block: suspend (T) -> Unit): CompositeResult {
return fold(CompositeResult.EMPTY) { result, item ->
result + runCatchingCancellable {
block(item)
}
}
}
}

View File

@@ -0,0 +1,34 @@
package org.koitharu.kotatsu.backups.data.model
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import org.koitharu.kotatsu.core.model.MangaSourceSerializer
import org.koitharu.kotatsu.filter.data.MangaListFilterSerializer
import org.koitharu.kotatsu.filter.data.PersistableFilter
import org.koitharu.kotatsu.parsers.model.MangaListFilter
import org.koitharu.kotatsu.parsers.model.MangaSource
@Serializable
data class SavedFilterBackup(
@SerialName("name")
val name: String,
@Serializable(with = MangaSourceSerializer::class)
@SerialName("source")
val source: MangaSource,
@Serializable(with = MangaListFilterSerializer::class)
@SerialName("filter")
val filter: MangaListFilter,
) {
constructor(persistableFilter: PersistableFilter) : this(
name = persistableFilter.name,
source = persistableFilter.source,
filter = persistableFilter.filter,
)
fun toPersistableFilter() = PersistableFilter(
name = name,
source = source,
filter = filter,
)
}

View File

@@ -17,6 +17,7 @@ enum class BackupSection(
SOURCES("sources"),
SCROBBLING("scrobbling"),
STATS("statistics"),
SAVED_FILTERS("saved_filters"),
;
companion object {