Remove need for SQLDelight primitive adapters

(cherry picked from commit cd91ea9b7723eec378bbbefd916d3da6407d685e)

# Conflicts:
#	app/build.gradle.kts
#	app/src/main/java/eu/kanade/tachiyomi/AppModule.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt
#	data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt
#	domain/src/main/java/tachiyomi/domain/history/model/HistoryWithRelations.kt
This commit is contained in:
arkon 2023-07-29 16:14:23 -04:00 committed by Jobobby04
parent af41e65b3d
commit 873742f6f4
42 changed files with 99 additions and 138 deletions

View File

@ -168,7 +168,6 @@ dependencies {
implementation(androidx.paging.compose) implementation(androidx.paging.compose)
implementation(libs.bundles.sqlite) implementation(libs.bundles.sqlite)
implementation(libs.sqldelight.primitive.adapters)
// SY --> // SY -->
implementation(libs.sqlcipher) implementation(libs.sqlcipher)
// SY <-- // SY <--

View File

@ -152,9 +152,9 @@ class SyncChaptersWithSource(
val reAdded = mutableListOf<Chapter>() val reAdded = mutableListOf<Chapter>()
val deletedChapterNumbers = TreeSet<Float>() val deletedChapterNumbers = TreeSet<Double>()
val deletedReadChapterNumbers = TreeSet<Float>() val deletedReadChapterNumbers = TreeSet<Double>()
val deletedBookmarkedChapterNumbers = TreeSet<Float>() val deletedBookmarkedChapterNumbers = TreeSet<Double>()
toDelete.forEach { chapter -> toDelete.forEach { chapter ->
if (chapter.read) deletedReadChapterNumbers.add(chapter.chapterNumber) if (chapter.read) deletedReadChapterNumbers.add(chapter.chapterNumber)

View File

@ -12,7 +12,7 @@ fun Chapter.toSChapter(): SChapter {
it.url = url it.url = url
it.name = name it.name = name
it.date_upload = dateUpload it.date_upload = dateUpload
it.chapter_number = chapterNumber it.chapter_number = chapterNumber.toFloat()
it.scanlator = scanlator it.scanlator = scanlator
} }
} }
@ -22,7 +22,7 @@ fun Chapter.copyFromSChapter(sChapter: SChapter): Chapter {
name = sChapter.name, name = sChapter.name,
url = sChapter.url, url = sChapter.url,
dateUpload = sChapter.date_upload, dateUpload = sChapter.date_upload,
chapterNumber = sChapter.chapter_number, chapterNumber = sChapter.chapter_number.toDouble(),
scanlator = sChapter.scanlator?.ifBlank { null }, scanlator = sChapter.scanlator?.ifBlank { null },
) )
} }
@ -48,6 +48,6 @@ fun Chapter.toDbChapter(): DbChapter = ChapterImpl().also {
it.last_page_read = lastPageRead.toInt() it.last_page_read = lastPageRead.toInt()
it.date_fetch = dateFetch it.date_fetch = dateFetch
it.date_upload = dateUpload it.date_upload = dateUpload
it.chapter_number = chapterNumber it.chapter_number = chapterNumber.toFloat()
it.source_order = sourceOrder.toInt() it.source_order = sourceOrder.toInt()
} }

View File

