diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/data/BookmarksDao.kt b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/data/BookmarksDao.kt index 0f7533857..db688a984 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/data/BookmarksDao.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/data/BookmarksDao.kt @@ -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> + @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 @@ -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) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupEntry.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupEntry.kt index dfcaaa9af..7498608c2 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupEntry.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupEntry.kt @@ -14,5 +14,6 @@ class BackupEntry( const val CATEGORIES = "categories" const val FAVOURITES = "favourites" const val SETTINGS = "settings" + const val BOOKMARKS = "bookmarks" } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupRepository.kt index fa4893319..231866047 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupRepository.kt @@ -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()) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/JsonDeserializer.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/JsonDeserializer.kt index c97882cd9..78619a0a6 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/JsonDeserializer.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/JsonDeserializer.kt @@ -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 { val map = mutableMapOf() val keys = json.keys() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/JsonSerializer.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/JsonSerializer.kt index 7793bb195..34a406a3b 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/JsonSerializer.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/JsonSerializer.kt @@ -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) : this( JSONObject(m), ) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/AppBackupAgent.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/AppBackupAgent.kt index 5214f5b57..3822f0da3 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/AppBackupAgent.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/AppBackupAgent.kt @@ -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 { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupViewModel.kt index 598cc838b..2a0db9416 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/BackupViewModel.kt @@ -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() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt index 441505328..903b1ad30 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt @@ -22,7 +22,6 @@ import kotlin.math.roundToInt @AndroidEntryPoint class RestoreDialogFragment : AlertDialogFragment() { - private val viewModel: RestoreViewModel by viewModels() override fun onCreateViewBinding( diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreViewModel.kt index 13496cc4b..fa0b1279b 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreViewModel.kt @@ -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) }