Save reading percent to database
This commit is contained in:
@@ -25,4 +25,5 @@ class BookmarkEntity(
|
||||
@ColumnInfo(name = "scroll") val scroll: Int,
|
||||
@ColumnInfo(name = "image") val imageUrl: String,
|
||||
@ColumnInfo(name = "created_at") val createdAt: Long,
|
||||
@ColumnInfo(name = "percent") val percent: Float,
|
||||
)
|
||||
@@ -18,6 +18,7 @@ fun BookmarkEntity.toBookmark(manga: Manga) = Bookmark(
|
||||
scroll = scroll,
|
||||
imageUrl = imageUrl,
|
||||
createdAt = Date(createdAt),
|
||||
percent = percent,
|
||||
)
|
||||
|
||||
fun Bookmark.toEntity() = BookmarkEntity(
|
||||
@@ -28,4 +29,5 @@ fun Bookmark.toEntity() = BookmarkEntity(
|
||||
scroll = scroll,
|
||||
imageUrl = imageUrl,
|
||||
createdAt = createdAt.time,
|
||||
percent = percent,
|
||||
)
|
||||
@@ -11,6 +11,7 @@ class Bookmark(
|
||||
val scroll: Int,
|
||||
val imageUrl: String,
|
||||
val createdAt: Date,
|
||||
val percent: Float,
|
||||
) {
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
@@ -26,6 +27,7 @@ class Bookmark(
|
||||
if (scroll != other.scroll) return false
|
||||
if (imageUrl != other.imageUrl) return false
|
||||
if (createdAt != other.createdAt) return false
|
||||
if (percent != other.percent) return false
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -38,6 +40,7 @@ class Bookmark(
|
||||
result = 31 * result + scroll
|
||||
result = 31 * result + imageUrl.hashCode()
|
||||
result = 31 * result + createdAt.hashCode()
|
||||
result = 31 * result + percent.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -111,6 +111,7 @@ class BackupRepository(private val db: MangaDatabase) {
|
||||
jo.put("chapter_id", chapterId)
|
||||
jo.put("page", page)
|
||||
jo.put("scroll", scroll)
|
||||
jo.put("percent", percent)
|
||||
return jo
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,7 @@ import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity
|
||||
import org.koitharu.kotatsu.favourites.data.FavouriteEntity
|
||||
import org.koitharu.kotatsu.history.data.HistoryEntity
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import org.koitharu.kotatsu.parsers.util.json.JSONIterator
|
||||
import org.koitharu.kotatsu.parsers.util.json.getBooleanOrDefault
|
||||
import org.koitharu.kotatsu.parsers.util.json.getStringOrNull
|
||||
import org.koitharu.kotatsu.parsers.util.json.mapJSON
|
||||
import org.koitharu.kotatsu.parsers.util.json.*
|
||||
|
||||
class RestoreRepository(private val db: MangaDatabase) {
|
||||
|
||||
@@ -95,7 +92,8 @@ class RestoreRepository(private val db: MangaDatabase) {
|
||||
updatedAt = json.getLong("updated_at"),
|
||||
chapterId = json.getLong("chapter_id"),
|
||||
page = json.getInt("page"),
|
||||
scroll = json.getDouble("scroll").toFloat()
|
||||
scroll = json.getDouble("scroll").toFloat(),
|
||||
percent = json.getFloatOrDefault("percent", -1f),
|
||||
)
|
||||
|
||||
private fun parseCategory(json: JSONObject) = FavouriteCategoryEntity(
|
||||
|
||||
@@ -6,8 +6,14 @@ import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import org.koitharu.kotatsu.bookmarks.data.BookmarkEntity
|
||||
import org.koitharu.kotatsu.bookmarks.data.BookmarksDao
|
||||
import org.koitharu.kotatsu.core.db.dao.*
|
||||
import org.koitharu.kotatsu.core.db.entity.*
|
||||
import org.koitharu.kotatsu.core.db.dao.MangaDao
|
||||
import org.koitharu.kotatsu.core.db.dao.PreferencesDao
|
||||
import org.koitharu.kotatsu.core.db.dao.TagsDao
|
||||
import org.koitharu.kotatsu.core.db.dao.TrackLogsDao
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaPrefsEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaTagsEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.TagEntity
|
||||
import org.koitharu.kotatsu.core.db.migrations.*
|
||||
import org.koitharu.kotatsu.favourites.data.FavouriteCategoriesDao
|
||||
import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity
|
||||
@@ -27,7 +33,7 @@ import org.koitharu.kotatsu.tracker.data.TracksDao
|
||||
FavouriteCategoryEntity::class, FavouriteEntity::class, MangaPrefsEntity::class,
|
||||
TrackEntity::class, TrackLogEntity::class, SuggestionEntity::class, BookmarkEntity::class,
|
||||
],
|
||||
version = 11,
|
||||
version = 12,
|
||||
)
|
||||
abstract class MangaDatabase : RoomDatabase() {
|
||||
|
||||
@@ -67,6 +73,7 @@ fun MangaDatabase(context: Context): MangaDatabase = Room.databaseBuilder(
|
||||
Migration8To9(),
|
||||
Migration9To10(),
|
||||
Migration10To11(),
|
||||
Migration11To12(),
|
||||
).addCallback(
|
||||
DatabasePrePopulateCallback(context.resources)
|
||||
).build()
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.koitharu.kotatsu.core.db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
class Migration11To12 : Migration(11, 12) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE history ADD COLUMN `percent` REAL NOT NULL DEFAULT -1")
|
||||
database.execSQL("ALTER TABLE bookmarks ADD COLUMN `percent` REAL NOT NULL DEFAULT -1")
|
||||
}
|
||||
}
|
||||
@@ -11,4 +11,5 @@ data class MangaHistory(
|
||||
val chapterId: Long,
|
||||
val page: Int,
|
||||
val scroll: Int,
|
||||
val percent: Float,
|
||||
) : Parcelable
|
||||
@@ -1,12 +1,13 @@
|
||||
package org.koitharu.kotatsu.history.data
|
||||
|
||||
import java.util.*
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
import java.util.*
|
||||
|
||||
fun HistoryEntity.toMangaHistory() = MangaHistory(
|
||||
createdAt = Date(createdAt),
|
||||
updatedAt = Date(updatedAt),
|
||||
chapterId = chapterId,
|
||||
page = page,
|
||||
scroll = scroll.toInt()
|
||||
scroll = scroll.toInt(),
|
||||
percent = percent,
|
||||
)
|
||||
@@ -13,16 +13,17 @@ import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||
entity = MangaEntity::class,
|
||||
parentColumns = ["manga_id"],
|
||||
childColumns = ["manga_id"],
|
||||
onDelete = ForeignKey.CASCADE
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
)
|
||||
]
|
||||
)
|
||||
class HistoryEntity(
|
||||
@PrimaryKey(autoGenerate = false)
|
||||
@ColumnInfo(name = "manga_id") val mangaId: Long,
|
||||
@ColumnInfo(name = "created_at") val createdAt: Long = System.currentTimeMillis(),
|
||||
@ColumnInfo(name = "created_at") val createdAt: Long,
|
||||
@ColumnInfo(name = "updated_at") val updatedAt: Long,
|
||||
@ColumnInfo(name = "chapter_id") val chapterId: Long,
|
||||
@ColumnInfo(name = "page") val page: Int,
|
||||
@ColumnInfo(name = "scroll") val scroll: Float,
|
||||
@ColumnInfo(name = "percent") val percent: Float,
|
||||
)
|
||||
@@ -59,7 +59,7 @@ class HistoryRepository(
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
suspend fun addOrUpdate(manga: Manga, chapterId: Long, page: Int, scroll: Int) {
|
||||
suspend fun addOrUpdate(manga: Manga, chapterId: Long, page: Int, scroll: Int, percent: Float) {
|
||||
if (manga.isNsfw && settings.isHistoryExcludeNsfw) {
|
||||
return
|
||||
}
|
||||
@@ -75,6 +75,7 @@ class HistoryRepository(
|
||||
chapterId = chapterId,
|
||||
page = page,
|
||||
scroll = scroll.toFloat(), // we migrate to int, but decide to not update database
|
||||
percent = percent,
|
||||
)
|
||||
)
|
||||
trackingRepository.syncWithHistory(manga, chapterId)
|
||||
|
||||
@@ -6,7 +6,6 @@ import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import java.util.*
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import org.koitharu.kotatsu.R
|
||||
@@ -32,6 +31,7 @@ import org.koitharu.kotatsu.utils.SingleLiveEvent
|
||||
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
||||
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
|
||||
import org.koitharu.kotatsu.utils.ext.processLifecycleScope
|
||||
import java.util.*
|
||||
|
||||
private const val BOUNDS_PAGE_OFFSET = 2
|
||||
private const val PAGES_TRIM_THRESHOLD = 120
|
||||
@@ -135,13 +135,16 @@ class ReaderViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO check performance
|
||||
fun saveCurrentState(state: ReaderState? = null) {
|
||||
if (state != null) {
|
||||
currentState.value = state
|
||||
}
|
||||
val readerState = state ?: currentState.value ?: return
|
||||
historyRepository.saveStateAsync(
|
||||
mangaData.value ?: return,
|
||||
state ?: currentState.value ?: return
|
||||
manga = mangaData.value ?: return,
|
||||
state = readerState,
|
||||
percent = computePercent(readerState.chapterId, readerState.page)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -223,7 +226,7 @@ class ReaderViewModel(
|
||||
if (bookmarkJob?.isActive == true) {
|
||||
return
|
||||
}
|
||||
bookmarkJob = launchJob {
|
||||
bookmarkJob = launchJob(Dispatchers.Default) {
|
||||
loadingJob?.join()
|
||||
val state = checkNotNull(currentState.value)
|
||||
val page = checkNotNull(getCurrentPage()) { "Page not found" }
|
||||
@@ -235,9 +238,10 @@ class ReaderViewModel(
|
||||
scroll = state.scroll,
|
||||
imageUrl = page.preview ?: pageLoader.getPageUrl(page),
|
||||
createdAt = Date(),
|
||||
percent = computePercent(state.chapterId, state.page),
|
||||
)
|
||||
bookmarksRepository.addBookmark(bookmark)
|
||||
onShowToast.call(R.string.bookmark_added)
|
||||
onShowToast.postCall(R.string.bookmark_added)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +283,8 @@ class ReaderViewModel(
|
||||
val pages = loadChapter(requireNotNull(currentState.value).chapterId)
|
||||
// save state
|
||||
currentState.value?.let {
|
||||
historyRepository.addOrUpdate(manga, it.chapterId, it.page, it.scroll)
|
||||
val percent = computePercent(it.chapterId, it.page)
|
||||
historyRepository.addOrUpdate(manga, it.chapterId, it.page, it.scroll, percent)
|
||||
shortcutsRepository.updateShortcuts()
|
||||
}
|
||||
|
||||
@@ -364,20 +369,32 @@ class ReaderViewModel(
|
||||
it.printStackTraceDebug()
|
||||
}.getOrDefault(defaultMode)
|
||||
}
|
||||
|
||||
private fun computePercent(chapterId: Long, pageIndex: Int): Float {
|
||||
val chapters = manga?.chapters ?: return -1f
|
||||
val chaptersCount = chapters.size
|
||||
val chapterIndex = chapters.indexOfFirst { x -> x.id == chapterId }
|
||||
val pages = content.value?.pages ?: return -1f
|
||||
val pagesCount = pages.count { x -> x.chapterId == chapterId }
|
||||
val chapterPercent = (chapterIndex + 1) / chaptersCount.toFloat()
|
||||
val pagePercent = (pageIndex + 1) / pagesCount.toFloat()
|
||||
return pagePercent * chapterPercent // FIXME
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is not a member of the ReaderViewModel
|
||||
* because it should work independently of the ViewModel's lifecycle.
|
||||
*/
|
||||
private fun HistoryRepository.saveStateAsync(manga: Manga, state: ReaderState): Job {
|
||||
private fun HistoryRepository.saveStateAsync(manga: Manga, state: ReaderState, percent: Float): Job {
|
||||
return processLifecycleScope.launch(Dispatchers.Default) {
|
||||
runCatching {
|
||||
addOrUpdate(
|
||||
manga = manga,
|
||||
chapterId = state.chapterId,
|
||||
page = state.page,
|
||||
scroll = state.scroll
|
||||
scroll = state.scroll,
|
||||
percent = percent,
|
||||
)
|
||||
}.onFailure {
|
||||
it.printStackTraceDebug()
|
||||
|
||||
Reference in New Issue
Block a user