Option to clear manga database
This commit is contained in:
@@ -58,6 +58,19 @@ abstract class MangaDao {
|
|||||||
@Delete
|
@Delete
|
||||||
abstract suspend fun delete(subjects: Collection<MangaEntity>)
|
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
|
@Transaction
|
||||||
open suspend fun upsert(manga: MangaEntity, tags: Iterable<TagEntity>? = null) {
|
open suspend fun upsert(manga: MangaEntity, tags: Iterable<TagEntity>? = null) {
|
||||||
upsert(manga)
|
upsert(manga)
|
||||||
|
|||||||
@@ -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.LocalMangaSource
|
||||||
import org.koitharu.kotatsu.core.model.isLocal
|
import org.koitharu.kotatsu.core.model.isLocal
|
||||||
import org.koitharu.kotatsu.core.nav.MangaIntent
|
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.prefs.ReaderMode
|
||||||
import org.koitharu.kotatsu.core.util.ext.toFileOrNull
|
import org.koitharu.kotatsu.core.util.ext.toFileOrNull
|
||||||
import org.koitharu.kotatsu.parsers.model.Manga
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
@@ -28,6 +29,7 @@ import javax.inject.Provider
|
|||||||
class MangaDataRepository @Inject constructor(
|
class MangaDataRepository @Inject constructor(
|
||||||
private val db: MangaDatabase,
|
private val db: MangaDatabase,
|
||||||
private val resolverProvider: Provider<MangaLinkResolver>,
|
private val resolverProvider: Provider<MangaLinkResolver>,
|
||||||
|
private val appShortcutManagerProvider: Provider<AppShortcutManager>,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun saveReaderMode(manga: Manga, mode: ReaderMode) {
|
suspend fun saveReaderMode(manga: Manga, mode: ReaderMode) {
|
||||||
@@ -119,7 +121,7 @@ class MangaDataRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun gcChapters() {
|
suspend fun gcChaptersCache() {
|
||||||
db.getChaptersDao().gc()
|
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? {
|
private fun MangaPrefsEntity.getColorFilterOrNull(): ReaderColorFilter? {
|
||||||
return if (cfBrightness != 0f || cfContrast != 0f || cfInvert || cfGrayscale) {
|
return if (cfBrightness != 0f || cfContrast != 0f || cfInvert || cfGrayscale) {
|
||||||
ReaderColorFilter(cfBrightness, cfContrast, cfInvert, cfGrayscale)
|
ReaderColorFilter(cfBrightness, cfContrast, cfInvert, cfGrayscale)
|
||||||
|
|||||||
@@ -740,6 +740,7 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
|||||||
const val KEY_HANDLE_LINKS = "handle_links"
|
const val KEY_HANDLE_LINKS = "handle_links"
|
||||||
const val KEY_BACKUP_TG_OPEN = "backup_periodic_tg_open"
|
const val KEY_BACKUP_TG_OPEN = "backup_periodic_tg_open"
|
||||||
const val KEY_BACKUP_TG_TEST = "backup_periodic_tg_test"
|
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
|
// old keys are for migration only
|
||||||
private const val KEY_IMAGES_PROXY_OLD = "images_proxy"
|
private const val KEY_IMAGES_PROXY_OLD = "images_proxy"
|
||||||
|
|||||||
@@ -158,17 +158,17 @@ class HistoryRepository @Inject constructor(
|
|||||||
|
|
||||||
suspend fun delete(manga: Manga) = db.withTransaction {
|
suspend fun delete(manga: Manga) = db.withTransaction {
|
||||||
db.getHistoryDao().delete(manga.id)
|
db.getHistoryDao().delete(manga.id)
|
||||||
mangaRepository.gcChapters()
|
mangaRepository.gcChaptersCache()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun deleteAfter(minDate: Long) = db.withTransaction {
|
suspend fun deleteAfter(minDate: Long) = db.withTransaction {
|
||||||
db.getHistoryDao().deleteAfter(minDate)
|
db.getHistoryDao().deleteAfter(minDate)
|
||||||
mangaRepository.gcChapters()
|
mangaRepository.gcChaptersCache()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun deleteNotFavorite() = db.withTransaction {
|
suspend fun deleteNotFavorite() = db.withTransaction {
|
||||||
db.getHistoryDao().deleteNotFavorite()
|
db.getHistoryDao().deleteNotFavorite()
|
||||||
mangaRepository.gcChapters()
|
mangaRepository.gcChaptersCache()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun delete(ids: Collection<Long>): ReversibleHandle {
|
suspend fun delete(ids: Collection<Long>): ReversibleHandle {
|
||||||
@@ -176,7 +176,7 @@ class HistoryRepository @Inject constructor(
|
|||||||
for (id in ids) {
|
for (id in ids) {
|
||||||
db.getHistoryDao().delete(id)
|
db.getHistoryDao().delete(id)
|
||||||
}
|
}
|
||||||
mangaRepository.gcChapters()
|
mangaRepository.gcChaptersCache()
|
||||||
}
|
}
|
||||||
return ReversibleHandle {
|
return ReversibleHandle {
|
||||||
recover(ids)
|
recover(ids)
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ class UserDataSettingsFragment : BasePreferenceFragment(R.string.data_and_privac
|
|||||||
viewModel.loadingKeys.observe(viewLifecycleOwner) { keys ->
|
viewModel.loadingKeys.observe(viewLifecycleOwner) { keys ->
|
||||||
loadingPrefs.addAll(keys)
|
loadingPrefs.addAll(keys)
|
||||||
loadingPrefs.forEach { prefKey ->
|
loadingPrefs.forEach { prefKey ->
|
||||||
findPreference<Preference>(prefKey)!!.isEnabled = prefKey !in keys
|
findPreference<Preference>(prefKey)?.isEnabled = prefKey !in keys
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
viewModel.onError.observeEvent(viewLifecycleOwner, SnackbarErrorObserver(listView, this))
|
viewModel.onError.observeEvent(viewLifecycleOwner, SnackbarErrorObserver(listView, this))
|
||||||
@@ -153,6 +153,11 @@ class UserDataSettingsFragment : BasePreferenceFragment(R.string.data_and_privac
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AppSettings.KEY_CLEAR_MANGA_DATA -> {
|
||||||
|
viewModel.clearMangaData()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
AppSettings.KEY_UPDATES_FEED_CLEAR -> {
|
AppSettings.KEY_UPDATES_FEED_CLEAR -> {
|
||||||
viewModel.clearUpdatesFeed()
|
viewModel.clearUpdatesFeed()
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.cancelAndJoin
|
import kotlinx.coroutines.cancelAndJoin
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
@@ -13,6 +12,7 @@ import kotlinx.coroutines.runInterruptible
|
|||||||
import okhttp3.Cache
|
import okhttp3.Cache
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar
|
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.AppSettings
|
||||||
import org.koitharu.kotatsu.core.prefs.observeAsFlow
|
import org.koitharu.kotatsu.core.prefs.observeAsFlow
|
||||||
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
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 org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
||||||
import java.util.EnumMap
|
import java.util.EnumMap
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Provider
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class UserDataSettingsViewModel @Inject constructor(
|
class UserDataSettingsViewModel @Inject constructor(
|
||||||
@@ -37,6 +38,7 @@ class UserDataSettingsViewModel @Inject constructor(
|
|||||||
private val cookieJar: MutableCookieJar,
|
private val cookieJar: MutableCookieJar,
|
||||||
private val settings: AppSettings,
|
private val settings: AppSettings,
|
||||||
private val deleteReadChaptersUseCase: DeleteReadChaptersUseCase,
|
private val deleteReadChaptersUseCase: DeleteReadChaptersUseCase,
|
||||||
|
private val mangaDataRepositoryProvider: Provider<MangaDataRepository>,
|
||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
|
|
||||||
val onActionDone = MutableEventFlow<ReversibleAction>()
|
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() {
|
fun cleanupChapters() {
|
||||||
launchJob(Dispatchers.Default) {
|
launchJob(Dispatchers.Default) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -787,4 +787,6 @@
|
|||||||
<string name="test_connection">Test connection</string>
|
<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="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="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>
|
</resources>
|
||||||
|
|||||||
@@ -89,6 +89,12 @@
|
|||||||
android:summary="@string/loading_"
|
android:summary="@string/loading_"
|
||||||
android:title="@string/clear_network_cache" />
|
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
|
<Preference
|
||||||
android:key="cookies_clear"
|
android:key="cookies_clear"
|
||||||
android:persistent="false"
|
android:persistent="false"
|
||||||
|
|||||||
Reference in New Issue
Block a user