Skip to content

Commit 87b8430

Browse files
committed
refactor: Use DB instead of file to store custom manga info
1 parent 716cc1f commit 87b8430

File tree

16 files changed

+354
-61
lines changed

16 files changed

+354
-61
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ Please backup your data before updating to this version.
1717

1818
## Other
1919
- Migrate to SQLDelight
20+
- Custom manga info is now stored in the database

app/src/main/java/dev/yokai/core/di/DomainModule.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@ package dev.yokai.core.di
22

33
import dev.yokai.domain.extension.repo.ExtensionRepoRepository
44
import dev.yokai.data.extension.repo.ExtensionRepoRepositoryImpl
5+
import dev.yokai.data.library.custom.CustomMangaRepositoryImpl
56
import dev.yokai.domain.extension.interactor.TrustExtension
67
import dev.yokai.domain.extension.repo.interactor.CreateExtensionRepo
78
import dev.yokai.domain.extension.repo.interactor.DeleteExtensionRepo
89
import dev.yokai.domain.extension.repo.interactor.GetExtensionRepo
910
import dev.yokai.domain.extension.repo.interactor.GetExtensionRepoCount
1011
import dev.yokai.domain.extension.repo.interactor.ReplaceExtensionRepo
1112
import dev.yokai.domain.extension.repo.interactor.UpdateExtensionRepo
13+
import dev.yokai.domain.library.custom.CustomMangaRepository
14+
import dev.yokai.domain.library.custom.interactor.CreateCustomManga
15+
import dev.yokai.domain.library.custom.interactor.DeleteCustomManga
16+
import dev.yokai.domain.library.custom.interactor.GetCustomManga
1217
import uy.kohesive.injekt.api.InjektModule
1318
import uy.kohesive.injekt.api.InjektRegistrar
1419
import uy.kohesive.injekt.api.addFactory
@@ -17,6 +22,8 @@ import uy.kohesive.injekt.api.get
1722

