Option to clear manga database

This commit is contained in:
Koitharu
2024-12-20 12:30:48 +02:00
parent 22e2411c77
commit a54744abc6
8 changed files with 61 additions and 7 deletions

View File

@@ -58,6 +58,19 @@ abstract class MangaDao {
@Delete
abstract suspend fun delete(subjects: Collection<MangaEntity>)
@Query(
"""
DELETE FROM manga WHERE NOT EXISTS(SELECT * FROM history WHERE history.manga_id == manga.manga_id)
AND NOT EXISTS(SELECT * FROM favourites WHERE favourites.manga_id == manga.manga_id)
AND NOT EXISTS(SELECT * FROM bookmarks WHERE bookmarks.manga_id == manga.manga_id)
AND NOT EXISTS(SELECT * FROM suggestions WHERE suggestions.manga_id == manga.manga_id)
AND NOT EXISTS(SELECT * FROM scrobblings WHERE scrobblings.manga_id == manga.manga_id)
AND NOT EXISTS(SELECT * FROM local_index WHERE local_index.manga_id == manga.manga_id)
AND manga.manga_id NOT IN (:idsToKeep)
""",
)
abstract suspend fun cleanup(idsToKeep: Set<Long>)
@Transaction
open suspend fun upsert(manga: MangaEntity, tags: Iterable<TagEntity>? = null) {
upsert(manga)

View File

@@ -15,6 +15,7 @@ import org.koitharu.kotatsu.core.db.entity.toMangaTags
import org.koitharu.kotatsu.core.model.LocalMangaSource
import org.koitharu.kotatsu.core.model.isLocal
import org.koitharu.kotatsu.core.nav.MangaIntent
import org.koitharu.kotatsu.core.os.AppShortcutManager
import org.koitharu.kotatsu.core.prefs.ReaderMode
import org.koitharu.kotatsu.core.util.ext.toFileOrNull
import org.koitharu.kotatsu.parsers.model.Manga
@@ -28,6 +29,7 @@ import javax.inject.Provider
class MangaDataRepository @Inject constructor(
private val db: MangaDatabase,
private val resolverProvider: Provider<MangaLinkResolver>,
private val appShortcutManagerProvider: Provider<AppShortcutManager>,
) {
suspend fun saveReaderMode(manga: Manga, mode: ReaderMode) {
@@ -119,7 +121,7 @@ class MangaDataRepository @Inject constructor(
}
}
suspend fun gcChapters() {
suspend fun gcChaptersCache() {
db.getChaptersDao().gc()
}
@@ -136,6 +138,14 @@ class MangaDataRepository @Inject constructor(
}
}
suspend fun cleanupDatabase() {
db.withTransaction {
gcChaptersCache()
val idsFromShortcuts = appShortcutManagerProvider.get().getMangaShortcuts()
db.getMangaDao().cleanup(idsFromShortcuts)
}
}
private fun MangaPrefsEntity.getColorFilterOrNull(): ReaderColorFilter? {
return if (cfBrightness != 0f || cfContrast != 0f || cfInvert || cfGrayscale) {
ReaderColorFilter(cfBrightness, cfContrast, cfInvert, cfGrayscale)

View File

@@ -740,6 +740,7 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
const val KEY_HANDLE_LINKS = "handle_links"
const val KEY_BACKUP_TG_OPEN = "backup_periodic_tg_open"
const val KEY_BACKUP_TG_TEST = "backup_periodic_tg_test"
const val KEY_CLEAR_MANGA_DATA = "manga_data_clear"
// old keys are for migration only
private const val KEY_IMAGES_PROXY_OLD = "images_proxy"

View File

@@ -158,17 +158,17 @@ class HistoryRepository @Inject constructor(
suspend fun delete(manga: Manga) = db.withTransaction {
db.getHistoryDao().delete(manga.id)
mangaRepository.gcChapters()
mangaRepository.gcChaptersCache()
}
suspend fun deleteAfter(minDate: Long) = db.withTransaction {
db.getHistoryDao().deleteAfter(minDate)
mangaRepository.gcChapters()
mangaRepository.gcChaptersCache()
}
suspend fun deleteNotFavorite() = db.withTransaction {
db.getHistoryDao().deleteNotFavorite()
mangaRepository.gcChapters()
mangaRepository.gcChaptersCache()
}
suspend fun delete(ids: Collection<Long>): ReversibleHandle {
@@ -176,7 +176,7 @@ class HistoryRepository @Inject constructor(
for (id in ids) {
db.getHistoryDao().delete(id)
}
mangaRepository.gcChapters()
mangaRepository.gcChaptersCache()
}
return ReversibleHandle {
recover(ids)

View File

@@ -107,7 +107,7 @@ class UserDataSettingsFragment : BasePreferenceFragment(R.string.data_and_privac
viewModel.loadingKeys.observe(viewLifecycleOwner) { keys ->
loadingPrefs.addAll(keys)
loadingPrefs.forEach { prefKey ->
findPreference<Preference>(prefKey)!!.isEnabled = prefKey !in keys
findPreference<Preference>(prefKey)?.isEnabled = prefKey !in keys
}
}
viewModel.onError.observeEvent(viewLifecycleOwner, SnackbarErrorObserver(listView, this))
@@ -153,6 +153,11 @@ class UserDataSettingsFragment : BasePreferenceFragment(R.string.data_and_privac
true
}
AppSettings.KEY_CLEAR_MANGA_DATA -> {
viewModel.clearMangaData()
true
}
AppSettings.KEY_UPDATES_FEED_CLEAR -> {
viewModel.clearUpdatesFeed()
true

View File

@@ -4,7 +4,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
@@ -13,6 +12,7 @@ import kotlinx.coroutines.runInterruptible
import okhttp3.Cache
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar
import org.koitharu.kotatsu.core.parser.MangaDataRepository
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.observeAsFlow
import org.koitharu.kotatsu.core.ui.BaseViewModel
@@ -27,6 +27,7 @@ import org.koitharu.kotatsu.search.domain.MangaSearchRepository
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
import java.util.EnumMap
import javax.inject.Inject
import javax.inject.Provider
@HiltViewModel
class UserDataSettingsViewModel @Inject constructor(
@@ -37,6 +38,7 @@ class UserDataSettingsViewModel @Inject constructor(
private val cookieJar: MutableCookieJar,
private val settings: AppSettings,
private val deleteReadChaptersUseCase: DeleteReadChaptersUseCase,
private val mangaDataRepositoryProvider: Provider<MangaDataRepository>,
) : BaseViewModel() {
val onActionDone = MutableEventFlow<ReversibleAction>()
@@ -139,6 +141,21 @@ class UserDataSettingsViewModel @Inject constructor(
}
}
fun clearMangaData() {
launchJob(Dispatchers.Default) {
try {
loadingKeys.update { it + AppSettings.KEY_CLEAR_MANGA_DATA }
trackingRepository.gc()
val repository = mangaDataRepositoryProvider.get()
repository.cleanupLocalManga()
repository.cleanupDatabase()
onActionDone.call(ReversibleAction(R.string.updates_feed_cleared, null))
} finally {
loadingKeys.update { it - AppSettings.KEY_CLEAR_MANGA_DATA }
}
}
}
fun cleanupChapters() {
launchJob(Dispatchers.Default) {
try {

View File

@@ -787,4 +787,6 @@
<string name="test_connection">Test connection</string>
<string name="telegram_chat_id_summary">Enter the chat ID where backups should be sent</string>
<string name="open_telegram_bot_summary">Press to open chat with Kotatsu Backup Bot</string>
<string name="clear_database">Clear database</string>
<string name="clear_database_summary">Delete information about manga that is not used</string>
</resources>

View File

@@ -89,6 +89,12 @@
android:summary="@string/loading_"
android:title="@string/clear_network_cache" />
<Preference
android:key="manga_data_clear"
android:persistent="false"
android:summary="@string/clear_database_summary"
android:title="@string/clear_database" />
<Preference
android:key="cookies_clear"
android:persistent="false"