@ -108,7 +108,7 @@ fun getComicInfo(manga: Manga, chapter: Chapter, chapterUrl: String, categories:
title = ComicInfo.Title(chapter.name), title = ComicInfo.Title(chapter.name),
series = ComicInfo.Series(manga.title), series = ComicInfo.Series(manga.title),
number = chapter.chapterNumber.takeIf { it >= 0 }?.let { number = chapter.chapterNumber.takeIf { it >= 0 }?.let {
if ((it.rem(1) == 0.0F)) { if ((it.rem(1) == 0.0)) {
ComicInfo.Number(it.toInt().toString()) ComicInfo.Number(it.toInt().toString())
} else { } else {
ComicInfo.Number(it.toString()) ComicInfo.Number(it.toString())

View File

@ -22,7 +22,7 @@ fun Track.toDbTrack(): DbTrack = DbTrack.create(syncId).also {
it.last_chapter_read = lastChapterRead.toFloat() it.last_chapter_read = lastChapterRead.toFloat()
it.total_chapters = totalChapters.toInt() it.total_chapters = totalChapters.toInt()
it.status = status.toInt() it.status = status.toInt()
it.score = score it.score = score.toFloat()
it.tracking_url = remoteUrl it.tracking_url = remoteUrl
it.started_reading_date = startDate it.started_reading_date = startDate
it.finished_reading_date = finishDate it.finished_reading_date = finishDate
@ -40,7 +40,7 @@ fun DbTrack.toDomainTrack(idRequired: Boolean = true): Track? {
lastChapterRead = last_chapter_read.toDouble(), lastChapterRead = last_chapter_read.toDouble(),
totalChapters = total_chapters.toLong(), totalChapters = total_chapters.toLong(),
status = status.toLong(), status = status.toLong(),
score = score, score = score.toDouble(),
remoteUrl = tracking_url, remoteUrl = tracking_url,
startDate = started_reading_date, startDate = started_reading_date,
finishDate = finished_reading_date, finishDate = finished_reading_date,

View File

@ -98,7 +98,7 @@ fun TrackInfoDialogHome(
}, },
onChaptersClick = { onChapterClick(item) }, onChaptersClick = { onChapterClick(item) },
score = item.service.displayScore(item.track.toDbTrack()) score = item.service.displayScore(item.track.toDbTrack())
.takeIf { supportsScoring && item.track.score != 0F }, .takeIf { supportsScoring && item.track.score != 0.0 },
onScoreClick = { onScoreClick(item) } onScoreClick = { onScoreClick(item) }
.takeIf { supportsScoring }, .takeIf { supportsScoring },
startDate = remember(item.track.startDate) { dateFormat.format(item.track.startDate) } startDate = remember(item.track.startDate) { dateFormat.format(item.track.startDate) }

View File

@ -8,6 +8,6 @@ private val formatter = DecimalFormat(
DecimalFormatSymbols().apply { decimalSeparator = '.' }, DecimalFormatSymbols().apply { decimalSeparator = '.' },
) )
fun formatChapterNumber(chapterNumber: Float): String { fun formatChapterNumber(chapterNumber: Double): String {
return formatter.format(chapterNumber) return formatter.format(chapterNumber)
} }

View File

@ -5,8 +5,6 @@ import android.os.Build
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
import app.cash.sqldelight.adapter.primitive.FloatColumnAdapter
import app.cash.sqldelight.adapter.primitive.IntColumnAdapter
import app.cash.sqldelight.db.SqlDriver import app.cash.sqldelight.db.SqlDriver
import app.cash.sqldelight.driver.android.AndroidSqliteDriver import app.cash.sqldelight.driver.android.AndroidSqliteDriver
import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.base.BasePreferences
@ -44,19 +42,14 @@ import tachiyomi.core.preference.PreferenceStore
import tachiyomi.core.provider.AndroidBackupFolderProvider import tachiyomi.core.provider.AndroidBackupFolderProvider
import tachiyomi.core.provider.AndroidDownloadFolderProvider import tachiyomi.core.provider.AndroidDownloadFolderProvider
import tachiyomi.data.AndroidDatabaseHandler import tachiyomi.data.AndroidDatabaseHandler
import tachiyomi.data.Chapters
import tachiyomi.data.Database import tachiyomi.data.Database
import tachiyomi.data.DatabaseHandler import tachiyomi.data.DatabaseHandler
import tachiyomi.data.DateColumnAdapter
import tachiyomi.data.History import tachiyomi.data.History
import tachiyomi.data.Manga_sync
import tachiyomi.data.Mangas import tachiyomi.data.Mangas
import tachiyomi.data.Search_metadata import tachiyomi.data.StringListAndColumnAdapter
import tachiyomi.data.Search_tags import tachiyomi.data.StringListColumnAdapter
import tachiyomi.data.Search_titles import tachiyomi.data.UpdateStrategyColumnAdapter
import tachiyomi.data.dateAdapter
import tachiyomi.data.listOfStringsAdapter
import tachiyomi.data.listOfStringsAndAdapter
import tachiyomi.data.updateStrategyAdapter
import tachiyomi.domain.UnsortedPreferences import tachiyomi.domain.UnsortedPreferences
import tachiyomi.domain.backup.service.BackupPreferences import tachiyomi.domain.backup.service.BackupPreferences
import tachiyomi.domain.download.service.DownloadPreferences import tachiyomi.domain.download.service.DownloadPreferences
@ -127,31 +120,16 @@ class AppModule(val app: Application) : InjektModule {
addSingletonFactory { addSingletonFactory {
Database( Database(
driver = get(), driver = get(),
chaptersAdapter = Chapters.Adapter(
chapter_numberAdapter = FloatColumnAdapter,
),
historyAdapter = History.Adapter( historyAdapter = History.Adapter(
last_readAdapter = dateAdapter, last_readAdapter = DateColumnAdapter,
),
manga_syncAdapter = Manga_sync.Adapter(
scoreAdapter = FloatColumnAdapter,
), ),
mangasAdapter = Mangas.Adapter( mangasAdapter = Mangas.Adapter(
genreAdapter = listOfStringsAdapter, genreAdapter = StringListColumnAdapter,
update_strategyAdapter = updateStrategyAdapter, update_strategyAdapter = UpdateStrategyColumnAdapter,
// SY --> // SY -->
filtered_scanlatorsAdapter = listOfStringsAndAdapter, filtered_scanlatorsAdapter = StringListAndColumnAdapter,
// SY <-- // SY <--
), ),
search_metadataAdapter = Search_metadata.Adapter(
extra_versionAdapter = IntColumnAdapter,
),
search_tagsAdapter = Search_tags.Adapter(
typeAdapter = IntColumnAdapter,
),
search_titlesAdapter = Search_titles.Adapter(
typeAdapter = IntColumnAdapter,
),
) )
} }
addSingletonFactory<DatabaseHandler> { AndroidDatabaseHandler(get(), get()) } addSingletonFactory<DatabaseHandler> { AndroidDatabaseHandler(get(), get()) }

View File

@ -44,15 +44,14 @@ import logcat.LogPriority
import okio.buffer import okio.buffer
import okio.gzip import okio.gzip
import okio.sink import okio.sink
import tachiyomi.core.util.lang.toLong
import tachiyomi.core.util.system.logcat import tachiyomi.core.util.system.logcat
import tachiyomi.data.DatabaseHandler import tachiyomi.data.DatabaseHandler
import tachiyomi.data.Manga_sync import tachiyomi.data.Manga_sync
import tachiyomi.data.Mangas import tachiyomi.data.Mangas
import tachiyomi.data.listOfStringsAndAdapter import tachiyomi.data.StringListAndColumnAdapter
import tachiyomi.data.UpdateStrategyColumnAdapter
import tachiyomi.data.manga.mangaMapper import tachiyomi.data.manga.mangaMapper
import tachiyomi.data.manga.mergedMangaReferenceMapper import tachiyomi.data.manga.mergedMangaReferenceMapper
import tachiyomi.data.updateStrategyAdapter
import tachiyomi.domain.backup.service.BackupPreferences import tachiyomi.domain.backup.service.BackupPreferences
import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.category.interactor.GetCategories
import tachiyomi.domain.category.model.Category import tachiyomi.domain.category.model.Category
@ -484,7 +483,7 @@ class BackupManager(
track.last_chapter_read, track.last_chapter_read,
track.total_chapters, track.total_chapters,
track.status, track.status,
track.score.toDouble(), track.score,
track.remote_url, track.remote_url,
track.start_date, track.start_date,
track.finish_date, track.finish_date,
@ -608,10 +607,10 @@ class BackupManager(
coverLastModified = manga.coverLastModified, coverLastModified = manga.coverLastModified,
dateAdded = manga.dateAdded, dateAdded = manga.dateAdded,
// SY --> // SY -->
filteredScanlators = manga.filteredScanlators?.let(listOfStringsAndAdapter::encode), filteredScanlators = manga.filteredScanlators?.let(StringListAndColumnAdapter::encode),
// SY <-- // SY <--
mangaId = manga.id, mangaId = manga.id,
updateStrategy = manga.updateStrategy.let(updateStrategyAdapter::encode), updateStrategy = manga.updateStrategy.let(UpdateStrategyColumnAdapter::encode),
) )
} }
return manga.id return manga.id

View File

@ -26,7 +26,7 @@ data class BackupChapter(
return Chapter.create().copy( return Chapter.create().copy(
url = this@BackupChapter.url, url = this@BackupChapter.url,
name = this@BackupChapter.name, name = this@BackupChapter.name,
chapterNumber = this@BackupChapter.chapterNumber, chapterNumber = this@BackupChapter.chapterNumber.toDouble(),
scanlator = this@BackupChapter.scanlator, scanlator = this@BackupChapter.scanlator,
read = this@BackupChapter.read, read = this@BackupChapter.read,
bookmark = this@BackupChapter.bookmark, bookmark = this@BackupChapter.bookmark,
@ -39,11 +39,11 @@ data class BackupChapter(
} }
} }
val backupChapterMapper = { _: Long, _: Long, url: String, name: String, scanlator: String?, read: Boolean, bookmark: Boolean, lastPageRead: Long, chapterNumber: Float, source_order: Long, dateFetch: Long, dateUpload: Long, lastModifiedAt: Long -> val backupChapterMapper = { _: Long, _: Long, url: String, name: String, scanlator: String?, read: Boolean, bookmark: Boolean, lastPageRead: Long, chapterNumber: Double, source_order: Long, dateFetch: Long, dateUpload: Long, lastModifiedAt: Long ->
BackupChapter( BackupChapter(
url = url, url = url,
name = name, name = name,
chapterNumber = chapterNumber, chapterNumber = chapterNumber.toFloat(),
scanlator = scanlator, scanlator = scanlator,
read = read, read = read,
bookmark = bookmark, bookmark = bookmark,

View File

@ -4,7 +4,7 @@ import eu.kanade.tachiyomi.source.model.UpdateStrategy
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber import kotlinx.serialization.protobuf.ProtoNumber
import tachiyomi.data.listOfStringsAndAdapter import tachiyomi.data.StringListAndColumnAdapter
import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.model.Chapter
import tachiyomi.domain.manga.model.CustomMangaInfo import tachiyomi.domain.manga.model.CustomMangaInfo
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
@ -79,7 +79,7 @@ data class BackupManga(
chapterFlags = this@BackupManga.chapterFlags.toLong(), chapterFlags = this@BackupManga.chapterFlags.toLong(),
updateStrategy = this@BackupManga.updateStrategy, updateStrategy = this@BackupManga.updateStrategy,
lastModifiedAt = this@BackupManga.lastModifiedAt, lastModifiedAt = this@BackupManga.lastModifiedAt,
filteredScanlators = this@BackupManga.filtered_scanlators?.let(listOfStringsAndAdapter::decode), filteredScanlators = this@BackupManga.filtered_scanlators?.let(StringListAndColumnAdapter::decode),
) )
} }
@ -141,7 +141,7 @@ data class BackupManga(
lastModifiedAt = manga.lastModifiedAt, lastModifiedAt = manga.lastModifiedAt,
favoriteModifiedAt = manga.favoriteModifiedAt, favoriteModifiedAt = manga.favoriteModifiedAt,
// SY --> // SY -->
filtered_scanlators = manga.filteredScanlators?.let(listOfStringsAndAdapter::encode), filtered_scanlators = manga.filteredScanlators?.let(StringListAndColumnAdapter::encode),
).also { backupManga -> ).also { backupManga ->
customMangaInfo?.let { customMangaInfo?.let {
backupManga.customTitle = it.title backupManga.customTitle = it.title

View File

@ -44,7 +44,7 @@ data class BackupTracking(
title = this@BackupTracking.title, title = this@BackupTracking.title,
lastChapterRead = this@BackupTracking.lastChapterRead.toDouble(), lastChapterRead = this@BackupTracking.lastChapterRead.toDouble(),
totalChapters = this@BackupTracking.totalChapters.toLong(), totalChapters = this@BackupTracking.totalChapters.toLong(),
score = this@BackupTracking.score, score = this@BackupTracking.score.toDouble(),
status = this@BackupTracking.status.toLong(), status = this@BackupTracking.status.toLong(),
startDate = this@BackupTracking.startedReadingDate, startDate = this@BackupTracking.startedReadingDate,
finishDate = this@BackupTracking.finishedReadingDate, finishDate = this@BackupTracking.finishedReadingDate,
@ -54,7 +54,7 @@ data class BackupTracking(
} }
val backupTrackMapper = { val backupTrackMapper = {
_: Long, _: Long, syncId: Long, mediaId: Long, libraryId: Long?, title: String, lastChapterRead: Double, totalChapters: Long, status: Long, score: Float, remoteUrl: String, startDate: Long, finishDate: Long -> _: Long, _: Long, syncId: Long, mediaId: Long, libraryId: Long?, title: String, lastChapterRead: Double, totalChapters: Long, status: Long, score: Double, remoteUrl: String, startDate: Long, finishDate: Long ->
BackupTracking( BackupTracking(
syncId = syncId.toInt(), syncId = syncId.toInt(),
mediaId = mediaId, mediaId = mediaId,
@ -63,7 +63,7 @@ val backupTrackMapper = {
title = title, title = title,
lastChapterRead = lastChapterRead.toFloat(), lastChapterRead = lastChapterRead.toFloat(),
totalChapters = totalChapters.toInt(), totalChapters = totalChapters.toInt(),
score = score, score = score.toFloat(),
status = status.toInt(), status = status.toInt(),
startedReadingDate = startDate, startedReadingDate = startDate,
finishedReadingDate = finishDate, finishedReadingDate = finishDate,

View File

@ -36,7 +36,7 @@ fun Chapter.toDomainChapter(): DomainChapter? {
url = url, url = url,
name = name, name = name,
dateUpload = date_upload, dateUpload = date_upload,
chapterNumber = chapter_number, chapterNumber = chapter_number.toDouble(),
scanlator = scanlator, scanlator = scanlator,
lastModifiedAt = last_modified, lastModifiedAt = last_modified,
) )

View File

@ -65,7 +65,7 @@ abstract class TrackService(val id: Long) {
abstract fun getScoreList(): List<String> abstract fun getScoreList(): List<String>
// TODO: Store all scores as 10 point in the future maybe? // TODO: Store all scores as 10 point in the future maybe?
open fun get10PointScore(track: DomainTrack): Float { open fun get10PointScore(track: DomainTrack): Double {
return track.score return track.score
} }

View File

@ -93,9 +93,9 @@ class Anilist(id: Long) : TrackService(id), DeletableTrackService {
} }
} }
override fun get10PointScore(track: DomainTrack): Float { override fun get10PointScore(track: DomainTrack): Double {
// Score is stored in 100 point format // Score is stored in 100 point format
return track.score / 10f return track.score / 10.0
} }
override fun indexToScore(index: Int): Float { override fun indexToScore(index: Int): Float {

View File

@ -6,6 +6,6 @@ fun SChapter.copyFrom(other: Chapters) {
name = other.name name = other.name
url = other.url url = other.url
date_upload = other.date_upload date_upload = other.date_upload
chapter_number = other.chapter_number chapter_number = other.chapter_number.toFloat()
scanlator = other.scanlator scanlator = other.scanlator
} }

View File

@ -30,11 +30,11 @@ class MigratingManga(
} }
data class ChapterInfo( data class ChapterInfo(
val latestChapter: Float?, val latestChapter: Double?,
val chapterCount: Int, val chapterCount: Int,
) { ) {
fun getFormattedLatestChapter(context: Context): String { fun getFormattedLatestChapter(context: Context): String {
return if (latestChapter != null && latestChapter > 0f) { return if (latestChapter != null && latestChapter > 0.0) {
context.getString( context.getString(
R.string.latest_, R.string.latest_,
DecimalFormat("#.#").format(latestChapter), DecimalFormat("#.#").format(latestChapter),

View File

@ -158,15 +158,13 @@ class StatsScreenModel(
private fun getTrackMeanScore(scoredMangaTrackMap: Map<Long, List<Track>>): Double { private fun getTrackMeanScore(scoredMangaTrackMap: Map<Long, List<Track>>): Double {
return scoredMangaTrackMap return scoredMangaTrackMap
.map { (_, tracks) -> .map { (_, tracks) ->
tracks.map { tracks.map(::get10PointScore).average()
get10PointScore(it)
}.average()
} }
.fastFilter { !it.isNaN() } .fastFilter { !it.isNaN() }
.average() .average()
} }
private fun get10PointScore(track: Track): Float { private fun get10PointScore(track: Track): Double {
val service = trackManager.getService(track.syncId)!! val service = trackManager.getService(track.syncId)!!
return service.get10PointScore(track) return service.get10PointScore(track)
} }

View File

@ -243,7 +243,7 @@ class EHentaiUpdateHelper(context: Context) {
}, },
dateFetch = chapter.dateFetch, dateFetch = chapter.dateFetch,
dateUpload = chapter.dateUpload, dateUpload = chapter.dateUpload,
chapterNumber = -1F, chapterNumber = -1.0,
scanlator = null, scanlator = null,
sourceOrder = -1, sourceOrder = -1,
lastModifiedAt = 0, lastModifiedAt = 0,
@ -256,7 +256,7 @@ class EHentaiUpdateHelper(context: Context) {
val newChapters = mutableListOf<Chapter>() val newChapters = mutableListOf<Chapter>()
chapters.mapIndexed { index, chapter -> chapters.mapIndexed { index, chapter ->
val name = "v${index + 1}: " + chapter.name.substringAfter(" ") val name = "v${index + 1}: " + chapter.name.substringAfter(" ")
val chapterNumber = index + 1f val chapterNumber = index + 1.0
val sourceOrder = chapters.lastIndex - index.toLong() val sourceOrder = chapters.lastIndex - index.toLong()
when (chapter.id) { when (chapter.id) {
-1L -> newChapters.add( -1L -> newChapters.add(

View File

@ -4,23 +4,23 @@ import app.cash.sqldelight.ColumnAdapter
import eu.kanade.tachiyomi.source.model.UpdateStrategy import eu.kanade.tachiyomi.source.model.UpdateStrategy
import java.util.Date import java.util.Date
val dateAdapter = object : ColumnAdapter<Date, Long> { object DateColumnAdapter : ColumnAdapter<Date, Long> {
override fun decode(databaseValue: Long): Date = Date(databaseValue) override fun decode(databaseValue: Long): Date = Date(databaseValue)
override fun encode(value: Date): Long = value.time override fun encode(value: Date): Long = value.time
} }
private const val listOfStringsSeparator = ", " private const val LIST_OF_STRINGS_SEPARATOR = ", "
val listOfStringsAdapter = object : ColumnAdapter<List<String>, String> { object StringListColumnAdapter : ColumnAdapter<List<String>, String> {
override fun decode(databaseValue: String) = override fun decode(databaseValue: String) =
if (databaseValue.isEmpty()) { if (databaseValue.isEmpty()) {
emptyList() emptyList()
} else { } else {
databaseValue.split(listOfStringsSeparator) databaseValue.split(LIST_OF_STRINGS_SEPARATOR)
} }
override fun encode(value: List<String>) = value.joinToString(separator = listOfStringsSeparator) override fun encode(value: List<String>) = value.joinToString(separator = LIST_OF_STRINGS_SEPARATOR)
} }
val updateStrategyAdapter = object : ColumnAdapter<UpdateStrategy, Long> { object UpdateStrategyColumnAdapter : ColumnAdapter<UpdateStrategy, Long> {
override fun decode(databaseValue: Long): UpdateStrategy = override fun decode(databaseValue: Long): UpdateStrategy =
UpdateStrategy.entries.getOrElse(databaseValue.toInt()) { UpdateStrategy.ALWAYS_UPDATE } UpdateStrategy.entries.getOrElse(databaseValue.toInt()) { UpdateStrategy.ALWAYS_UPDATE }
@ -28,25 +28,14 @@ val updateStrategyAdapter = object : ColumnAdapter<UpdateStrategy, Long> {
} }
// SY --> // SY -->
private const val listOfStringsAndSeparator = " & " private const val LIST_OF_STRINGS_AND_SEPARATOR = " & "
val listOfStringsAndAdapter = object : ColumnAdapter<List<String>, String> { object StringListAndColumnAdapter : ColumnAdapter<List<String>, String> {
override fun decode(databaseValue: String) = override fun decode(databaseValue: String) =
if (databaseValue.isEmpty()) { if (databaseValue.isEmpty()) {
emptyList() emptyList()
} else { } else {
databaseValue.split(listOfStringsAndSeparator) databaseValue.split(LIST_OF_STRINGS_AND_SEPARATOR)
} }
override fun encode(value: List<String>) = value.joinToString(separator = listOfStringsAndSeparator) override fun encode(value: List<String>) = value.joinToString(separator = LIST_OF_STRINGS_AND_SEPARATOR)
}
private const val listOfLongsSeparator = "/"
val listOfLongsAdapter = object : ColumnAdapter<List<Long>, String> {
override fun decode(databaseValue: String) =
if (databaseValue.isEmpty()) {
emptyList()
} else {
databaseValue.split(listOfLongsSeparator).mapNotNull { it.toLongOrNull() }
}
override fun encode(value: List<Long>) = value.joinToString(separator = listOfLongsSeparator)
} }
// SY <-- // SY <--

View File

@ -15,7 +15,7 @@ private val mapper = { cursor: SqlCursor ->
artist = cursor.getString(3), artist = cursor.getString(3),
author = cursor.getString(4), author = cursor.getString(4),
description = cursor.getString(5), description = cursor.getString(5),
genre = cursor.getString(6)?.let(listOfStringsAdapter::decode), genre = cursor.getString(6)?.let(StringListColumnAdapter::decode),
title = cursor.getString(7)!!, title = cursor.getString(7)!!,
status = cursor.getLong(8)!!, status = cursor.getLong(8)!!,
thumbnail_url = cursor.getString(9), thumbnail_url = cursor.getString(9),
@ -27,8 +27,8 @@ private val mapper = { cursor: SqlCursor ->
chapter_flags = cursor.getLong(15)!!, chapter_flags = cursor.getLong(15)!!,
cover_last_modified = cursor.getLong(16)!!, cover_last_modified = cursor.getLong(16)!!,
date_added = cursor.getLong(17)!!, date_added = cursor.getLong(17)!!,
filtered_scanlators = cursor.getString(18)?.let(listOfStringsAndAdapter::decode), filtered_scanlators = cursor.getString(18)?.let(StringListAndColumnAdapter::decode),
update_strategy = updateStrategyAdapter.decode(cursor.getLong(19)!!), update_strategy = UpdateStrategyColumnAdapter.decode(cursor.getLong(19)!!),
calculate_interval = cursor.getLong(20)!!, calculate_interval = cursor.getLong(20)!!,
last_modified_at = cursor.getLong(21)!!, last_modified_at = cursor.getLong(21)!!,
favorite_modified_at = cursor.getLong(22), favorite_modified_at = cursor.getLong(22),

View File

@ -2,7 +2,7 @@ package tachiyomi.data.chapter
import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.model.Chapter
val chapterMapper: (Long, Long, String, String, String?, Boolean, Boolean, Long, Float, Long, Long, Long, Long) -> Chapter = val chapterMapper: (Long, Long, String, String, String?, Boolean, Boolean, Long, Double, Long, Long, Long, Long) -> Chapter =
{ id, mangaId, url, name, scanlator, read, bookmark, lastPageRead, chapterNumber, sourceOrder, dateFetch, dateUpload, lastModifiedAt -> { id, mangaId, url, name, scanlator, read, bookmark, lastPageRead, chapterNumber, sourceOrder, dateFetch, dateUpload, lastModifiedAt ->
Chapter( Chapter(
id = id, id = id,

View File

@ -14,7 +14,7 @@ val historyMapper: (Long, Long, Date?, Long) -> History = { id, chapterId, readA
) )
} }
val historyWithRelationsMapper: (Long, Long, Long, String, String?, Long, Boolean, Long, Float, Date?, Long) -> HistoryWithRelations = { val historyWithRelationsMapper: (Long, Long, Long, String, String?, Long, Boolean, Long, Double, Date?, Long) -> HistoryWithRelations = {
historyId, mangaId, chapterId, title, thumbnailUrl, sourceId, isFavorite, coverLastModified, chapterNumber, readAt, readDuration -> historyId, mangaId, chapterId, title, thumbnailUrl, sourceId, isFavorite, coverLastModified, chapterNumber, readAt, readDuration ->
HistoryWithRelations( HistoryWithRelations(
id = historyId, id = historyId,

View File

@ -44,15 +44,15 @@ class MangaMetadataRepositoryImpl(
handler.await(true) { handler.await(true) {
flatMetadata.metadata.run { flatMetadata.metadata.run {
search_metadataQueries.upsert(mangaId, uploader, extra, indexedExtra, extraVersion) search_metadataQueries.upsert(mangaId, uploader, extra, indexedExtra, extraVersion.toLong())
} }
search_tagsQueries.deleteByManga(flatMetadata.metadata.mangaId) search_tagsQueries.deleteByManga(flatMetadata.metadata.mangaId)
flatMetadata.tags.forEach { flatMetadata.tags.forEach {
search_tagsQueries.insert(it.mangaId, it.namespace, it.name, it.type) search_tagsQueries.insert(it.mangaId, it.namespace, it.name, it.type.toLong())
} }
search_titlesQueries.deleteByManga(flatMetadata.metadata.mangaId) search_titlesQueries.deleteByManga(flatMetadata.metadata.mangaId)
flatMetadata.titles.forEach { flatMetadata.titles.forEach {
search_titlesQueries.insert(it.mangaId, it.title, it.type) search_titlesQueries.insert(it.mangaId, it.title, it.type.toLong())
} }
} }
} }

View File

@ -6,9 +6,9 @@ import logcat.LogPriority
import tachiyomi.core.util.system.logcat import tachiyomi.core.util.system.logcat
import tachiyomi.data.AndroidDatabaseHandler import tachiyomi.data.AndroidDatabaseHandler
import tachiyomi.data.DatabaseHandler import tachiyomi.data.DatabaseHandler
import tachiyomi.data.listOfStringsAdapter import tachiyomi.data.StringListAndColumnAdapter
import tachiyomi.data.listOfStringsAndAdapter import tachiyomi.data.StringListColumnAdapter
import tachiyomi.data.updateStrategyAdapter import tachiyomi.data.UpdateStrategyColumnAdapter
import tachiyomi.domain.library.model.LibraryManga import tachiyomi.domain.library.model.LibraryManga
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.manga.model.MangaUpdate import tachiyomi.domain.manga.model.MangaUpdate
@ -143,7 +143,7 @@ class MangaRepositoryImpl(
artist = value.artist, artist = value.artist,
author = value.author, author = value.author,
description = value.description, description = value.description,
genre = value.genre?.let(listOfStringsAdapter::encode), genre = value.genre?.let(StringListColumnAdapter::encode),
title = value.title, title = value.title,
status = value.status, status = value.status,
thumbnailUrl = value.thumbnailUrl, thumbnailUrl = value.thumbnailUrl,
@ -157,10 +157,10 @@ class MangaRepositoryImpl(
coverLastModified = value.coverLastModified, coverLastModified = value.coverLastModified,
dateAdded = value.dateAdded, dateAdded = value.dateAdded,
// SY --> // SY -->
filteredScanlators = value.filteredScanlators?.let(listOfStringsAndAdapter::encode), filteredScanlators = value.filteredScanlators?.let(StringListAndColumnAdapter::encode),
// SY <-- // SY <--
mangaId = value.id, mangaId = value.id,
updateStrategy = value.updateStrategy?.let(updateStrategyAdapter::encode), updateStrategy = value.updateStrategy?.let(UpdateStrategyColumnAdapter::encode),
) )
} }
} }

View File

@ -2,13 +2,13 @@ package tachiyomi.data.manga
import exh.metadata.sql.models.SearchMetadata import exh.metadata.sql.models.SearchMetadata
val searchMetadataMapper: (Long, String?, String, String?, Int) -> SearchMetadata = val searchMetadataMapper: (Long, String?, String, String?, Long) -> SearchMetadata =
{ mangaId, uploader, extra, indexedExtra, extraVersion -> { mangaId, uploader, extra, indexedExtra, extraVersion ->
SearchMetadata( SearchMetadata(
mangaId = mangaId, mangaId = mangaId,
uploader = uploader, uploader = uploader,
extra = extra, extra = extra,
indexedExtra = indexedExtra, indexedExtra = indexedExtra,
extraVersion = extraVersion, extraVersion = extraVersion.toInt(),
) )
} }

View File

@ -2,13 +2,13 @@ package tachiyomi.data.manga
import exh.metadata.sql.models.SearchTag import exh.metadata.sql.models.SearchTag
val searchTagMapper: (Long, Long, String?, String, Int) -> SearchTag = val searchTagMapper: (Long, Long, String?, String, Long) -> SearchTag =
{ id, mangaId, namespace, name, type -> { id, mangaId, namespace, name, type ->
SearchTag( SearchTag(
id = id, id = id,
mangaId = mangaId, mangaId = mangaId,
namespace = namespace, namespace = namespace,
name = name, name = name,
type = type, type = type.toInt(),
) )
} }

View File

@ -2,12 +2,12 @@ package tachiyomi.data.manga
import exh.metadata.sql.models.SearchTitle import exh.metadata.sql.models.SearchTitle
val searchTitleMapper: (Long, Long, String, Int) -> SearchTitle = val searchTitleMapper: (Long, Long, String, Long) -> SearchTitle =
{ id, mangaId, title, type -> { id, mangaId, title, type ->
SearchTitle( SearchTitle(
id = id, id = id,
mangaId = mangaId, mangaId = mangaId,
title = title, title = title,
type = type, type = type.toInt(),
) )
} }

View File

@ -2,7 +2,7 @@ package tachiyomi.data.track
import tachiyomi.domain.track.model.Track import tachiyomi.domain.track.model.Track
val trackMapper: (Long, Long, Long, Long, Long?, String, Double, Long, Long, Float, String, Long, Long) -> Track = val trackMapper: (Long, Long, Long, Long, Long?, String, Double, Long, Long, Double, String, Long, Long) -> Track =
{ id, mangaId, syncId, remoteId, libraryId, title, lastChapterRead, totalChapters, status, score, remoteUrl, startDate, finishDate -> { id, mangaId, syncId, remoteId, libraryId, title, lastChapterRead, totalChapters, status, score, remoteUrl, startDate, finishDate ->
Track( Track(
id = id, id = id,

View File

@ -1,5 +1,4 @@
import kotlin.Boolean; import kotlin.Boolean;
import kotlin.Float;
CREATE TABLE chapters( CREATE TABLE chapters(
_id INTEGER NOT NULL PRIMARY KEY, _id INTEGER NOT NULL PRIMARY KEY,
@ -10,7 +9,7 @@ CREATE TABLE chapters(
read INTEGER AS Boolean NOT NULL, read INTEGER AS Boolean NOT NULL,
bookmark INTEGER AS Boolean NOT NULL, bookmark INTEGER AS Boolean NOT NULL,
last_page_read INTEGER NOT NULL, last_page_read INTEGER NOT NULL,
chapter_number REAL AS Float NOT NULL, chapter_number REAL NOT NULL,
source_order INTEGER NOT NULL, source_order INTEGER NOT NULL,
date_fetch INTEGER NOT NULL, date_fetch INTEGER NOT NULL,
date_upload INTEGER NOT NULL, date_upload INTEGER NOT NULL,

View File

@ -1,5 +1,3 @@
import kotlin.Float;
CREATE TABLE manga_sync( CREATE TABLE manga_sync(
_id INTEGER NOT NULL PRIMARY KEY, _id INTEGER NOT NULL PRIMARY KEY,
manga_id INTEGER NOT NULL, manga_id INTEGER NOT NULL,
@ -10,7 +8,7 @@ CREATE TABLE manga_sync(
last_chapter_read REAL NOT NULL, last_chapter_read REAL NOT NULL,
total_chapters INTEGER NOT NULL, total_chapters INTEGER NOT NULL,
status INTEGER NOT NULL, status INTEGER NOT NULL,
score REAL AS Float NOT NULL, score REAL NOT NULL,
remote_url TEXT NOT NULL, remote_url TEXT NOT NULL,
start_date INTEGER NOT NULL, start_date INTEGER NOT NULL,
finish_date INTEGER NOT NULL, finish_date INTEGER NOT NULL,

View File

@ -5,7 +5,7 @@ CREATE TABLE search_metadata (
uploader TEXT, uploader TEXT,
extra TEXT NOT NULL, extra TEXT NOT NULL,
indexed_extra TEXT, indexed_extra TEXT,
extra_version INTEGER AS Int NOT NULL, extra_version INTEGER NOT NULL,
FOREIGN KEY(manga_id) REFERENCES mangas (_id) FOREIGN KEY(manga_id) REFERENCES mangas (_id)
ON DELETE CASCADE ON DELETE CASCADE
); );

View File

@ -5,7 +5,7 @@ CREATE TABLE search_tags (
manga_id INTEGER NOT NULL, manga_id INTEGER NOT NULL,
namespace TEXT, namespace TEXT,
name TEXT NOT NULL, name TEXT NOT NULL,
type INTEGER AS Int NOT NULL, type INTEGER NOT NULL,
FOREIGN KEY(manga_id) REFERENCES mangas (_id) FOREIGN KEY(manga_id) REFERENCES mangas (_id)
ON DELETE CASCADE ON DELETE CASCADE
); );

View File

@ -4,7 +4,7 @@ CREATE TABLE search_titles (
_id INTEGER NOT NULL PRIMARY KEY, _id INTEGER NOT NULL PRIMARY KEY,
manga_id INTEGER NOT NULL, manga_id INTEGER NOT NULL,
title TEXT NOT NULL, title TEXT NOT NULL,
type INTEGER AS Int NOT NULL, type INTEGER NOT NULL,
FOREIGN KEY(manga_id) REFERENCES mangas (_id) FOREIGN KEY(manga_id) REFERENCES mangas (_id)
ON DELETE CASCADE ON DELETE CASCADE
); );

View File

@ -11,7 +11,7 @@ data class Chapter(
val url: String, val url: String,
val name: String, val name: String,
val dateUpload: Long, val dateUpload: Long,
val chapterNumber: Float, val chapterNumber: Double,
val scanlator: String?, val scanlator: String?,
val lastModifiedAt: Long, val lastModifiedAt: Long,
) { ) {
@ -30,7 +30,7 @@ data class Chapter(
url = "", url = "",
name = "", name = "",
dateUpload = -1, dateUpload = -1,
chapterNumber = -1f, chapterNumber = -1.0,
scanlator = null, scanlator = null,
lastModifiedAt = 0, lastModifiedAt = 0,
) )

View File

@ -11,7 +11,7 @@ data class ChapterUpdate(
val url: String? = null, val url: String? = null,
val name: String? = null, val name: String? = null,
val dateUpload: Long? = null, val dateUpload: Long? = null,
val chapterNumber: Float? = null, val chapterNumber: Double? = null,
val scanlator: String? = null, val scanlator: String? = null,
) )

View File

@ -30,9 +30,9 @@ object ChapterRecognition {
*/ */
private val unwantedWhiteSpace = Regex("""\s(?=extra|special|omake)""") private val unwantedWhiteSpace = Regex("""\s(?=extra|special|omake)""")
fun parseChapterNumber(mangaTitle: String, chapterName: String, chapterNumber: Float? = null): Float { fun parseChapterNumber(mangaTitle: String, chapterName: String, chapterNumber: Double? = null): Double {
// If chapter number is known return. // If chapter number is known return.
if (chapterNumber != null && (chapterNumber == -2f || chapterNumber > -1f)) { if (chapterNumber != null && (chapterNumber == -2.0 || chapterNumber > -1.0)) {
return chapterNumber return chapterNumber
} }
@ -57,7 +57,7 @@ object ChapterRecognition {
// Take the first number encountered. // Take the first number encountered.
number.find(name)?.let { return getChapterNumberFromMatch(it) } number.find(name)?.let { return getChapterNumberFromMatch(it) }
return chapterNumber ?: -1f return chapterNumber ?: -1.0
} }
/** /**
@ -65,9 +65,9 @@ object ChapterRecognition {
* @param match result of regex * @param match result of regex
* @return chapter number if found else null * @return chapter number if found else null
*/ */
private fun getChapterNumberFromMatch(match: MatchResult): Float { private fun getChapterNumberFromMatch(match: MatchResult): Double {
return match.let { return match.let {
val initial = it.groups[1]?.value?.toFloat()!! val initial = it.groups[1]?.value?.toDouble()!!
val subChapterDecimal = it.groups[2]?.value val subChapterDecimal = it.groups[2]?.value
val subChapterAlpha = it.groups[3]?.value val subChapterAlpha = it.groups[3]?.value
val addition = checkForDecimal(subChapterDecimal, subChapterAlpha) val addition = checkForDecimal(subChapterDecimal, subChapterAlpha)

View File

@ -3,16 +3,16 @@ package tachiyomi.domain.chapter.service
import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.model.Chapter
import kotlin.math.floor import kotlin.math.floor
fun List<Float>.missingChaptersCount(): Int { fun List<Double>.missingChaptersCount(): Int {
if (this.isEmpty()) { if (this.isEmpty()) {
return 0 return 0
} }
val chapters = this val chapters = this
// Ignore unknown chapter numbers // Ignore unknown chapter numbers
.filterNot { it == -1f } .filterNot { it == -1.0 }
// Convert to integers, as we cannot check if 16.5 is missing // Convert to integers, as we cannot check if 16.5 is missing
.map(Float::toInt) .map(Double::toInt)
// Only keep unique chapters so that -1 or 16 are not counted multiple times // Only keep unique chapters so that -1 or 16 are not counted multiple times
.distinct() .distinct()
.sorted() .sorted()
@ -43,7 +43,7 @@ fun calculateChapterGap(higherChapter: Chapter?, lowerChapter: Chapter?): Int {
return calculateChapterGap(higherChapter.chapterNumber, lowerChapter.chapterNumber) return calculateChapterGap(higherChapter.chapterNumber, lowerChapter.chapterNumber)
} }
fun calculateChapterGap(higherChapterNumber: Float, lowerChapterNumber: Float): Int { fun calculateChapterGap(higherChapterNumber: Double, lowerChapterNumber: Double): Int {
if (higherChapterNumber < 0f || lowerChapterNumber < 0f) return 0 if (higherChapterNumber < 0.0 || lowerChapterNumber < 0.0) return 0
return floor(higherChapterNumber).toInt() - floor(lowerChapterNumber).toInt() - 1 return floor(higherChapterNumber).toInt() - floor(lowerChapterNumber).toInt() - 1
} }

View File

@ -12,7 +12,7 @@ data class HistoryWithRelations(
// SY --> // SY -->
val ogTitle: String, val ogTitle: String,
// SY <-- // SY <--
val chapterNumber: Float, val chapterNumber: Double,
val readAt: Date?, val readAt: Date?,
val readDuration: Long, val readDuration: Long,
val coverData: MangaCover, val coverData: MangaCover,

View File

@ -10,7 +10,7 @@ data class Track(
val lastChapterRead: Double, val lastChapterRead: Double,
val totalChapters: Long, val totalChapters: Long,
val status: Long, val status: Long,
val score: Float, val score: Double,
val remoteUrl: String, val remoteUrl: String,
val startDate: Long, val startDate: Long,
val finishDate: Long, val finishDate: Long,

View File

@ -83,7 +83,6 @@ leakcanary-plumber = { module = "com.squareup.leakcanary:plumber-android", versi
sqldelight-android-driver = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" } sqldelight-android-driver = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions-jvm", version.ref = "sqldelight" } sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions-jvm", version.ref = "sqldelight" }
sqldelight-android-paging = { module = "app.cash.sqldelight:androidx-paging3-extensions", version.ref = "sqldelight" } sqldelight-android-paging = { module = "app.cash.sqldelight:androidx-paging3-extensions", version.ref = "sqldelight" }
sqldelight-primitive-adapters = { module = "app.cash.sqldelight:primitive-adapters", version.ref = "sqldelight" }
sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", version.ref = "sqldelight" } sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", version.ref = "sqldelight" }
sqldelight-gradle = { module = "app.cash.sqldelight:gradle-plugin", version.ref = "sqldelight" } sqldelight-gradle = { module = "app.cash.sqldelight:gradle-plugin", version.ref = "sqldelight" }
@ -104,7 +103,7 @@ js-engine = ["quickjs-android"]
sqlite = ["sqlite-framework", "sqlite-ktx", "sqlite-android"] sqlite = ["sqlite-framework", "sqlite-ktx", "sqlite-android"]
coil = ["coil-core", "coil-gif", "coil-compose"] coil = ["coil-core", "coil-gif", "coil-compose"]
shizuku = ["shizuku-api", "shizuku-provider"] shizuku = ["shizuku-api", "shizuku-provider"]
sqldelight = ["sqldelight-android-driver", "sqldelight-coroutines", "sqldelight-android-paging", "sqldelight-primitive-adapters"] sqldelight = ["sqldelight-android-driver", "sqldelight-coroutines", "sqldelight-android-paging"]
voyager = ["voyager-navigator", "voyager-tab-navigator", "voyager-transitions"] voyager = ["voyager-navigator", "voyager-tab-navigator", "voyager-transitions"]
richtext = ["richtext-commonmark", "richtext-m3"] richtext = ["richtext-commonmark", "richtext-m3"]
test = ["junit", "kotest-assertions", "mockk"] test = ["junit", "kotest-assertions", "mockk"]

View File

@ -340,7 +340,9 @@ actual class LocalSource(
chapterFile.nameWithoutExtension chapterFile.nameWithoutExtension
} }
date_upload = chapterFile.lastModified() date_upload = chapterFile.lastModified()
chapter_number = ChapterRecognition.parseChapterNumber(manga.title, this.name, this.chapter_number) chapter_number = ChapterRecognition
.parseChapterNumber(manga.title, this.name, this.chapter_number.toDouble())
.toFloat()
val format = Format.valueOf(chapterFile) val format = Format.valueOf(chapterFile)
if (format is Format.Epub) { if (format is Format.Epub) {