1823
class DomainModule : InjektModule {
1924
override fun InjektRegistrar.registerInjectables() {
25+
addFactory { TrustExtension(get(), get()) }
26+
2027
addSingletonFactory<ExtensionRepoRepository> { ExtensionRepoRepositoryImpl(get()) }
2128
addFactory { CreateExtensionRepo(get()) }
2229
addFactory { DeleteExtensionRepo(get()) }
@@ -25,6 +32,9 @@ class DomainModule : InjektModule {
2532
addFactory { ReplaceExtensionRepo(get()) }
2633
addFactory { UpdateExtensionRepo(get(), get()) }
2734

28-
addFactory { TrustExtension(get(), get()) }
35+
addSingletonFactory<CustomMangaRepository> { CustomMangaRepositoryImpl(get()) }
36+
addFactory { CreateCustomManga(get()) }
37+
addFactory { DeleteCustomManga(get()) }
38+
addFactory { GetCustomManga(get()) }
2939
}
3040
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package dev.yokai.data.library.custom
2+
3+
import android.database.sqlite.SQLiteException
4+
import dev.yokai.data.DatabaseHandler
5+
import dev.yokai.domain.library.custom.CustomMangaRepository
6+
import dev.yokai.domain.library.custom.exception.SaveCustomMangaException
7+
import dev.yokai.domain.library.custom.model.CustomMangaInfo
8+
import kotlinx.coroutines.flow.Flow
9+
import timber.log.Timber
10+
11+
class CustomMangaRepositoryImpl(private val handler: DatabaseHandler) : CustomMangaRepository {
12+
override fun subscribeAll(): Flow<List<CustomMangaInfo>> =
13+
handler.subscribeToList { custom_manga_infoQueries.findAll(::mapCustomMangaInfo) }
14+
15+
override suspend fun getAll(): List<CustomMangaInfo> =
16+
handler.awaitList { custom_manga_infoQueries.findAll(::mapCustomMangaInfo) }
17+
18+
override suspend fun insertCustomManga(
19+
mangaId: Long,
20+
title: String?,
21+
author: String?,
22+
artist: String?,
23+
description: String?,
24+
genre: String?,
25+
status: Int?
26+
) {
27+
try {
28+
handler.await { custom_manga_infoQueries.insert(mangaId, title, author, artist, description, genre, status?.toLong()) }
29+
} catch (exc: SQLiteException) {
30+
Timber.e(exc)
31+
throw SaveCustomMangaException(exc)
32+
}
33+
}
34+
35+
override suspend fun insertBulkCustomManga(mangaList: List<CustomMangaInfo>) {
36+
try {
37+
handler.await(true) {
38+
for (customMangaInfo in mangaList) {
39+
custom_manga_infoQueries.insert(
40+
customMangaInfo.mangaId,
41+
customMangaInfo.title,
42+
customMangaInfo.author,
43+
customMangaInfo.artist,
44+
customMangaInfo.description,
45+
customMangaInfo.genre,
46+
customMangaInfo.status?.toLong(),
47+
)
48+
}
49+
}
50+
} catch (exc: SQLiteException) {
51+
Timber.e(exc)
52+
throw SaveCustomMangaException(exc)
53+
}
54+
}
55+
56+
override suspend fun deleteCustomManga(mangaId: Long) =
57+
handler.await { custom_manga_infoQueries.delete(mangaId) }
58+
59+
override suspend fun deleteBulkCustomManga(mangaIds: List<Long>) =
60+
handler.await(true) {
61+
for (mangaId in mangaIds) {
62+
custom_manga_infoQueries.delete(mangaId)
63+
}
64+
}
65+
66+
private fun mapCustomMangaInfo(
67+
mangaId: Long,
68+
title: String?,
69+
author: String?,
70+
artist: String?,
71+
description: String?,
72+
genre: String?,
73+
status: Long?
74+
): CustomMangaInfo = CustomMangaInfo(mangaId, title, author, artist, description, genre, status?.toInt())
75+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package dev.yokai.domain.library.custom
2+
3+
import dev.yokai.domain.library.custom.model.CustomMangaInfo
4+
import kotlinx.coroutines.flow.Flow
5+
6+
interface CustomMangaRepository {
7+
fun subscribeAll(): Flow<List<CustomMangaInfo>>
8+
suspend fun getAll(): List<CustomMangaInfo>
9+
suspend fun insertCustomManga(
10+
mangaId: Long,
11+
title: String? = null,
12+
author: String? = null,
13+
artist: String? = null,
14+
description: String? = null,
15+
genre: String? = null,
16+
status: Int? = null,
17+
)
18+
suspend fun insertCustomManga(mangaInfo: CustomMangaInfo) =
19+
insertCustomManga(
20+
mangaInfo.mangaId,
21+
mangaInfo.title,
22+
mangaInfo.author,
23+
mangaInfo.artist,
24+
mangaInfo.description,
25+
mangaInfo.genre,
26+
mangaInfo.status,
27+
)
28+
suspend fun insertBulkCustomManga(mangaList: List<CustomMangaInfo>)
29+
suspend fun deleteCustomManga(mangaId: Long)
30+
suspend fun deleteBulkCustomManga(mangaIds: List<Long>)
31+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package dev.yokai.domain.library.custom.exception
2+
3+
import java.io.IOException
4+
5+
/**
6+
* Exception to abstract over SQLiteException and SQLiteConstraintException for multiplatform.
7+
*
8+
* @param throwable the source throwable to include for tracing.
9+
*/
10+
class SaveCustomMangaException(throwable: Throwable) : IOException("Error Saving Custom Manga Info to Database", throwable)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package dev.yokai.domain.library.custom.interactor
2+
3+
import dev.yokai.domain.library.custom.CustomMangaRepository
4+
import dev.yokai.domain.library.custom.exception.SaveCustomMangaException
5+
import dev.yokai.domain.library.custom.model.CustomMangaInfo
6+
7+
class CreateCustomManga(
8+
private val customMangaRepository: CustomMangaRepository,
9+
) {
10+
suspend fun await(mangaInfo: CustomMangaInfo): Result {
11+
try {
12+
customMangaRepository.insertCustomManga(mangaInfo)
13+
return Result.Success
14+
} catch (exc: SaveCustomMangaException) {
15+
return Result.Error
16+
}
17+
}
18+
19+
suspend fun bulk(mangaList: List<CustomMangaInfo>): Result {
20+
try {
21+
customMangaRepository.insertBulkCustomManga(mangaList)
22+
return Result.Success
23+
} catch (exc: SaveCustomMangaException) {
24+
return Result.Error
25+
}
26+
}
27+
28+
sealed interface Result {
29+
data object Success : Result
30+
data object Error : Result
31+
}
32+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package dev.yokai.domain.library.custom.interactor
2+
3+
import dev.yokai.domain.library.custom.CustomMangaRepository
4+
5+
class DeleteCustomManga(
6+
private val customMangaRepository: CustomMangaRepository,
7+
) {
8+
suspend fun await(mangaId: Long) = customMangaRepository.deleteCustomManga(mangaId)
9+
suspend fun bulk(mangaIds: List<Long>) = customMangaRepository.deleteBulkCustomManga(mangaIds)
10+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package dev.yokai.domain.library.custom.interactor
2+
3+
import dev.yokai.domain.library.custom.CustomMangaRepository
4+
5+
class GetCustomManga(
6+
private val customMangaRepository: CustomMangaRepository,
7+
) {
8+
fun subscribeAll() = customMangaRepository.subscribeAll()
9+
10+
suspend fun getAll() = customMangaRepository.getAll()
11+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package dev.yokai.domain.library.custom.model
2+
3+
import eu.kanade.tachiyomi.data.database.models.Manga
4+
import eu.kanade.tachiyomi.data.database.models.MangaImpl
5+
6+
data class CustomMangaInfo(
7+
var mangaId: Long,
8+
val title: String? = null,
9+
val author: String? = null,
10+
val artist: String? = null,
11+
val description: String? = null,
12+
val genre: String? = null,
13+
val status: Int? = null,
14+
) {
15+
fun toManga() = MangaImpl().apply {
16+
id = this@CustomMangaInfo.mangaId
17+
title = this@CustomMangaInfo.title ?: ""
18+
author = this@CustomMangaInfo.author
19+
artist = this@CustomMangaInfo.artist
20+
description = this@CustomMangaInfo.description
21+
genre = this@CustomMangaInfo.genre
22+
status = this@CustomMangaInfo.status ?: -1
23+
}
24+
25+
companion object {
26+
fun Manga.getMangaInfo() =
27+
CustomMangaInfo(
28+
mangaId = id!!,
29+
title = title,
30+
author = author,
31+
artist = artist,
32+
description = description,
33+
genre = genre,
34+
status = status,
35+
)
36+
}
37+
}

app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.data.backup
22

33
import android.content.Context
44
import android.net.Uri
5+
import dev.yokai.domain.library.custom.model.CustomMangaInfo
56
import dev.yokai.domain.ui.settings.ReaderPreferences
67
import dev.yokai.domain.ui.settings.ReaderPreferences.CutoutBehaviour
78
import eu.kanade.tachiyomi.R
@@ -37,6 +38,7 @@ import eu.kanade.tachiyomi.util.BackupUtil
3738
import eu.kanade.tachiyomi.util.chapter.ChapterUtil
3839
import eu.kanade.tachiyomi.util.manga.MangaUtil
3940
import eu.kanade.tachiyomi.util.system.createFileInCacheDir
41+
import eu.kanade.tachiyomi.util.system.launchNow
4042
import kotlinx.coroutines.coroutineScope
4143
import kotlinx.coroutines.isActive
4244
import kotlinx.serialization.protobuf.ProtoBuf
@@ -198,7 +200,7 @@ class BackupRestorer(val context: Context, val notifier: BackupNotifier) {
198200
tracks: List<Track>,
199201
backupCategories: List<BackupCategory>,
200202
filteredScanlators: List<String>,
201-
customManga: CustomMangaManager.ComicList.ComicInfoYokai?,
203+
customManga: CustomMangaInfo?,
202204
) {
203205
val fetchedManga = manga.also {
204206
it.initialized = it.description != null
@@ -218,7 +220,7 @@ class BackupRestorer(val context: Context, val notifier: BackupNotifier) {
218220
tracks: List<Track>,
219221
backupCategories: List<BackupCategory>,
220222
filteredScanlators: List<String>,
221-
customManga: CustomMangaManager.ComicList.ComicInfoYokai?,
223+
customManga: CustomMangaInfo?,
222224
) {
223225
restoreChapters(backupManga, chapters)
224226
restoreExtras(backupManga, categories, history, tracks, backupCategories, filteredScanlators, customManga)
@@ -258,14 +260,18 @@ class BackupRestorer(val context: Context, val notifier: BackupNotifier) {
258260
tracks: List<Track>,
259261
backupCategories: List<BackupCategory>,
260262
filteredScanlators: List<String>,
261-
customManga: CustomMangaManager.ComicList.ComicInfoYokai?,
263+
customManga: CustomMangaInfo?,
262264
) {
263265
restoreCategories(manga, categories, backupCategories)
264266
restoreHistoryForManga(history)
265267
restoreTrackForManga(manga, tracks)
266268
restoreFilteredScanlatorsForManga(manga, filteredScanlators)
267-
customManga?.id = manga.id!!
268-
customManga?.let { customMangaManager.saveMangaInfo(it) }
269+
customManga?.let {
270+
it.mangaId = manga.id!!
271+
launchNow {
272+
customMangaManager.saveMangaInfo(it)
273+
}
274+
}
269275
}
270276

271277
/**

0 commit comments

Comments
 (0)