More backup/restore code cleanup
(cherry picked from commit 9f0052eceb8bdbe9ca1ea18a2aac18a4718387bf) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupManager.kt # app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestore.kt # app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt # app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt
This commit is contained in:
parent
16bd7853ad
commit
8b777e1e5a
@ -1,212 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.data.backup
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.net.Uri
|
|
||||||
import eu.kanade.data.DatabaseHandler
|
|
||||||
import eu.kanade.data.manga.mangaMapper
|
|
||||||
import eu.kanade.data.toLong
|
|
||||||
import eu.kanade.domain.manga.interactor.GetFavorites
|
|
||||||
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
|
|
||||||
import eu.kanade.domain.manga.interactor.GetMergedManga
|
|
||||||
import eu.kanade.domain.manga.interactor.InsertFlatMetadata
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
|
||||||
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
|
||||||
import exh.metadata.metadata.base.FlatMetadata
|
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import data.Mangas as DbManga
|
|
||||||
import eu.kanade.domain.manga.model.Manga as DomainManga
|
|
||||||
|
|
||||||
abstract class AbstractBackupManager(protected val context: Context) {
|
|
||||||
|
|
||||||
protected val handler: DatabaseHandler = Injekt.get()
|
|
||||||
|
|
||||||
internal val sourceManager: SourceManager = Injekt.get()
|
|
||||||
internal val trackManager: TrackManager = Injekt.get()
|
|
||||||
protected val preferences: PreferencesHelper = Injekt.get()
|
|
||||||
private val getFavorites: GetFavorites = Injekt.get()
|
|
||||||
|
|
||||||
// SY -->
|
|
||||||
private val getMergedManga: GetMergedManga = Injekt.get()
|
|
||||||
protected val customMangaManager: CustomMangaManager = Injekt.get()
|
|
||||||
private val insertFlatMetadata: InsertFlatMetadata = Injekt.get()
|
|
||||||
private val getFlatMetadataById: GetFlatMetadataById = Injekt.get()
|
|
||||||
// SY <--
|
|
||||||
|
|
||||||
abstract suspend fun createBackup(uri: Uri, flags: Int, isAutoBackup: Boolean): String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns manga
|
|
||||||
*
|
|
||||||
* @return [Manga], null if not found
|
|
||||||
*/
|
|
||||||
internal suspend fun getMangaFromDatabase(url: String, source: Long): DbManga? {
|
|
||||||
return handler.awaitOneOrNull { mangasQueries.getMangaByUrlAndSource(url, source) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns list containing manga from library
|
|
||||||
*
|
|
||||||
* @return [Manga] from library
|
|
||||||
*/
|
|
||||||
protected suspend fun getFavoriteManga(): List<DomainManga> {
|
|
||||||
return getFavorites.await()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SY -->
|
|
||||||
protected suspend fun getReadManga(): List<DomainManga> {
|
|
||||||
return handler.awaitList { mangasQueries.getReadMangaNotInLibrary(mangaMapper) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns list containing merged manga that are possibly not in the library
|
|
||||||
*
|
|
||||||
* @return merged [Manga] that are possibly not in the library
|
|
||||||
*/
|
|
||||||
protected suspend fun getMergedManga(): List<DomainManga> {
|
|
||||||
return getMergedManga.await()
|
|
||||||
}
|
|
||||||
|
|
||||||
protected suspend fun getFlatMetadata(mangaId: Long) = getFlatMetadataById.await(mangaId)
|
|
||||||
|
|
||||||
protected suspend fun insertFlatMetadata(flatMetadata: FlatMetadata) = insertFlatMetadata.await(flatMetadata)
|
|
||||||
// SY <--
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts manga and returns id
|
|
||||||
*
|
|
||||||
* @return id of [Manga], null if not found
|
|
||||||
*/
|
|
||||||
internal suspend fun insertManga(manga: Manga): Long {
|
|
||||||
return handler.awaitOne(true) {
|
|
||||||
mangasQueries.insert(
|
|
||||||
source = manga.source,
|
|
||||||
url = manga.url,
|
|
||||||
artist = manga.artist,
|
|
||||||
author = manga.author,
|
|
||||||
description = manga.description,
|
|
||||||
genre = manga.getGenres(),
|
|
||||||
title = manga.title,
|
|
||||||
status = manga.status.toLong(),
|
|
||||||
thumbnailUrl = manga.thumbnail_url,
|
|
||||||
favorite = manga.favorite,
|
|
||||||
lastUpdate = manga.last_update,
|
|
||||||
nextUpdate = 0L,
|
|
||||||
initialized = manga.initialized,
|
|
||||||
viewerFlags = manga.viewer_flags.toLong(),
|
|
||||||
chapterFlags = manga.chapter_flags.toLong(),
|
|
||||||
coverLastModified = manga.cover_last_modified,
|
|
||||||
dateAdded = manga.date_added,
|
|
||||||
)
|
|
||||||
mangasQueries.selectLastInsertedRowId()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal suspend fun updateManga(manga: Manga): Long {
|
|
||||||
handler.await(true) {
|
|
||||||
mangasQueries.update(
|
|
||||||
source = manga.source,
|
|
||||||
url = manga.url,
|
|
||||||
artist = manga.artist,
|
|
||||||
author = manga.author,
|
|
||||||
description = manga.description,
|
|
||||||
genre = manga.genre,
|
|
||||||
title = manga.title,
|
|
||||||
status = manga.status.toLong(),
|
|
||||||
thumbnailUrl = manga.thumbnail_url,
|
|
||||||
favorite = manga.favorite.toLong(),
|
|
||||||
lastUpdate = manga.last_update,
|
|
||||||
initialized = manga.initialized.toLong(),
|
|
||||||
viewer = manga.viewer_flags.toLong(),
|
|
||||||
chapterFlags = manga.chapter_flags.toLong(),
|
|
||||||
coverLastModified = manga.cover_last_modified,
|
|
||||||
dateAdded = manga.date_added,
|
|
||||||
mangaId = manga.id!!,
|
|
||||||
filteredScanlators = manga.filtered_scanlators,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return manga.id!!
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts list of chapters
|
|
||||||
*/
|
|
||||||
protected suspend fun insertChapters(chapters: List<Chapter>) {
|
|
||||||
handler.await(true) {
|
|
||||||
chapters.forEach { chapter ->
|
|
||||||
chaptersQueries.insert(
|
|
||||||
chapter.manga_id!!,
|
|
||||||
chapter.url,
|
|
||||||
chapter.name,
|
|
||||||
chapter.scanlator,
|
|
||||||
chapter.read,
|
|
||||||
chapter.bookmark,
|
|
||||||
chapter.last_page_read.toLong(),
|
|
||||||
chapter.chapter_number,
|
|
||||||
chapter.source_order.toLong(),
|
|
||||||
chapter.date_fetch,
|
|
||||||
chapter.date_upload,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates a list of chapters
|
|
||||||
*/
|
|
||||||
protected suspend fun updateChapters(chapters: List<Chapter>) {
|
|
||||||
handler.await(true) {
|
|
||||||
chapters.forEach { chapter ->
|
|
||||||
chaptersQueries.update(
|
|
||||||
chapter.manga_id!!,
|
|
||||||
chapter.url,
|
|
||||||
chapter.name,
|
|
||||||
chapter.scanlator,
|
|
||||||
chapter.read.toLong(),
|
|
||||||
chapter.bookmark.toLong(),
|
|
||||||
chapter.last_page_read.toLong(),
|
|
||||||
chapter.chapter_number.toDouble(),
|
|
||||||
chapter.source_order.toLong(),
|
|
||||||
chapter.date_fetch,
|
|
||||||
chapter.date_upload,
|
|
||||||
chapter.id!!,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates a list of chapters with known database ids
|
|
||||||
*/
|
|
||||||
protected suspend fun updateKnownChapters(chapters: List<Chapter>) {
|
|
||||||
handler.await(true) {
|
|
||||||
chapters.forEach { chapter ->
|
|
||||||
chaptersQueries.update(
|
|
||||||
mangaId = null,
|
|
||||||
url = null,
|
|
||||||
name = null,
|
|
||||||
scanlator = null,
|
|
||||||
read = chapter.read.toLong(),
|
|
||||||
bookmark = chapter.bookmark.toLong(),
|
|
||||||
lastPageRead = chapter.last_page_read.toLong(),
|
|
||||||
chapterNumber = null,
|
|
||||||
sourceOrder = null,
|
|
||||||
dateFetch = null,
|
|
||||||
dateUpload = null,
|
|
||||||
chapterId = chapter.id!!,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return number of backups.
|
|
||||||
*
|
|
||||||
* @return number of backups selected by user
|
|
||||||
*/
|
|
||||||
protected fun numberOfBackups(): Int = preferences.numberOfBackups().get()
|
|
||||||
}
|
|
@ -1,133 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.data.backup
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.net.Uri
|
|
||||||
import eu.kanade.data.DatabaseHandler
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
|
||||||
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
|
||||||
import eu.kanade.tachiyomi.util.system.createFileInCacheDir
|
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.io.File
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Date
|
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
abstract class AbstractBackupRestore<T : AbstractBackupManager>(protected val context: Context, protected val notifier: BackupNotifier) {
|
|
||||||
|
|
||||||
protected val handler: DatabaseHandler by injectLazy()
|
|
||||||
protected val trackManager: TrackManager by injectLazy()
|
|
||||||
|
|
||||||
// SY -->
|
|
||||||
protected val customMangaManager: CustomMangaManager by injectLazy()
|
|
||||||
// SY <--
|
|
||||||
|
|
||||||
var job: Job? = null
|
|
||||||
|
|
||||||
protected lateinit var backupManager: T
|
|
||||||
|
|
||||||
protected var restoreAmount = 0
|
|
||||||
protected var restoreProgress = 0
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mapping of source ID to source name from backup data
|
|
||||||
*/
|
|
||||||
protected var sourceMapping: Map<Long, String> = emptyMap()
|
|
||||||
|
|
||||||
protected val errors = mutableListOf<Pair<Date, String>>()
|
|
||||||
|
|
||||||
abstract suspend fun performRestore(uri: Uri): Boolean
|
|
||||||
|
|
||||||
suspend fun restoreBackup(uri: Uri): Boolean {
|
|
||||||
val startTime = System.currentTimeMillis()
|
|
||||||
restoreProgress = 0
|
|
||||||
errors.clear()
|
|
||||||
|
|
||||||
if (!performRestore(uri)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
val endTime = System.currentTimeMillis()
|
|
||||||
val time = endTime - startTime
|
|
||||||
|
|
||||||
val logFile = writeErrorLog()
|
|
||||||
|
|
||||||
notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Refreshes tracking information.
|
|
||||||
*
|
|
||||||
* @param manga manga that needs updating.
|
|
||||||
* @param tracks list containing tracks from restore file.
|
|
||||||
*/
|
|
||||||
internal suspend fun updateTracking(manga: Manga, tracks: List<Track>) {
|
|
||||||
tracks.forEach { track ->
|
|
||||||
val service = trackManager.getService(track.sync_id.toLong())
|
|
||||||
if (service != null && service.isLogged) {
|
|
||||||
try {
|
|
||||||
val updatedTrack = service.refresh(track)
|
|
||||||
handler.await {
|
|
||||||
manga_syncQueries.insert(
|
|
||||||
updatedTrack.manga_id,
|
|
||||||
updatedTrack.sync_id.toLong(),
|
|
||||||
updatedTrack.media_id,
|
|
||||||
updatedTrack.library_id,
|
|
||||||
updatedTrack.title,
|
|
||||||
updatedTrack.last_chapter_read.toDouble(),
|
|
||||||
updatedTrack.total_chapters.toLong(),
|
|
||||||
updatedTrack.status.toLong(),
|
|
||||||
updatedTrack.score,
|
|
||||||
updatedTrack.tracking_url,
|
|
||||||
updatedTrack.started_reading_date,
|
|
||||||
updatedTrack.finished_reading_date,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
errors.add(Date() to "${manga.title} - ${e.message}")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val serviceName = service?.nameRes()?.let { context.getString(it) }
|
|
||||||
errors.add(Date() to "${manga.title} - ${context.getString(R.string.tracker_not_logged_in, serviceName)}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called to update dialog in [BackupConst]
|
|
||||||
*
|
|
||||||
* @param progress restore progress
|
|
||||||
* @param amount total restoreAmount of manga
|
|
||||||
* @param title title of restored manga
|
|
||||||
*/
|
|
||||||
internal fun showRestoreProgress(
|
|
||||||
progress: Int,
|
|
||||||
amount: Int,
|
|
||||||
title: String,
|
|
||||||
) {
|
|
||||||
notifier.showRestoreProgress(title, progress, amount)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun writeErrorLog(): File {
|
|
||||||
try {
|
|
||||||
if (errors.isNotEmpty()) {
|
|
||||||
val file = context.createFileInCacheDir("tachiyomi_restore.txt")
|
|
||||||
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault())
|
|
||||||
|
|
||||||
file.bufferedWriter().use { out ->
|
|
||||||
errors.forEach { (date, message) ->
|
|
||||||
out.write("[${sdf.format(date)}] $message\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return file
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
// Empty
|
|
||||||
}
|
|
||||||
return File("")
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,11 +5,17 @@ import android.net.Uri
|
|||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
import data.Manga_sync
|
import data.Manga_sync
|
||||||
import data.Mangas
|
import data.Mangas
|
||||||
import eu.kanade.data.category.categoryMapper
|
import eu.kanade.data.DatabaseHandler
|
||||||
import eu.kanade.data.exh.mergedMangaReferenceMapper
|
import eu.kanade.data.exh.mergedMangaReferenceMapper
|
||||||
import eu.kanade.data.manga.mangaMapper
|
import eu.kanade.data.manga.mangaMapper
|
||||||
|
import eu.kanade.data.toLong
|
||||||
|
import eu.kanade.domain.category.interactor.GetCategories
|
||||||
import eu.kanade.domain.category.model.Category
|
import eu.kanade.domain.category.model.Category
|
||||||
import eu.kanade.domain.history.model.HistoryUpdate
|
import eu.kanade.domain.history.model.HistoryUpdate
|
||||||
|
import eu.kanade.domain.manga.interactor.GetFavorites
|
||||||
|
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
|
||||||
|
import eu.kanade.domain.manga.interactor.GetMergedManga
|
||||||
|
import eu.kanade.domain.manga.interactor.InsertFlatMetadata
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY
|
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY_MASK
|
import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY_MASK
|
||||||
@ -40,6 +46,9 @@ import eu.kanade.tachiyomi.data.backup.models.backupTrackMapper
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
|
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
import eu.kanade.tachiyomi.util.system.logcat
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
import exh.source.MERGED_SOURCE_ID
|
import exh.source.MERGED_SOURCE_ID
|
||||||
@ -50,33 +59,47 @@ import logcat.LogPriority
|
|||||||
import okio.buffer
|
import okio.buffer
|
||||||
import okio.gzip
|
import okio.gzip
|
||||||
import okio.sink
|
import okio.sink
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import eu.kanade.domain.manga.model.Manga as DomainManga
|
import eu.kanade.domain.manga.model.Manga as DomainManga
|
||||||
|
|
||||||
class BackupManager(context: Context) : AbstractBackupManager(context) {
|
class BackupManager(
|
||||||
|
private val context: Context,
|
||||||
|
) {
|
||||||
|
|
||||||
val parser = ProtoBuf
|
private val handler: DatabaseHandler = Injekt.get()
|
||||||
|
private val sourceManager: SourceManager = Injekt.get()
|
||||||
|
private val preferences: PreferencesHelper = Injekt.get()
|
||||||
|
private val getCategories: GetCategories = Injekt.get()
|
||||||
|
private val getFavorites: GetFavorites = Injekt.get()
|
||||||
|
|
||||||
|
// SY -->
|
||||||
|
private val getMergedManga: GetMergedManga = Injekt.get()
|
||||||
|
private val customMangaManager: CustomMangaManager = Injekt.get()
|
||||||
|
private val insertFlatMetadata: InsertFlatMetadata = Injekt.get()
|
||||||
|
private val getFlatMetadataById: GetFlatMetadataById = Injekt.get()
|
||||||
|
// SY <--
|
||||||
|
|
||||||
|
internal val parser = ProtoBuf
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create backup Json file from database
|
* Create backup file from database
|
||||||
*
|
*
|
||||||
* @param uri path of Uri
|
* @param uri path of Uri
|
||||||
* @param isAutoBackup backup called from scheduled backup job
|
* @param isAutoBackup backup called from scheduled backup job
|
||||||
*/
|
*/
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
override suspend fun createBackup(uri: Uri, flags: Int, isAutoBackup: Boolean): String {
|
suspend fun createBackup(uri: Uri, flags: Int, isAutoBackup: Boolean): String {
|
||||||
// Create root object
|
val databaseManga = getFavorites.await() /* SY --> */ + if (flags and BACKUP_READ_MANGA_MASK == BACKUP_READ_MANGA) {
|
||||||
var backup: Backup? = null
|
handler.awaitList { mangasQueries.getReadMangaNotInLibrary(mangaMapper) }
|
||||||
|
|
||||||
val databaseManga = getFavoriteManga() /* SY --> */ + if (flags and BACKUP_READ_MANGA_MASK == BACKUP_READ_MANGA) {
|
|
||||||
getReadManga()
|
|
||||||
} else {
|
} else {
|
||||||
emptyList()
|
emptyList()
|
||||||
} + getMergedManga() // SY <--
|
} + getMergedManga.await() // SY <--
|
||||||
|
|
||||||
backup = Backup(
|
val backup = Backup(
|
||||||
backupMangas(databaseManga, flags),
|
backupMangas(databaseManga, flags),
|
||||||
backupCategories(flags),
|
backupCategories(flags),
|
||||||
emptyList(),
|
emptyList(),
|
||||||
@ -95,7 +118,7 @@ class BackupManager(context: Context) : AbstractBackupManager(context) {
|
|||||||
dir = dir.createDirectory("automatic")
|
dir = dir.createDirectory("automatic")
|
||||||
|
|
||||||
// Delete older backups
|
// Delete older backups
|
||||||
val numberOfBackups = numberOfBackups()
|
val numberOfBackups = preferences.numberOfBackups().get()
|
||||||
val backupRegex = Regex("""tachiyomi_\d+-\d+-\d+_\d+-\d+.proto.gz""")
|
val backupRegex = Regex("""tachiyomi_\d+-\d+-\d+_\d+-\d+.proto.gz""")
|
||||||
dir.listFiles { _, filename -> backupRegex.matches(filename) }
|
dir.listFiles { _, filename -> backupRegex.matches(filename) }
|
||||||
.orEmpty()
|
.orEmpty()
|
||||||
@ -115,7 +138,7 @@ class BackupManager(context: Context) : AbstractBackupManager(context) {
|
|||||||
throw IllegalStateException("Failed to get handle on file")
|
throw IllegalStateException("Failed to get handle on file")
|
||||||
}
|
}
|
||||||
|
|
||||||
val byteArray = parser.encodeToByteArray(BackupSerializer, backup!!)
|
val byteArray = parser.encodeToByteArray(BackupSerializer, backup)
|
||||||
if (byteArray.isEmpty()) {
|
if (byteArray.isEmpty()) {
|
||||||
throw IllegalStateException(context.getString(R.string.empty_backup_error))
|
throw IllegalStateException(context.getString(R.string.empty_backup_error))
|
||||||
}
|
}
|
||||||
@ -155,7 +178,7 @@ class BackupManager(context: Context) : AbstractBackupManager(context) {
|
|||||||
private suspend fun backupCategories(options: Int): List<BackupCategory> {
|
private suspend fun backupCategories(options: Int): List<BackupCategory> {
|
||||||
// Check if user wants category information in backup
|
// Check if user wants category information in backup
|
||||||
return if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) {
|
return if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) {
|
||||||
handler.awaitList { categoriesQueries.getCategories(categoryMapper) }
|
getCategories.await()
|
||||||
.filterNot(Category::isSystemCategory)
|
.filterNot(Category::isSystemCategory)
|
||||||
.map(backupCategoryMapper)
|
.map(backupCategoryMapper)
|
||||||
} else {
|
} else {
|
||||||
@ -198,7 +221,7 @@ class BackupManager(context: Context) : AbstractBackupManager(context) {
|
|||||||
|
|
||||||
val source = sourceManager.get(manga.source)?.getMainSource<MetadataSource<*, *>>()
|
val source = sourceManager.get(manga.source)?.getMainSource<MetadataSource<*, *>>()
|
||||||
if (source != null) {
|
if (source != null) {
|
||||||
getFlatMetadata(manga.id)?.let { flatMetadata ->
|
getFlatMetadataById.await(manga.id)?.let { flatMetadata ->
|
||||||
mangaObject.flatMetadata = BackupFlatMetadata.copyFrom(flatMetadata)
|
mangaObject.flatMetadata = BackupFlatMetadata.copyFrom(flatMetadata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -216,7 +239,7 @@ class BackupManager(context: Context) : AbstractBackupManager(context) {
|
|||||||
// Check if user wants category information in backup
|
// Check if user wants category information in backup
|
||||||
if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) {
|
if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) {
|
||||||
// Backup categories for this manga
|
// Backup categories for this manga
|
||||||
val categoriesForManga = handler.awaitList { categoriesQueries.getCategoriesByMangaId(manga.id) }
|
val categoriesForManga = getCategories.await(manga.id)
|
||||||
if (categoriesForManga.isNotEmpty()) {
|
if (categoriesForManga.isNotEmpty()) {
|
||||||
mangaObject.categories = categoriesForManga.map { it.order }
|
mangaObject.categories = categoriesForManga.map { it.order }
|
||||||
}
|
}
|
||||||
@ -247,7 +270,7 @@ class BackupManager(context: Context) : AbstractBackupManager(context) {
|
|||||||
return mangaObject
|
return mangaObject
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun restoreExistingManga(manga: Manga, dbManga: Mangas) {
|
internal suspend fun restoreExistingManga(manga: Manga, dbManga: Mangas) {
|
||||||
manga.id = dbManga._id
|
manga.id = dbManga._id
|
||||||
manga.copyFrom(dbManga)
|
manga.copyFrom(dbManga)
|
||||||
updateManga(manga)
|
updateManga(manga)
|
||||||
@ -259,7 +282,7 @@ class BackupManager(context: Context) : AbstractBackupManager(context) {
|
|||||||
* @param manga manga that needs updating
|
* @param manga manga that needs updating
|
||||||
* @return Updated manga info.
|
* @return Updated manga info.
|
||||||
*/
|
*/
|
||||||
suspend fun restoreNewManga(manga: Manga): Manga {
|
internal suspend fun restoreNewManga(manga: Manga): Manga {
|
||||||
return manga.also {
|
return manga.also {
|
||||||
it.initialized = it.description != null
|
it.initialized = it.description != null
|
||||||
it.id = insertManga(it)
|
it.id = insertManga(it)
|
||||||
@ -273,7 +296,7 @@ class BackupManager(context: Context) : AbstractBackupManager(context) {
|
|||||||
*/
|
*/
|
||||||
internal suspend fun restoreCategories(backupCategories: List<BackupCategory>) {
|
internal suspend fun restoreCategories(backupCategories: List<BackupCategory>) {
|
||||||
// Get categories from file and from db
|
// Get categories from file and from db
|
||||||
val dbCategories = handler.awaitList { categoriesQueries.getCategories(categoryMapper) }
|
val dbCategories = getCategories.await()
|
||||||
|
|
||||||
val categories = backupCategories.map {
|
val categories = backupCategories.map {
|
||||||
var category = it.getCategory()
|
var category = it.getCategory()
|
||||||
@ -313,7 +336,7 @@ class BackupManager(context: Context) : AbstractBackupManager(context) {
|
|||||||
* @param categories the categories to restore.
|
* @param categories the categories to restore.
|
||||||
*/
|
*/
|
||||||
internal suspend fun restoreCategories(manga: Manga, categories: List<Int>, backupCategories: List<BackupCategory>) {
|
internal suspend fun restoreCategories(manga: Manga, categories: List<Int>, backupCategories: List<BackupCategory>) {
|
||||||
val dbCategories = handler.awaitList { categoriesQueries.getCategories() }
|
val dbCategories = getCategories.await()
|
||||||
val mangaCategoriesToUpdate = mutableListOf<Pair<Long, Long>>()
|
val mangaCategoriesToUpdate = mutableListOf<Pair<Long, Long>>()
|
||||||
|
|
||||||
categories.forEach { backupCategoryOrder ->
|
categories.forEach { backupCategoryOrder ->
|
||||||
@ -399,7 +422,6 @@ class BackupManager(context: Context) : AbstractBackupManager(context) {
|
|||||||
tracks.map { it.manga_id = manga.id!! }
|
tracks.map { it.manga_id = manga.id!! }
|
||||||
|
|
||||||
// Get tracks from database
|
// Get tracks from database
|
||||||
|
|
||||||
val dbTracks = handler.awaitList { manga_syncQueries.getTracksByMangaId(manga.id!!) }
|
val dbTracks = handler.awaitList { manga_syncQueries.getTracksByMangaId(manga.id!!) }
|
||||||
val toUpdate = mutableListOf<Manga_sync>()
|
val toUpdate = mutableListOf<Manga_sync>()
|
||||||
val toInsert = mutableListOf<Track>()
|
val toInsert = mutableListOf<Track>()
|
||||||
@ -499,6 +521,144 @@ class BackupManager(context: Context) : AbstractBackupManager(context) {
|
|||||||
newChapters[false]?.let { insertChapters(it) }
|
newChapters[false]?.let { insertChapters(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns manga
|
||||||
|
*
|
||||||
|
* @return [Manga], null if not found
|
||||||
|
*/
|
||||||
|
internal suspend fun getMangaFromDatabase(url: String, source: Long): Mangas? {
|
||||||
|
return handler.awaitOneOrNull { mangasQueries.getMangaByUrlAndSource(url, source) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts manga and returns id
|
||||||
|
*
|
||||||
|
* @return id of [Manga], null if not found
|
||||||
|
*/
|
||||||
|
private suspend fun insertManga(manga: Manga): Long {
|
||||||
|
return handler.awaitOne(true) {
|
||||||
|
mangasQueries.insert(
|
||||||
|
source = manga.source,
|
||||||
|
url = manga.url,
|
||||||
|
artist = manga.artist,
|
||||||
|
author = manga.author,
|
||||||
|
description = manga.description,
|
||||||
|
genre = manga.getGenres(),
|
||||||
|
title = manga.title,
|
||||||
|
status = manga.status.toLong(),
|
||||||
|
thumbnailUrl = manga.thumbnail_url,
|
||||||
|
favorite = manga.favorite,
|
||||||
|
lastUpdate = manga.last_update,
|
||||||
|
nextUpdate = 0L,
|
||||||
|
initialized = manga.initialized,
|
||||||
|
viewerFlags = manga.viewer_flags.toLong(),
|
||||||
|
chapterFlags = manga.chapter_flags.toLong(),
|
||||||
|
coverLastModified = manga.cover_last_modified,
|
||||||
|
dateAdded = manga.date_added,
|
||||||
|
)
|
||||||
|
mangasQueries.selectLastInsertedRowId()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun updateManga(manga: Manga): Long {
|
||||||
|
handler.await(true) {
|
||||||
|
mangasQueries.update(
|
||||||
|
source = manga.source,
|
||||||
|
url = manga.url,
|
||||||
|
artist = manga.artist,
|
||||||
|
author = manga.author,
|
||||||
|
description = manga.description,
|
||||||
|
genre = manga.genre,
|
||||||
|
title = manga.title,
|
||||||
|
status = manga.status.toLong(),
|
||||||
|
thumbnailUrl = manga.thumbnail_url,
|
||||||
|
favorite = manga.favorite.toLong(),
|
||||||
|
lastUpdate = manga.last_update,
|
||||||
|
initialized = manga.initialized.toLong(),
|
||||||
|
viewer = manga.viewer_flags.toLong(),
|
||||||
|
chapterFlags = manga.chapter_flags.toLong(),
|
||||||
|
coverLastModified = manga.cover_last_modified,
|
||||||
|
dateAdded = manga.date_added,
|
||||||
|
mangaId = manga.id!!,
|
||||||
|
// SY -->
|
||||||
|
filteredScanlators = manga.filtered_scanlators,
|
||||||
|
// SY <--
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return manga.id!!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts list of chapters
|
||||||
|
*/
|
||||||
|
private suspend fun insertChapters(chapters: List<Chapter>) {
|
||||||
|
handler.await(true) {
|
||||||
|
chapters.forEach { chapter ->
|
||||||
|
chaptersQueries.insert(
|
||||||
|
chapter.manga_id!!,
|
||||||
|
chapter.url,
|
||||||
|
chapter.name,
|
||||||
|
chapter.scanlator,
|
||||||
|
chapter.read,
|
||||||
|
chapter.bookmark,
|
||||||
|
chapter.last_page_read.toLong(),
|
||||||
|
chapter.chapter_number,
|
||||||
|
chapter.source_order.toLong(),
|
||||||
|
chapter.date_fetch,
|
||||||
|
chapter.date_upload,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a list of chapters
|
||||||
|
*/
|
||||||
|
private suspend fun updateChapters(chapters: List<Chapter>) {
|
||||||
|
handler.await(true) {
|
||||||
|
chapters.forEach { chapter ->
|
||||||
|
chaptersQueries.update(
|
||||||
|
chapter.manga_id!!,
|
||||||
|
chapter.url,
|
||||||
|
chapter.name,
|
||||||
|
chapter.scanlator,
|
||||||
|
chapter.read.toLong(),
|
||||||
|
chapter.bookmark.toLong(),
|
||||||
|
chapter.last_page_read.toLong(),
|
||||||
|
chapter.chapter_number.toDouble(),
|
||||||
|
chapter.source_order.toLong(),
|
||||||
|
chapter.date_fetch,
|
||||||
|
chapter.date_upload,
|
||||||
|
chapter.id!!,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a list of chapters with known database ids
|
||||||
|
*/
|
||||||
|
private suspend fun updateKnownChapters(chapters: List<Chapter>) {
|
||||||
|
handler.await(true) {
|
||||||
|
chapters.forEach { chapter ->
|
||||||
|
chaptersQueries.update(
|
||||||
|
mangaId = null,
|
||||||
|
url = null,
|
||||||
|
name = null,
|
||||||
|
scanlator = null,
|
||||||
|
read = chapter.read.toLong(),
|
||||||
|
bookmark = chapter.bookmark.toLong(),
|
||||||
|
lastPageRead = chapter.last_page_read.toLong(),
|
||||||
|
chapterNumber = null,
|
||||||
|
sourceOrder = null,
|
||||||
|
dateFetch = null,
|
||||||
|
dateUpload = null,
|
||||||
|
chapterId = chapter.id!!,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
internal suspend fun restoreSavedSearches(backupSavedSearches: List<BackupSavedSearch>) {
|
internal suspend fun restoreSavedSearches(backupSavedSearches: List<BackupSavedSearch>) {
|
||||||
val currentSavedSearches = handler.awaitList {
|
val currentSavedSearches = handler.awaitList {
|
||||||
@ -560,9 +720,14 @@ class BackupManager(context: Context) : AbstractBackupManager(context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal suspend fun restoreFlatMetadata(mangaId: Long, backupFlatMetadata: BackupFlatMetadata) {
|
internal suspend fun restoreFlatMetadata(mangaId: Long, backupFlatMetadata: BackupFlatMetadata) {
|
||||||
if (getFlatMetadata(mangaId) == null) {
|
if (getFlatMetadataById.await(mangaId) == null) {
|
||||||
insertFlatMetadata(backupFlatMetadata.getFlatMetadata(mangaId))
|
insertFlatMetadata.await(backupFlatMetadata.getFlatMetadata(mangaId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun restoreEditedInfo(mangaJson: CustomMangaManager.MangaJson?) {
|
||||||
|
mangaJson ?: return
|
||||||
|
customMangaManager.saveMangaInfo(mangaJson)
|
||||||
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ class BackupRestoreService : Service() {
|
|||||||
private lateinit var wakeLock: PowerManager.WakeLock
|
private lateinit var wakeLock: PowerManager.WakeLock
|
||||||
|
|
||||||
private lateinit var ioScope: CoroutineScope
|
private lateinit var ioScope: CoroutineScope
|
||||||
private var restorer: AbstractBackupRestore<*>? = null
|
private var restorer: BackupRestorer? = null
|
||||||
private lateinit var notifier: BackupNotifier
|
private lateinit var notifier: BackupNotifier
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
|
@ -15,19 +15,76 @@ import eu.kanade.tachiyomi.data.database.models.Chapter
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
||||||
|
import eu.kanade.tachiyomi.util.system.createFileInCacheDir
|
||||||
import exh.EXHMigrations
|
import exh.EXHMigrations
|
||||||
import exh.source.MERGED_SOURCE_ID
|
import exh.source.MERGED_SOURCE_ID
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import okio.buffer
|
import okio.buffer
|
||||||
import okio.gzip
|
import okio.gzip
|
||||||
import okio.source
|
import okio.source
|
||||||
|
import java.io.File
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
class BackupRestorer(context: Context, notifier: BackupNotifier) : AbstractBackupRestore<BackupManager>(context, notifier) {
|
class BackupRestorer(
|
||||||
|
private val context: Context,
|
||||||
|
private val notifier: BackupNotifier,
|
||||||
|
) {
|
||||||
|
|
||||||
|
var job: Job? = null
|
||||||
|
|
||||||
|
private var backupManager = BackupManager(context)
|
||||||
|
|
||||||
|
private var restoreAmount = 0
|
||||||
|
private var restoreProgress = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapping of source ID to source name from backup data
|
||||||
|
*/
|
||||||
|
private var sourceMapping: Map<Long, String> = emptyMap()
|
||||||
|
|
||||||
|
private val errors = mutableListOf<Pair<Date, String>>()
|
||||||
|
|
||||||
|
suspend fun restoreBackup(uri: Uri): Boolean {
|
||||||
|
val startTime = System.currentTimeMillis()
|
||||||
|
restoreProgress = 0
|
||||||
|
errors.clear()
|
||||||
|
|
||||||
|
if (!performRestore(uri)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val endTime = System.currentTimeMillis()
|
||||||
|
val time = endTime - startTime
|
||||||
|
|
||||||
|
val logFile = writeErrorLog()
|
||||||
|
|
||||||
|
notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun writeErrorLog(): File {
|
||||||
|
try {
|
||||||
|
if (errors.isNotEmpty()) {
|
||||||
|
val file = context.createFileInCacheDir("tachiyomi_restore.txt")
|
||||||
|
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault())
|
||||||
|
|
||||||
|
file.bufferedWriter().use { out ->
|
||||||
|
errors.forEach { (date, message) ->
|
||||||
|
out.write("[${sdf.format(date)}] $message\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// Empty
|
||||||
|
}
|
||||||
|
return File("")
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
override suspend fun performRestore(uri: Uri): Boolean {
|
private suspend fun performRestore(uri: Uri): Boolean {
|
||||||
backupManager = BackupManager(context)
|
|
||||||
|
|
||||||
val backupString = context.contentResolver.openInputStream(uri)!!.source().gzip().buffer().use { it.readByteArray() }
|
val backupString = context.contentResolver.openInputStream(uri)!!.source().gzip().buffer().use { it.readByteArray() }
|
||||||
val backup = backupManager.parser.decodeFromByteArray(BackupSerializer, backupString)
|
val backup = backupManager.parser.decodeFromByteArray(BackupSerializer, backupString)
|
||||||
|
|
||||||
@ -179,7 +236,18 @@ class BackupRestorer(context: Context, notifier: BackupNotifier) : AbstractBacku
|
|||||||
backupManager.restoreMergedMangaReferencesForManga(manga.id!!, mergedMangaReferences)
|
backupManager.restoreMergedMangaReferencesForManga(manga.id!!, mergedMangaReferences)
|
||||||
flatMetadata?.let { backupManager.restoreFlatMetadata(manga.id!!, it) }
|
flatMetadata?.let { backupManager.restoreFlatMetadata(manga.id!!, it) }
|
||||||
customManga?.id = manga.id!!
|
customManga?.id = manga.id!!
|
||||||
customManga?.let { customMangaManager.saveMangaInfo(it) }
|
backupManager.restoreEditedInfo(customManga)
|
||||||
// SY <--
|
// SY <--
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to update dialog in [BackupConst]
|
||||||
|
*
|
||||||
|
* @param progress restore progress
|
||||||
|
* @param amount total restoreAmount of manga
|
||||||
|
* @param title title of restored manga
|
||||||
|
*/
|
||||||
|
private fun showRestoreProgress(progress: Int, amount: Int, title: String) {
|
||||||
|
notifier.showRestoreProgress(title, progress, amount)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ open class BrowseSourcePresenter(
|
|||||||
private val savedSearch: Long? = null,
|
private val savedSearch: Long? = null,
|
||||||
// SY <--
|
// SY <--
|
||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val sourceManager: SourceManager = Injekt.get(),
|
||||||
private val prefs: PreferencesHelper = Injekt.get(),
|
private val preferences: PreferencesHelper = Injekt.get(),
|
||||||
private val coverCache: CoverCache = Injekt.get(),
|
private val coverCache: CoverCache = Injekt.get(),
|
||||||
private val getManga: GetManga = Injekt.get(),
|
private val getManga: GetManga = Injekt.get(),
|
||||||
private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(),
|
private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(),
|
||||||
@ -208,7 +208,7 @@ open class BrowseSourcePresenter(
|
|||||||
pager = createPager(query, filters)
|
pager = createPager(query, filters)
|
||||||
|
|
||||||
val sourceId = source.id
|
val sourceId = source.id
|
||||||
val sourceDisplayMode = prefs.sourceDisplayMode()
|
val sourceDisplayMode = preferences.sourceDisplayMode()
|
||||||
|
|
||||||
pagerJob?.cancel()
|
pagerJob?.cancel()
|
||||||
pagerJob = presenterScope.launchIO {
|
pagerJob = presenterScope.launchIO {
|
||||||
|
@ -18,15 +18,15 @@ import uy.kohesive.injekt.api.get
|
|||||||
|
|
||||||
class MorePresenter(
|
class MorePresenter(
|
||||||
private val downloadManager: DownloadManager = Injekt.get(),
|
private val downloadManager: DownloadManager = Injekt.get(),
|
||||||
preferencesHelper: PreferencesHelper = Injekt.get(),
|
preferences: PreferencesHelper = Injekt.get(),
|
||||||
) : BasePresenter<MoreController>() {
|
) : BasePresenter<MoreController>() {
|
||||||
|
|
||||||
val downloadedOnly = preferencesHelper.downloadedOnly().asState()
|
val downloadedOnly = preferences.downloadedOnly().asState()
|
||||||
val incognitoMode = preferencesHelper.incognitoMode().asState()
|
val incognitoMode = preferences.incognitoMode().asState()
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
val showNavUpdates = preferencesHelper.showNavUpdates().asState()
|
val showNavUpdates = preferences.showNavUpdates().asState()
|
||||||
val showNavHistory = preferencesHelper.showNavHistory().asState()
|
val showNavHistory = preferences.showNavHistory().asState()
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
private var _state: MutableStateFlow<DownloadQueueState> = MutableStateFlow(DownloadQueueState.Stopped)
|
private var _state: MutableStateFlow<DownloadQueueState> = MutableStateFlow(DownloadQueueState.Stopped)
|
||||||
|
@ -50,17 +50,17 @@ fun Manga.removeCovers(coverCache: CoverCache = Injekt.get()): Int {
|
|||||||
return coverCache.deleteFromCache(this, true)
|
return coverCache.deleteFromCache(this, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun DomainManga.shouldDownloadNewChapters(dbCategories: List<Long>, prefs: PreferencesHelper): Boolean {
|
fun DomainManga.shouldDownloadNewChapters(dbCategories: List<Long>, preferences: PreferencesHelper): Boolean {
|
||||||
if (!favorite) return false
|
if (!favorite) return false
|
||||||
|
|
||||||
val categories = dbCategories.ifEmpty { listOf(0L) }
|
val categories = dbCategories.ifEmpty { listOf(0L) }
|
||||||
|
|
||||||
// Boolean to determine if user wants to automatically download new chapters.
|
// Boolean to determine if user wants to automatically download new chapters.
|
||||||
val downloadNewChapter = prefs.downloadNewChapter().get()
|
val downloadNewChapter = preferences.downloadNewChapter().get()
|
||||||
if (!downloadNewChapter) return false
|
if (!downloadNewChapter) return false
|
||||||
|
|
||||||
val includedCategories = prefs.downloadNewChapterCategories().get().map { it.toLong() }
|
val includedCategories = preferences.downloadNewChapterCategories().get().map { it.toLong() }
|
||||||
val excludedCategories = prefs.downloadNewChapterCategoriesExclude().get().map { it.toLong() }
|
val excludedCategories = preferences.downloadNewChapterCategoriesExclude().get().map { it.toLong() }
|
||||||
|
|
||||||
// Default: Download from all categories
|
// Default: Download from all categories
|
||||||
if (includedCategories.isEmpty() && excludedCategories.isEmpty()) return true
|
if (includedCategories.isEmpty() && excludedCategories.isEmpty()) return true
|
||||||
|
@ -10,7 +10,7 @@ import uy.kohesive.injekt.injectLazy
|
|||||||
|
|
||||||
object ChapterSettingsHelper {
|
object ChapterSettingsHelper {
|
||||||
|
|
||||||
private val prefs: PreferencesHelper by injectLazy()
|
private val preferences: PreferencesHelper by injectLazy()
|
||||||
private val getFavorites: GetFavorites by injectLazy()
|
private val getFavorites: GetFavorites by injectLazy()
|
||||||
private val setMangaChapterFlags: SetMangaChapterFlags by injectLazy()
|
private val setMangaChapterFlags: SetMangaChapterFlags by injectLazy()
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ object ChapterSettingsHelper {
|
|||||||
* Updates the global Chapter Settings in Preferences.
|
* Updates the global Chapter Settings in Preferences.
|
||||||
*/
|
*/
|
||||||
fun setGlobalSettings(manga: Manga) {
|
fun setGlobalSettings(manga: Manga) {
|
||||||
prefs.setChapterSettingsDefault(manga.toDbManga())
|
preferences.setChapterSettingsDefault(manga.toDbManga())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,12 +28,12 @@ object ChapterSettingsHelper {
|
|||||||
launchIO {
|
launchIO {
|
||||||
setMangaChapterFlags.awaitSetAllFlags(
|
setMangaChapterFlags.awaitSetAllFlags(
|
||||||
mangaId = manga.id,
|
mangaId = manga.id,
|
||||||
unreadFilter = prefs.filterChapterByRead().toLong(),
|
unreadFilter = preferences.filterChapterByRead().toLong(),
|
||||||
downloadedFilter = prefs.filterChapterByDownloaded().toLong(),
|
downloadedFilter = preferences.filterChapterByDownloaded().toLong(),
|
||||||
bookmarkedFilter = prefs.filterChapterByBookmarked().toLong(),
|
bookmarkedFilter = preferences.filterChapterByBookmarked().toLong(),
|
||||||
sortingMode = prefs.sortChapterBySourceOrNumber().toLong(),
|
sortingMode = preferences.sortChapterBySourceOrNumber().toLong(),
|
||||||
sortingDirection = prefs.sortChapterByAscendingOrDescending().toLong(),
|
sortingDirection = preferences.sortChapterByAscendingOrDescending().toLong(),
|
||||||
displayMode = prefs.displayChapterByNameOrNumber().toLong(),
|
displayMode = preferences.displayChapterByNameOrNumber().toLong(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,12 +41,12 @@ object ChapterSettingsHelper {
|
|||||||
suspend fun applySettingDefaults(mangaId: Long) {
|
suspend fun applySettingDefaults(mangaId: Long) {
|
||||||
setMangaChapterFlags.awaitSetAllFlags(
|
setMangaChapterFlags.awaitSetAllFlags(
|
||||||
mangaId = mangaId,
|
mangaId = mangaId,
|
||||||
unreadFilter = prefs.filterChapterByRead().toLong(),
|
unreadFilter = preferences.filterChapterByRead().toLong(),
|
||||||
downloadedFilter = prefs.filterChapterByDownloaded().toLong(),
|
downloadedFilter = preferences.filterChapterByDownloaded().toLong(),
|
||||||
bookmarkedFilter = prefs.filterChapterByBookmarked().toLong(),
|
bookmarkedFilter = preferences.filterChapterByBookmarked().toLong(),
|
||||||
sortingMode = prefs.sortChapterBySourceOrNumber().toLong(),
|
sortingMode = preferences.sortChapterBySourceOrNumber().toLong(),
|
||||||
sortingDirection = prefs.sortChapterByAscendingOrDescending().toLong(),
|
sortingDirection = preferences.sortChapterByAscendingOrDescending().toLong(),
|
||||||
displayMode = prefs.displayChapterByNameOrNumber().toLong(),
|
displayMode = preferences.displayChapterByNameOrNumber().toLong(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,12 +59,12 @@ object ChapterSettingsHelper {
|
|||||||
.map { manga ->
|
.map { manga ->
|
||||||
setMangaChapterFlags.awaitSetAllFlags(
|
setMangaChapterFlags.awaitSetAllFlags(
|
||||||
mangaId = manga.id,
|
mangaId = manga.id,
|
||||||
unreadFilter = prefs.filterChapterByRead().toLong(),
|
unreadFilter = preferences.filterChapterByRead().toLong(),
|
||||||
downloadedFilter = prefs.filterChapterByDownloaded().toLong(),
|
downloadedFilter = preferences.filterChapterByDownloaded().toLong(),
|
||||||
bookmarkedFilter = prefs.filterChapterByBookmarked().toLong(),
|
bookmarkedFilter = preferences.filterChapterByBookmarked().toLong(),
|
||||||
sortingMode = prefs.sortChapterBySourceOrNumber().toLong(),
|
sortingMode = preferences.sortChapterBySourceOrNumber().toLong(),
|
||||||
sortingDirection = prefs.sortChapterByAscendingOrDescending().toLong(),
|
sortingDirection = preferences.sortChapterByAscendingOrDescending().toLong(),
|
||||||
displayMode = prefs.displayChapterByNameOrNumber().toLong(),
|
displayMode = preferences.displayChapterByNameOrNumber().toLong(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -319,8 +319,8 @@ fun Context.isNightMode(): Boolean {
|
|||||||
* https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java;l=348;drc=e28752c96fc3fb4d3354781469a1af3dbded4898
|
* https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java;l=348;drc=e28752c96fc3fb4d3354781469a1af3dbded4898
|
||||||
*/
|
*/
|
||||||
fun Context.createReaderThemeContext(): Context {
|
fun Context.createReaderThemeContext(): Context {
|
||||||
val prefs = Injekt.get<PreferencesHelper>()
|
val preferences = Injekt.get<PreferencesHelper>()
|
||||||
val isDarkBackground = when (prefs.readerTheme().get()) {
|
val isDarkBackground = when (preferences.readerTheme().get()) {
|
||||||
1, 2 -> true // Black, Gray
|
1, 2 -> true // Black, Gray
|
||||||
3 -> applicationContext.isNightMode() // Automatic bg uses activity background by default
|
3 -> applicationContext.isNightMode() // Automatic bg uses activity background by default
|
||||||
else -> false // White
|
else -> false // White
|
||||||
@ -333,7 +333,7 @@ fun Context.createReaderThemeContext(): Context {
|
|||||||
|
|
||||||
val wrappedContext = ContextThemeWrapper(this, R.style.Theme_Tachiyomi)
|
val wrappedContext = ContextThemeWrapper(this, R.style.Theme_Tachiyomi)
|
||||||
wrappedContext.applyOverrideConfiguration(overrideConf)
|
wrappedContext.applyOverrideConfiguration(overrideConf)
|
||||||
ThemingDelegate.getThemeResIds(prefs.appTheme().get(), prefs.themeDarkAmoled().get())
|
ThemingDelegate.getThemeResIds(preferences.appTheme().get(), preferences.themeDarkAmoled().get())
|
||||||
.forEach { wrappedContext.theme.applyStyle(it, true) }
|
.forEach { wrappedContext.theme.applyStyle(it, true) }
|
||||||
return wrappedContext
|
return wrappedContext
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user