Backup and restore bookmarks
This commit is contained in:
@@ -5,6 +5,7 @@ import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.Upsert
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaWithTags
|
||||
|
||||
@@ -14,6 +15,12 @@ abstract class BookmarksDao {
|
||||
@Query("SELECT * FROM bookmarks WHERE manga_id = :mangaId AND page_id = :pageId")
|
||||
abstract suspend fun find(mangaId: Long, pageId: Long): BookmarkEntity?
|
||||
|
||||
@Transaction
|
||||
@Query(
|
||||
"SELECT * FROM manga JOIN bookmarks ON bookmarks.manga_id = manga.manga_id ORDER BY bookmarks.created_at",
|
||||
)
|
||||
abstract suspend fun findAll(): Map<MangaWithTags, List<BookmarkEntity>>
|
||||
|
||||
@Query("SELECT * FROM bookmarks WHERE manga_id = :mangaId AND chapter_id = :chapterId AND page = :page")
|
||||
abstract fun observe(mangaId: Long, chapterId: Long, page: Int): Flow<BookmarkEntity?>
|
||||
|
||||
@@ -37,4 +44,7 @@ abstract class BookmarksDao {
|
||||
|
||||
@Query("DELETE FROM bookmarks WHERE manga_id = :mangaId AND chapter_id = :chapterId AND page = :page")
|
||||
abstract suspend fun delete(mangaId: Long, chapterId: Long, page: Int): Int
|
||||
|
||||
@Upsert
|
||||
abstract suspend fun upsert(bookmarks: Collection<BookmarkEntity>)
|
||||
}
|
||||
|
||||
@@ -14,5 +14,6 @@ class BackupEntry(
|
||||
const val CATEGORIES = "categories"
|
||||
const val FAVOURITES = "favourites"
|
||||
const val SETTINGS = "settings"
|
||||
const val BOOKMARKS = "bookmarks"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,24 @@ class BackupRepository @Inject constructor(
|
||||
return entry
|
||||
}
|
||||
|
||||
suspend fun dumpBookmarks(): BackupEntry {
|
||||
val entry = BackupEntry(BackupEntry.BOOKMARKS, JSONArray())
|
||||
val all = db.bookmarksDao.findAll()
|
||||
for ((m, b) in all) {
|
||||
val json = JSONObject()
|
||||
val manga = JsonSerializer(m.manga).toJson()
|
||||
json.put("manga", manga)
|
||||
val tags = JSONArray()
|
||||
m.tags.forEach { tags.put(JsonSerializer(it).toJson()) }
|
||||
json.put("tags", tags)
|
||||
val bookmarks = JSONArray()
|
||||
b.forEach { bookmarks.put(JsonSerializer(it).toJson()) }
|
||||
json.put("bookmarks", bookmarks)
|
||||
entry.data.put(json)
|
||||
}
|
||||
return entry
|
||||
}
|
||||
|
||||
fun dumpSettings(): BackupEntry {
|
||||
val entry = BackupEntry(BackupEntry.SETTINGS, JSONArray())
|
||||
val settingsDump = settings.getAllValues().toMutableMap()
|
||||
@@ -144,6 +162,28 @@ class BackupRepository @Inject constructor(
|
||||
return result
|
||||
}
|
||||
|
||||
suspend fun restoreBookmarks(entry: BackupEntry): CompositeResult {
|
||||
val result = CompositeResult()
|
||||
for (item in entry.data.JSONIterator()) {
|
||||
val mangaJson = item.getJSONObject("manga")
|
||||
val manga = JsonDeserializer(mangaJson).toMangaEntity()
|
||||
val tags = item.getJSONArray("tags").mapJSON {
|
||||
JsonDeserializer(it).toTagEntity()
|
||||
}
|
||||
val bookmarks = item.getJSONArray("bookmarks").mapJSON {
|
||||
JsonDeserializer(it).toBookmarkEntity()
|
||||
}
|
||||
result += runCatchingCancellable {
|
||||
db.withTransaction {
|
||||
db.tagsDao.upsert(tags)
|
||||
db.mangaDao.upsert(manga, tags)
|
||||
db.bookmarksDao.upsert(bookmarks)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun restoreSettings(entry: BackupEntry): CompositeResult {
|
||||
val result = CompositeResult()
|
||||
for (item in entry.data.JSONIterator()) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.core.backup
|
||||
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.bookmarks.data.BookmarkEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.TagEntity
|
||||
import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity
|
||||
@@ -67,6 +68,17 @@ class JsonDeserializer(private val json: JSONObject) {
|
||||
deletedAt = 0L,
|
||||
)
|
||||
|
||||
fun toBookmarkEntity() = BookmarkEntity(
|
||||
mangaId = json.getLong("manga_id"),
|
||||
pageId = json.getLong("page_id"),
|
||||
chapterId = json.getLong("chapter_id"),
|
||||
page = json.getInt("page"),
|
||||
scroll = json.getInt("scroll"),
|
||||
imageUrl = json.getString("image_url"),
|
||||
createdAt = json.getLong("created_at"),
|
||||
percent = json.getDouble("percent").toFloat(),
|
||||
)
|
||||
|
||||
fun toMap(): Map<String, Any?> {
|
||||
val map = mutableMapOf<String, Any?>()
|
||||
val keys = json.keys()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.koitharu.kotatsu.core.backup
|
||||
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.bookmarks.data.BookmarkEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.TagEntity
|
||||
import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity
|
||||
@@ -68,6 +69,19 @@ class JsonSerializer private constructor(private val json: JSONObject) {
|
||||
},
|
||||
)
|
||||
|
||||
constructor(e: BookmarkEntity) : this(
|
||||
JSONObject().apply {
|
||||
put("manga_id", e.mangaId)
|
||||
put("page_id", e.pageId)
|
||||
put("chapter_id", e.chapterId)
|
||||
put("page", e.page)
|
||||
put("scroll", e.scroll)
|
||||
put("image_url", e.imageUrl)
|
||||
put("created_at", e.createdAt)
|
||||
put("percent", e.percent)
|
||||
},
|
||||
)
|
||||
|
||||
constructor(m: Map<String, *>) : this(
|
||||
JSONObject(m),
|
||||
)
|
||||
|
||||
@@ -68,6 +68,7 @@ class AppBackupAgent : BackupAgent() {
|
||||
backup.put(repository.dumpHistory())
|
||||
backup.put(repository.dumpCategories())
|
||||
backup.put(repository.dumpFavourites())
|
||||
backup.put(repository.dumpBookmarks())
|
||||
backup.put(repository.dumpSettings())
|
||||
backup.finish()
|
||||
backup.file
|
||||
@@ -88,6 +89,7 @@ class AppBackupAgent : BackupAgent() {
|
||||
backup.getEntry(BackupEntry.HISTORY)?.let { repository.restoreHistory(it) }
|
||||
backup.getEntry(BackupEntry.CATEGORIES)?.let { repository.restoreCategories(it) }
|
||||
backup.getEntry(BackupEntry.FAVOURITES)?.let { repository.restoreFavourites(it) }
|
||||
backup.getEntry(BackupEntry.BOOKMARKS)?.let { repository.restoreBookmarks(it) }
|
||||
backup.getEntry(BackupEntry.SETTINGS)?.let { repository.restoreSettings(it) }
|
||||
}
|
||||
} finally {
|
||||
|
||||
@@ -29,13 +29,16 @@ class BackupViewModel @Inject constructor(
|
||||
progress.value = 0f
|
||||
backup.put(repository.dumpHistory())
|
||||
|
||||
progress.value = 0.25f
|
||||
progress.value = 0.2f
|
||||
backup.put(repository.dumpCategories())
|
||||
|
||||
progress.value = 0.5f
|
||||
progress.value = 0.4f
|
||||
backup.put(repository.dumpFavourites())
|
||||
|
||||
progress.value = 0.75f
|
||||
progress.value = 0.6f
|
||||
backup.put(repository.dumpBookmarks())
|
||||
|
||||
progress.value = 0.8f
|
||||
backup.put(repository.dumpSettings())
|
||||
|
||||
backup.finish()
|
||||
|
||||
@@ -22,7 +22,6 @@ import kotlin.math.roundToInt
|
||||
@AndroidEntryPoint
|
||||
class RestoreDialogFragment : AlertDialogFragment<DialogProgressBinding>() {
|
||||
|
||||
|
||||
private val viewModel: RestoreViewModel by viewModels()
|
||||
|
||||
override fun onCreateViewBinding(
|
||||
|
||||
@@ -52,17 +52,22 @@ class RestoreViewModel @Inject constructor(
|
||||
result += repository.restoreHistory(it)
|
||||
}
|
||||
|
||||
progress.value = 0.25f
|
||||
progress.value = 0.2f
|
||||
backup.getEntry(BackupEntry.CATEGORIES)?.let {
|
||||
result += repository.restoreCategories(it)
|
||||
}
|
||||
|
||||
progress.value = 0.5f
|
||||
progress.value = 0.4f
|
||||
backup.getEntry(BackupEntry.FAVOURITES)?.let {
|
||||
result += repository.restoreFavourites(it)
|
||||
}
|
||||
|
||||
progress.value = 0.75f
|
||||
progress.value = 0.6f
|
||||
backup.getEntry(BackupEntry.BOOKMARKS)?.let {
|
||||
result += repository.restoreBookmarks(it)
|
||||
}
|
||||
|
||||
progress.value = 0.8f
|
||||
backup.getEntry(BackupEntry.SETTINGS)?.let {
|
||||
result += repository.restoreSettings(it)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user