mirror of
https://github.com/mihonapp/mihon.git
synced 2025-11-15 13:37:29 +01:00
Migrate History screen database calls to SQLDelight (#6933)
* Migrate History screen database call to SQLDelight - Move all migrations to SQLDelight - Move all tables to SQLDelight Co-authored-by: inorichi <3521738+inorichi@users.noreply.github.com> * Changes from review comments * Add adapters to database * Remove logging of database version in App * Change query name for paging source queries * Update migrations * Make SQLite Callback handle migration - To ensure it updates the database * Use SQLDelight Schema version for Callback database version Co-authored-by: inorichi <3521738+inorichi@users.noreply.github.com>
This commit is contained in:
@@ -2,9 +2,18 @@ package eu.kanade.tachiyomi
|
||||
|
||||
import android.app.Application
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.squareup.sqldelight.android.AndroidSqliteDriver
|
||||
import com.squareup.sqldelight.db.SqlDriver
|
||||
import data.History
|
||||
import data.Mangas
|
||||
import eu.kanade.data.AndroidDatabaseHandler
|
||||
import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.data.dateAdapter
|
||||
import eu.kanade.data.listOfStringsAdapter
|
||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.DbOpenCallback
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.saver.ImageSaver
|
||||
@@ -25,11 +34,37 @@ class AppModule(val app: Application) : InjektModule {
|
||||
override fun InjektRegistrar.registerInjectables() {
|
||||
addSingleton(app)
|
||||
|
||||
addSingletonFactory { DbOpenCallback() }
|
||||
|
||||
addSingletonFactory<SqlDriver> {
|
||||
AndroidSqliteDriver(
|
||||
schema = Database.Schema,
|
||||
context = app,
|
||||
name = DbOpenCallback.DATABASE_NAME,
|
||||
callback = get<DbOpenCallback>()
|
||||
)
|
||||
}
|
||||
|
||||
addSingletonFactory {
|
||||
Database(
|
||||
driver = get(),
|
||||
historyAdapter = History.Adapter(
|
||||
history_last_readAdapter = dateAdapter,
|
||||
history_time_readAdapter = dateAdapter
|
||||
),
|
||||
mangasAdapter = Mangas.Adapter(
|
||||
genreAdapter = listOfStringsAdapter
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
addSingletonFactory<DatabaseHandler> { AndroidDatabaseHandler(get(), get()) }
|
||||
|
||||
addSingletonFactory { Json { ignoreUnknownKeys = true } }
|
||||
|
||||
addSingletonFactory { PreferencesHelper(app) }
|
||||
|
||||
addSingletonFactory { DatabaseHelper(app) }
|
||||
addSingletonFactory { DatabaseHelper(app, get()) }
|
||||
|
||||
addSingletonFactory { ChapterCache(app) }
|
||||
|
||||
@@ -57,6 +92,8 @@ class AppModule(val app: Application) : InjektModule {
|
||||
|
||||
get<SourceManager>()
|
||||
|
||||
get<Database>()
|
||||
|
||||
get<DatabaseHelper>()
|
||||
|
||||
get<DownloadManager>()
|
||||
|
||||
@@ -26,12 +26,15 @@ import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory
|
||||
/**
|
||||
* This class provides operations to manage the database through its interfaces.
|
||||
*/
|
||||
open class DatabaseHelper(context: Context) :
|
||||
open class DatabaseHelper(
|
||||
context: Context,
|
||||
callback: DbOpenCallback
|
||||
) :
|
||||
MangaQueries, ChapterQueries, TrackQueries, CategoryQueries, MangaCategoryQueries, HistoryQueries {
|
||||
|
||||
private val configuration = SupportSQLiteOpenHelper.Configuration.builder(context)
|
||||
.name(DbOpenCallback.DATABASE_NAME)
|
||||
.callback(DbOpenCallback())
|
||||
.callback(callback)
|
||||
.build()
|
||||
|
||||
override val db = DefaultStorIOSQLite.builder()
|
||||
|
||||
@@ -2,98 +2,28 @@ package eu.kanade.tachiyomi.data.database
|
||||
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import androidx.sqlite.db.SupportSQLiteOpenHelper
|
||||
import eu.kanade.tachiyomi.data.database.tables.CategoryTable
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable
|
||||
import eu.kanade.tachiyomi.data.database.tables.HistoryTable
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable
|
||||
import com.squareup.sqldelight.android.AndroidSqliteDriver
|
||||
import eu.kanade.tachiyomi.Database
|
||||
|
||||
class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
|
||||
class DbOpenCallback : SupportSQLiteOpenHelper.Callback(Database.Schema.version) {
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Name of the database file.
|
||||
*/
|
||||
const val DATABASE_NAME = "tachiyomi.db"
|
||||
|
||||
/**
|
||||
* Version of the database.
|
||||
*/
|
||||
const val DATABASE_VERSION = 14
|
||||
}
|
||||
|
||||
override fun onCreate(db: SupportSQLiteDatabase) = with(db) {
|
||||
execSQL(MangaTable.createTableQuery)
|
||||
execSQL(ChapterTable.createTableQuery)
|
||||
execSQL(TrackTable.createTableQuery)
|
||||
execSQL(CategoryTable.createTableQuery)
|
||||
execSQL(MangaCategoryTable.createTableQuery)
|
||||
execSQL(HistoryTable.createTableQuery)
|
||||
|
||||
// DB indexes
|
||||
execSQL(MangaTable.createUrlIndexQuery)
|
||||
execSQL(MangaTable.createLibraryIndexQuery)
|
||||
execSQL(ChapterTable.createMangaIdIndexQuery)
|
||||
execSQL(ChapterTable.createUnreadChaptersIndexQuery)
|
||||
execSQL(HistoryTable.createChapterIdIndexQuery)
|
||||
override fun onCreate(db: SupportSQLiteDatabase) {
|
||||
Database.Schema.create(AndroidSqliteDriver(database = db, cacheSize = 1))
|
||||
}
|
||||
|
||||
override fun onUpgrade(db: SupportSQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
if (oldVersion < 2) {
|
||||
db.execSQL(ChapterTable.sourceOrderUpdateQuery)
|
||||
|
||||
// Fix kissmanga covers after supporting cloudflare
|
||||
db.execSQL(
|
||||
"""UPDATE mangas SET thumbnail_url =
|
||||
REPLACE(thumbnail_url, '93.174.95.110', 'kissmanga.com') WHERE source = 4""",
|
||||
)
|
||||
}
|
||||
if (oldVersion < 3) {
|
||||
// Initialize history tables
|
||||
db.execSQL(HistoryTable.createTableQuery)
|
||||
db.execSQL(HistoryTable.createChapterIdIndexQuery)
|
||||
}
|
||||
if (oldVersion < 4) {
|
||||
db.execSQL(ChapterTable.bookmarkUpdateQuery)
|
||||
}
|
||||
if (oldVersion < 5) {
|
||||
db.execSQL(ChapterTable.addScanlator)
|
||||
}
|
||||
if (oldVersion < 6) {
|
||||
db.execSQL(TrackTable.addTrackingUrl)
|
||||
}
|
||||
if (oldVersion < 7) {
|
||||
db.execSQL(TrackTable.addLibraryId)
|
||||
}
|
||||
if (oldVersion < 8) {
|
||||
db.execSQL("DROP INDEX IF EXISTS mangas_favorite_index")
|
||||
db.execSQL(MangaTable.createLibraryIndexQuery)
|
||||
db.execSQL(ChapterTable.createUnreadChaptersIndexQuery)
|
||||
}
|
||||
if (oldVersion < 9) {
|
||||
db.execSQL(TrackTable.addStartDate)
|
||||
db.execSQL(TrackTable.addFinishDate)
|
||||
}
|
||||
if (oldVersion < 10) {
|
||||
db.execSQL(MangaTable.addCoverLastModified)
|
||||
}
|
||||
if (oldVersion < 11) {
|
||||
db.execSQL(MangaTable.addDateAdded)
|
||||
db.execSQL(MangaTable.backfillDateAdded)
|
||||
}
|
||||
if (oldVersion < 12) {
|
||||
db.execSQL(MangaTable.addNextUpdateCol)
|
||||
}
|
||||
if (oldVersion < 13) {
|
||||
db.execSQL(TrackTable.renameTableToTemp)
|
||||
db.execSQL(TrackTable.createTableQuery)
|
||||
db.execSQL(TrackTable.insertFromTempTable)
|
||||
db.execSQL(TrackTable.dropTempTable)
|
||||
}
|
||||
if (oldVersion < 14) {
|
||||
db.execSQL(ChapterTable.fixDateUploadIfNeeded)
|
||||
}
|
||||
Database.Schema.migrate(
|
||||
driver = AndroidSqliteDriver(database = db, cacheSize = 1),
|
||||
oldVersion = oldVersion,
|
||||
newVersion = newVersion
|
||||
)
|
||||
}
|
||||
|
||||
override fun onConfigure(db: SupportSQLiteDatabase) {
|
||||
|
||||
@@ -4,39 +4,11 @@ import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
|
||||
import com.pushtorefresh.storio.sqlite.queries.RawQuery
|
||||
import eu.kanade.tachiyomi.data.database.DbProvider
|
||||
import eu.kanade.tachiyomi.data.database.models.History
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
|
||||
import eu.kanade.tachiyomi.data.database.resolvers.HistoryUpsertResolver
|
||||
import eu.kanade.tachiyomi.data.database.resolvers.MangaChapterHistoryGetResolver
|
||||
import eu.kanade.tachiyomi.data.database.tables.HistoryTable
|
||||
import java.util.Date
|
||||
|
||||
interface HistoryQueries : DbProvider {
|
||||
|
||||
/**
|
||||
* Insert history into database
|
||||
* @param history object containing history information
|
||||
*/
|
||||
fun insertHistory(history: History) = db.put().`object`(history).prepare()
|
||||
|
||||
/**
|
||||
* Returns history of recent manga containing last read chapter
|
||||
* @param date recent date range
|
||||
* @param limit the limit of manga to grab
|
||||
* @param offset offset the db by
|
||||
* @param search what to search in the db history
|
||||
*/
|
||||
fun getRecentManga(date: Date, limit: Int = 25, offset: Int = 0, search: String = "") = db.get()
|
||||
.listOfObjects(MangaChapterHistory::class.java)
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(getRecentMangasQuery(search))
|
||||
.args(date.time, limit, offset)
|
||||
.observesTables(HistoryTable.TABLE)
|
||||
.build(),
|
||||
)
|
||||
.withGetResolver(MangaChapterHistoryGetResolver.INSTANCE)
|
||||
.prepare()
|
||||
|
||||
fun getHistoryByMangaId(mangaId: Long) = db.get()
|
||||
.listOfObjects(History::class.java)
|
||||
.withQuery(
|
||||
@@ -79,34 +51,6 @@ interface HistoryQueries : DbProvider {
|
||||
.withPutResolver(HistoryUpsertResolver())
|
||||
.prepare()
|
||||
|
||||
fun resetHistoryLastRead(historyId: Long) = db.executeSQL()
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(
|
||||
"""
|
||||
UPDATE ${HistoryTable.TABLE}
|
||||
SET history_last_read = 0
|
||||
WHERE ${HistoryTable.COL_ID} = $historyId
|
||||
""".trimIndent()
|
||||
)
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun resetHistoryLastRead(historyIds: List<Long>) = db.executeSQL()
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(
|
||||
"""
|
||||
UPDATE ${HistoryTable.TABLE}
|
||||
SET history_last_read = 0
|
||||
WHERE ${HistoryTable.COL_ID} in ${historyIds.joinToString(",", "(", ")")}
|
||||
""".trimIndent()
|
||||
)
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun dropHistoryTable() = db.delete()
|
||||
.byQuery(
|
||||
DeleteQuery.builder()
|
||||
|
||||
@@ -70,7 +70,8 @@ fun getRecentMangasQuery(search: String = "") =
|
||||
SELECT ${Chapter.TABLE}.${Chapter.COL_MANGA_ID},${Chapter.TABLE}.${Chapter.COL_ID} as ${History.COL_CHAPTER_ID}, MAX(${History.TABLE}.${History.COL_LAST_READ}) as ${History.COL_LAST_READ}
|
||||
FROM ${Chapter.TABLE} JOIN ${History.TABLE}
|
||||
ON ${Chapter.TABLE}.${Chapter.COL_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID}
|
||||
GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}) AS max_last_read
|
||||
GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}
|
||||
) AS max_last_read
|
||||
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID}
|
||||
WHERE ${History.TABLE}.${History.COL_LAST_READ} > ?
|
||||
AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID}
|
||||
|
||||
@@ -11,13 +11,4 @@ object CategoryTable {
|
||||
const val COL_ORDER = "sort"
|
||||
|
||||
const val COL_FLAGS = "flags"
|
||||
|
||||
val createTableQuery: String
|
||||
get() =
|
||||
"""CREATE TABLE $TABLE(
|
||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
$COL_NAME TEXT NOT NULL,
|
||||
$COL_ORDER INTEGER NOT NULL,
|
||||
$COL_FLAGS INTEGER NOT NULL
|
||||
)"""
|
||||
}
|
||||
|
||||
@@ -27,42 +27,4 @@ object ChapterTable {
|
||||
const val COL_CHAPTER_NUMBER = "chapter_number"
|
||||
|
||||
const val COL_SOURCE_ORDER = "source_order"
|
||||
|
||||
val createTableQuery: String
|
||||
get() =
|
||||
"""CREATE TABLE $TABLE(
|
||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
$COL_MANGA_ID INTEGER NOT NULL,
|
||||
$COL_URL TEXT NOT NULL,
|
||||
$COL_NAME TEXT NOT NULL,
|
||||
$COL_SCANLATOR TEXT,
|
||||
$COL_READ BOOLEAN NOT NULL,
|
||||
$COL_BOOKMARK BOOLEAN NOT NULL,
|
||||
$COL_LAST_PAGE_READ INT NOT NULL,
|
||||
$COL_CHAPTER_NUMBER FLOAT NOT NULL,
|
||||
$COL_SOURCE_ORDER INTEGER NOT NULL,
|
||||
$COL_DATE_FETCH LONG NOT NULL,
|
||||
$COL_DATE_UPLOAD LONG NOT NULL,
|
||||
FOREIGN KEY($COL_MANGA_ID) REFERENCES ${MangaTable.TABLE} (${MangaTable.COL_ID})
|
||||
ON DELETE CASCADE
|
||||
)"""
|
||||
|
||||
val createMangaIdIndexQuery: String
|
||||
get() = "CREATE INDEX ${TABLE}_${COL_MANGA_ID}_index ON $TABLE($COL_MANGA_ID)"
|
||||
|
||||
val createUnreadChaptersIndexQuery: String
|
||||
get() = "CREATE INDEX ${TABLE}_unread_by_manga_index ON $TABLE($COL_MANGA_ID, $COL_READ) " +
|
||||
"WHERE $COL_READ = 0"
|
||||
|
||||
val sourceOrderUpdateQuery: String
|
||||
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_SOURCE_ORDER INTEGER DEFAULT 0"
|
||||
|
||||
val bookmarkUpdateQuery: String
|
||||
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_BOOKMARK BOOLEAN DEFAULT FALSE"
|
||||
|
||||
val addScanlator: String
|
||||
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_SCANLATOR TEXT DEFAULT NULL"
|
||||
|
||||
val fixDateUploadIfNeeded: String
|
||||
get() = "UPDATE $TABLE SET $COL_DATE_UPLOAD = $COL_DATE_FETCH WHERE $COL_DATE_UPLOAD = 0"
|
||||
}
|
||||
|
||||
@@ -26,24 +26,4 @@ object HistoryTable {
|
||||
* Time read column name
|
||||
*/
|
||||
const val COL_TIME_READ = "${TABLE}_time_read"
|
||||
|
||||
/**
|
||||
* query to create history table
|
||||
*/
|
||||
val createTableQuery: String
|
||||
get() =
|
||||
"""CREATE TABLE $TABLE(
|
||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
$COL_CHAPTER_ID INTEGER NOT NULL UNIQUE,
|
||||
$COL_LAST_READ LONG,
|
||||
$COL_TIME_READ LONG,
|
||||
FOREIGN KEY($COL_CHAPTER_ID) REFERENCES ${ChapterTable.TABLE} (${ChapterTable.COL_ID})
|
||||
ON DELETE CASCADE
|
||||
)"""
|
||||
|
||||
/**
|
||||
* query to index history chapter id
|
||||
*/
|
||||
val createChapterIdIndexQuery: String
|
||||
get() = "CREATE INDEX ${TABLE}_${COL_CHAPTER_ID}_index ON $TABLE($COL_CHAPTER_ID)"
|
||||
}
|
||||
|
||||
@@ -9,16 +9,4 @@ object MangaCategoryTable {
|
||||
const val COL_MANGA_ID = "manga_id"
|
||||
|
||||
const val COL_CATEGORY_ID = "category_id"
|
||||
|
||||
val createTableQuery: String
|
||||
get() =
|
||||
"""CREATE TABLE $TABLE(
|
||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
$COL_MANGA_ID INTEGER NOT NULL,
|
||||
$COL_CATEGORY_ID INTEGER NOT NULL,
|
||||
FOREIGN KEY($COL_CATEGORY_ID) REFERENCES ${CategoryTable.TABLE} (${CategoryTable.COL_ID})
|
||||
ON DELETE CASCADE,
|
||||
FOREIGN KEY($COL_MANGA_ID) REFERENCES ${MangaTable.TABLE} (${MangaTable.COL_ID})
|
||||
ON DELETE CASCADE
|
||||
)"""
|
||||
}
|
||||
|
||||
@@ -47,53 +47,4 @@ object MangaTable {
|
||||
const val COMPUTED_COL_UNREAD_COUNT = "unread_count"
|
||||
|
||||
const val COMPUTED_COL_READ_COUNT = "read_count"
|
||||
|
||||
val createTableQuery: String
|
||||
get() =
|
||||
"""CREATE TABLE $TABLE(
|
||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
$COL_SOURCE INTEGER NOT NULL,
|
||||
$COL_URL TEXT NOT NULL,
|
||||
$COL_ARTIST TEXT,
|
||||
$COL_AUTHOR TEXT,
|
||||
$COL_DESCRIPTION TEXT,
|
||||
$COL_GENRE TEXT,
|
||||
$COL_TITLE TEXT NOT NULL,
|
||||
$COL_STATUS INTEGER NOT NULL,
|
||||
$COL_THUMBNAIL_URL TEXT,
|
||||
$COL_FAVORITE INTEGER NOT NULL,
|
||||
$COL_LAST_UPDATE LONG,
|
||||
$COL_NEXT_UPDATE LONG,
|
||||
$COL_INITIALIZED BOOLEAN NOT NULL,
|
||||
$COL_VIEWER INTEGER NOT NULL,
|
||||
$COL_CHAPTER_FLAGS INTEGER NOT NULL,
|
||||
$COL_COVER_LAST_MODIFIED LONG NOT NULL,
|
||||
$COL_DATE_ADDED LONG NOT NULL
|
||||
)"""
|
||||
|
||||
val createUrlIndexQuery: String
|
||||
get() = "CREATE INDEX ${TABLE}_${COL_URL}_index ON $TABLE($COL_URL)"
|
||||
|
||||
val createLibraryIndexQuery: String
|
||||
get() = "CREATE INDEX library_${COL_FAVORITE}_index ON $TABLE($COL_FAVORITE) " +
|
||||
"WHERE $COL_FAVORITE = 1"
|
||||
|
||||
val addCoverLastModified: String
|
||||
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_COVER_LAST_MODIFIED LONG NOT NULL DEFAULT 0"
|
||||
|
||||
val addDateAdded: String
|
||||
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_DATE_ADDED LONG NOT NULL DEFAULT 0"
|
||||
|
||||
/**
|
||||
* Used with addDateAdded to populate it with the oldest chapter fetch date.
|
||||
*/
|
||||
val backfillDateAdded: String
|
||||
get() = "UPDATE $TABLE SET $COL_DATE_ADDED = " +
|
||||
"(SELECT MIN(${ChapterTable.COL_DATE_FETCH}) " +
|
||||
"FROM $TABLE INNER JOIN ${ChapterTable.TABLE} " +
|
||||
"ON $TABLE.$COL_ID = ${ChapterTable.TABLE}.${ChapterTable.COL_MANGA_ID} " +
|
||||
"GROUP BY $TABLE.$COL_ID)"
|
||||
|
||||
val addNextUpdateCol: String
|
||||
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_NEXT_UPDATE LONG DEFAULT 0"
|
||||
}
|
||||
|
||||
@@ -30,43 +30,6 @@ object TrackTable {
|
||||
|
||||
const val COL_FINISH_DATE = "finish_date"
|
||||
|
||||
val createTableQuery: String
|
||||
get() =
|
||||
"""CREATE TABLE $TABLE(
|
||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
$COL_MANGA_ID INTEGER NOT NULL,
|
||||
$COL_SYNC_ID INTEGER NOT NULL,
|
||||
$COL_MEDIA_ID INTEGER NOT NULL,
|
||||
$COL_LIBRARY_ID INTEGER,
|
||||
$COL_TITLE TEXT NOT NULL,
|
||||
$COL_LAST_CHAPTER_READ REAL NOT NULL,
|
||||
$COL_TOTAL_CHAPTERS INTEGER NOT NULL,
|
||||
$COL_STATUS INTEGER NOT NULL,
|
||||
$COL_SCORE FLOAT NOT NULL,
|
||||
$COL_TRACKING_URL TEXT NOT NULL,
|
||||
$COL_START_DATE LONG NOT NULL,
|
||||
$COL_FINISH_DATE LONG NOT NULL,
|
||||
UNIQUE ($COL_MANGA_ID, $COL_SYNC_ID) ON CONFLICT REPLACE,
|
||||
FOREIGN KEY($COL_MANGA_ID) REFERENCES ${MangaTable.TABLE} (${MangaTable.COL_ID})
|
||||
ON DELETE CASCADE
|
||||
)"""
|
||||
|
||||
val addTrackingUrl: String
|
||||
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_TRACKING_URL TEXT DEFAULT ''"
|
||||
|
||||
val addLibraryId: String
|
||||
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_LIBRARY_ID INTEGER NULL"
|
||||
|
||||
val addStartDate: String
|
||||
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_START_DATE LONG NOT NULL DEFAULT 0"
|
||||
|
||||
val addFinishDate: String
|
||||
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_FINISH_DATE LONG NOT NULL DEFAULT 0"
|
||||
|
||||
val renameTableToTemp: String
|
||||
get() =
|
||||
"ALTER TABLE $TABLE RENAME TO ${TABLE}_tmp"
|
||||
|
||||
val insertFromTempTable: String
|
||||
get() =
|
||||
"""
|
||||
@@ -74,7 +37,4 @@ object TrackTable {
|
||||
|SELECT $COL_ID,$COL_MANGA_ID,$COL_SYNC_ID,$COL_MEDIA_ID,$COL_LIBRARY_ID,$COL_TITLE,$COL_LAST_CHAPTER_READ,$COL_TOTAL_CHAPTERS,$COL_STATUS,$COL_SCORE,$COL_TRACKING_URL,$COL_START_DATE,$COL_FINISH_DATE
|
||||
|FROM ${TABLE}_tmp
|
||||
""".trimMargin()
|
||||
|
||||
val dropTempTable: String
|
||||
get() = "DROP TABLE ${TABLE}_tmp"
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
* @param chapterId id of chapter
|
||||
*/
|
||||
private fun openChapter(context: Context, mangaId: Long, chapterId: Long) {
|
||||
val db = DatabaseHelper(context)
|
||||
val db = Injekt.get<DatabaseHelper>()
|
||||
val manga = db.getManga(mangaId).executeAsBlocking()
|
||||
val chapter = db.getChapter(chapterId).executeAsBlocking()
|
||||
if (manga != null && chapter != null) {
|
||||
|
||||
@@ -35,6 +35,7 @@ import com.google.android.material.snackbar.Snackbar
|
||||
import dev.chrisbanes.insetter.applyInsetter
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.SelectableAdapter
|
||||
import eu.kanade.domain.history.model.HistoryWithRelations
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
@@ -118,6 +119,8 @@ class MangaController :
|
||||
DownloadCustomChaptersDialog.Listener,
|
||||
DeleteChaptersDialog.Listener {
|
||||
|
||||
constructor(history: HistoryWithRelations) : this(history.mangaId)
|
||||
|
||||
constructor(manga: Manga?, fromSource: Boolean = false) : super(
|
||||
bundleOf(
|
||||
MANGA_EXTRA to (manga?.id ?: 0),
|
||||
|
||||
@@ -6,9 +6,9 @@ import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import eu.kanade.domain.chapter.model.Chapter
|
||||
import eu.kanade.presentation.history.HistoryScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.databinding.ComposeControllerBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.RootController
|
||||
@@ -44,16 +44,16 @@ class HistoryController :
|
||||
HistoryScreen(
|
||||
composeView = binding.root,
|
||||
presenter = presenter,
|
||||
onClickItem = { (manga, _, _) ->
|
||||
router.pushController(MangaController(manga).withFadeTransaction())
|
||||
onClickItem = { history ->
|
||||
router.pushController(MangaController(history).withFadeTransaction())
|
||||
},
|
||||
onClickResume = { (manga, chapter, _) ->
|
||||
presenter.getNextChapterForManga(manga, chapter)
|
||||
onClickResume = { history ->
|
||||
presenter.getNextChapterForManga(history.mangaId, history.chapterId)
|
||||
},
|
||||
onClickDelete = { (manga, _, history), all ->
|
||||
onClickDelete = { history, all ->
|
||||
if (all) {
|
||||
// Reset last read of chapter to 0L
|
||||
presenter.removeAllFromHistory(manga.id!!)
|
||||
presenter.removeAllFromHistory(history.mangaId)
|
||||
} else {
|
||||
// Remove all chapters belonging to manga from library
|
||||
presenter.removeFromHistory(history)
|
||||
@@ -97,7 +97,7 @@ class HistoryController :
|
||||
fun openChapter(chapter: Chapter?) {
|
||||
val activity = activity ?: return
|
||||
if (chapter != null) {
|
||||
val intent = ReaderActivity.newIntent(activity, chapter.manga_id, chapter.id)
|
||||
val intent = ReaderActivity.newIntent(activity, chapter.mangaId, chapter.id)
|
||||
startActivity(intent)
|
||||
} else {
|
||||
activity.toast(R.string.no_next_chapter)
|
||||
|
||||
@@ -10,11 +10,8 @@ import eu.kanade.domain.history.interactor.GetHistory
|
||||
import eu.kanade.domain.history.interactor.GetNextChapterForManga
|
||||
import eu.kanade.domain.history.interactor.RemoveHistoryById
|
||||
import eu.kanade.domain.history.interactor.RemoveHistoryByMangaId
|
||||
import eu.kanade.domain.history.model.HistoryWithRelations
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.History
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
@@ -58,20 +55,13 @@ class HistoryPresenter(
|
||||
.map { pagingData ->
|
||||
pagingData
|
||||
.map {
|
||||
UiModel.History(it)
|
||||
UiModel.Item(it)
|
||||
}
|
||||
.insertSeparators { before, after ->
|
||||
val beforeDate =
|
||||
before?.item?.history?.last_read?.toDateKey()
|
||||
val afterDate =
|
||||
after?.item?.history?.last_read?.toDateKey()
|
||||
val beforeDate = before?.item?.readAt?.time?.toDateKey() ?: Date(0)
|
||||
val afterDate = after?.item?.readAt?.time?.toDateKey() ?: Date(0)
|
||||
when {
|
||||
beforeDate == null && afterDate != null -> UiModel.Header(
|
||||
afterDate,
|
||||
)
|
||||
beforeDate != null && afterDate != null -> UiModel.Header(
|
||||
afterDate,
|
||||
)
|
||||
beforeDate.time != afterDate.time && afterDate.time != 0L -> UiModel.Header(afterDate)
|
||||
// Return null to avoid adding a separator between two items.
|
||||
else -> null
|
||||
}
|
||||
@@ -90,7 +80,7 @@ class HistoryPresenter(
|
||||
}
|
||||
}
|
||||
|
||||
fun removeFromHistory(history: History) {
|
||||
fun removeFromHistory(history: HistoryWithRelations) {
|
||||
presenterScope.launchIO {
|
||||
removeHistoryById.await(history)
|
||||
}
|
||||
@@ -102,9 +92,9 @@ class HistoryPresenter(
|
||||
}
|
||||
}
|
||||
|
||||
fun getNextChapterForManga(manga: Manga, chapter: Chapter) {
|
||||
fun getNextChapterForManga(mangaId: Long, chapterId: Long) {
|
||||
presenterScope.launchIO {
|
||||
val chapter = getNextChapterForManga.await(manga, chapter)
|
||||
val chapter = getNextChapterForManga.await(mangaId, chapterId)
|
||||
view?.openChapter(chapter)
|
||||
}
|
||||
}
|
||||
@@ -121,7 +111,7 @@ class HistoryPresenter(
|
||||
}
|
||||
|
||||
sealed class UiModel {
|
||||
data class History(val item: MangaChapterHistory) : UiModel()
|
||||
data class Item(val item: HistoryWithRelations) : UiModel()
|
||||
data class Header(val date: Date) : UiModel()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package eu.kanade.tachiyomi.ui.setting.database
|
||||
|
||||
import android.os.Bundle
|
||||
import eu.kanade.tachiyomi.Database
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
@@ -13,6 +14,7 @@ import uy.kohesive.injekt.api.get
|
||||
class ClearDatabasePresenter : BasePresenter<ClearDatabaseController>() {
|
||||
|
||||
private val db = Injekt.get<DatabaseHelper>()
|
||||
private val database = Injekt.get<Database>()
|
||||
|
||||
private val sourceManager = Injekt.get<SourceManager>()
|
||||
|
||||
@@ -26,7 +28,7 @@ class ClearDatabasePresenter : BasePresenter<ClearDatabaseController>() {
|
||||
|
||||
fun clearDatabaseForSourceIds(sources: List<Long>) {
|
||||
db.deleteMangasNotInLibraryBySourceIds(sources).executeAsBlocking()
|
||||
db.deleteHistoryNoLastRead().executeAsBlocking()
|
||||
database.historyQueries.removeResettedHistory()
|
||||
}
|
||||
|
||||
private fun getDatabaseSourcesObservable(): Observable<List<ClearDatabaseSourceItem>> {
|
||||
|
||||
Reference in New Issue
Block a user