Remove SourceData and use StubSource directly for database (#9429)
This commit is contained in:
parent
b328f0e344
commit
f63573f25f
12 changed files with 81 additions and 97 deletions
|
@ -21,8 +21,8 @@ import tachiyomi.data.chapter.ChapterRepositoryImpl
|
|||
import tachiyomi.data.history.HistoryRepositoryImpl
|
||||
import tachiyomi.data.manga.MangaRepositoryImpl
|
||||
import tachiyomi.data.release.ReleaseServiceImpl
|
||||
import tachiyomi.data.source.SourceDataRepositoryImpl
|
||||
import tachiyomi.data.source.SourceRepositoryImpl
|
||||
import tachiyomi.data.source.StubSourceRepositoryImpl
|
||||
import tachiyomi.data.track.TrackRepositoryImpl
|
||||
import tachiyomi.data.updates.UpdatesRepositoryImpl
|
||||
import tachiyomi.domain.category.interactor.CreateCategoryWithName
|
||||
|
@ -61,8 +61,8 @@ import tachiyomi.domain.release.interactor.GetApplicationRelease
|
|||
import tachiyomi.domain.release.service.ReleaseService
|
||||
import tachiyomi.domain.source.interactor.GetRemoteManga
|
||||
import tachiyomi.domain.source.interactor.GetSourcesWithNonLibraryManga
|
||||
import tachiyomi.domain.source.repository.SourceDataRepository
|
||||
import tachiyomi.domain.source.repository.SourceRepository
|
||||
import tachiyomi.domain.source.repository.StubSourceRepository
|
||||
import tachiyomi.domain.track.interactor.DeleteTrack
|
||||
import tachiyomi.domain.track.interactor.GetTracks
|
||||
import tachiyomi.domain.track.interactor.GetTracksPerManga
|
||||
|
@ -139,7 +139,7 @@ class DomainModule : InjektModule {
|
|||
addFactory { GetUpdates(get()) }
|
||||
|
||||
addSingletonFactory<SourceRepository> { SourceRepositoryImpl(get(), get()) }
|
||||
addSingletonFactory<SourceDataRepository> { SourceDataRepositoryImpl(get()) }
|
||||
addSingletonFactory<StubSourceRepository> { StubSourceRepositoryImpl(get()) }
|
||||
addFactory { GetEnabledSources(get(), get()) }
|
||||
addFactory { GetLanguagesWithSources(get(), get()) }
|
||||
addFactory { GetRemoteManga(get()) }
|
||||
|
|
|
@ -5,7 +5,6 @@ import android.graphics.drawable.Drawable
|
|||
import eu.kanade.domain.source.service.SourcePreferences
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi
|
||||
import eu.kanade.tachiyomi.extension.model.AvailableSources
|
||||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
import eu.kanade.tachiyomi.extension.model.InstallStep
|
||||
import eu.kanade.tachiyomi.extension.model.LoadResult
|
||||
|
@ -22,7 +21,7 @@ import rx.Observable
|
|||
import tachiyomi.core.util.lang.launchNow
|
||||
import tachiyomi.core.util.lang.withUIContext
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.source.model.SourceData
|
||||
import tachiyomi.domain.source.model.StubSource
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.Locale
|
||||
|
@ -73,12 +72,12 @@ class ExtensionManager(
|
|||
private val _availableExtensionsFlow = MutableStateFlow(emptyList<Extension.Available>())
|
||||
val availableExtensionsFlow = _availableExtensionsFlow.asStateFlow()
|
||||
|
||||
private var availableExtensionsSourcesData: Map<Long, SourceData> = emptyMap()
|
||||
private var availableExtensionsSourcesData: Map<Long, StubSource> = emptyMap()
|
||||
|
||||
private fun setupAvailableExtensionsSourcesDataMap(extensions: List<Extension.Available>) {
|
||||
if (extensions.isEmpty()) return
|
||||
availableExtensionsSourcesData = extensions
|
||||
.flatMap { ext -> ext.sources.map { it.toSourceData() } }
|
||||
.flatMap { ext -> ext.sources.map { it.toStubSource() } }
|
||||
.associateBy { it.id }
|
||||
}
|
||||
|
||||
|
@ -145,8 +144,8 @@ class ExtensionManager(
|
|||
// Use the source lang as some aren't present on the extension level.
|
||||
val availableLanguages = extensions
|
||||
.flatMap(Extension.Available::sources)
|
||||
.distinctBy(AvailableSources::lang)
|
||||
.map(AvailableSources::lang)
|
||||
.distinctBy(Extension.Available.Source::lang)
|
||||
.map(Extension.Available.Source::lang)
|
||||
|
||||
val deviceLanguage = Locale.getDefault().language
|
||||
val defaultLanguages = preferences.enabledLanguages().defaultValue()
|
||||
|
|
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.extension.api
|
|||
|
||||
import android.content.Context
|
||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||
import eu.kanade.tachiyomi.extension.model.AvailableSources
|
||||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
import eu.kanade.tachiyomi.extension.model.LoadResult
|
||||
import eu.kanade.tachiyomi.extension.util.ExtensionLoader
|
||||
|
@ -124,24 +123,13 @@ internal class ExtensionGithubApi {
|
|||
isNsfw = it.nsfw == 1,
|
||||
hasReadme = it.hasReadme == 1,
|
||||
hasChangelog = it.hasChangelog == 1,
|
||||
sources = it.sources?.toExtensionSources().orEmpty(),
|
||||
sources = it.sources?.map(extensionSourceMapper).orEmpty(),
|
||||
apkName = it.apk,
|
||||
iconUrl = "${getUrlPrefix()}icon/${it.apk.replace(".apk", ".png")}",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<ExtensionSourceJsonObject>.toExtensionSources(): List<AvailableSources> {
|
||||
return this.map {
|
||||
AvailableSources(
|
||||
id = it.id,
|
||||
lang = it.lang,
|
||||
name = it.name,
|
||||
baseUrl = it.baseUrl,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun getApkUrl(extension: Extension.Available): String {
|
||||
return "${getUrlPrefix()}apk/${extension.apkName}"
|
||||
}
|
||||
|
@ -183,3 +171,12 @@ private data class ExtensionSourceJsonObject(
|
|||
val name: String,
|
||||
val baseUrl: String,
|
||||
)
|
||||
|
||||
private val extensionSourceMapper: (ExtensionSourceJsonObject) -> Extension.Available.Source = {
|
||||
Extension.Available.Source(
|
||||
id = it.id,
|
||||
lang = it.lang,
|
||||
name = it.name,
|
||||
baseUrl = it.baseUrl,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.extension.model
|
|||
|
||||
import android.graphics.drawable.Drawable
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import tachiyomi.domain.source.model.SourceData
|
||||
import tachiyomi.domain.source.model.StubSource
|
||||
|
||||
sealed class Extension {
|
||||
|
||||
|
@ -44,10 +44,26 @@ sealed class Extension {
|
|||
override val isNsfw: Boolean,
|
||||
override val hasReadme: Boolean,
|
||||
override val hasChangelog: Boolean,
|
||||
val sources: List<AvailableSources>,
|
||||
val sources: List<Source>,
|
||||
val apkName: String,
|
||||
val iconUrl: String,
|
||||
) : Extension()
|
||||
) : Extension() {
|
||||
|
||||
data class Source(
|
||||
val id: Long,
|
||||
val lang: String,
|
||||
val name: String,
|
||||
val baseUrl: String,
|
||||
) {
|
||||
fun toStubSource(): StubSource {
|
||||
return StubSource(
|
||||
id = this.id,
|
||||
lang = this.lang,
|
||||
name = this.name,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class Untrusted(
|
||||
override val name: String,
|
||||
|
@ -62,18 +78,3 @@ sealed class Extension {
|
|||
override val hasChangelog: Boolean = false,
|
||||
) : Extension()
|
||||
}
|
||||
|
||||
data class AvailableSources(
|
||||
val id: Long,
|
||||
val lang: String,
|
||||
val name: String,
|
||||
val baseUrl: String,
|
||||
) {
|
||||
fun toSourceData(): SourceData {
|
||||
return SourceData(
|
||||
id = this.id,
|
||||
lang = this.lang,
|
||||
name = this.name,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,9 +13,8 @@ import kotlinx.coroutines.flow.collectLatest
|
|||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import tachiyomi.domain.source.model.SourceData
|
||||
import tachiyomi.domain.source.model.StubSource
|
||||
import tachiyomi.domain.source.repository.SourceDataRepository
|
||||
import tachiyomi.domain.source.repository.StubSourceRepository
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.source.local.LocalSource
|
||||
import uy.kohesive.injekt.Injekt
|
||||
|
@ -26,7 +25,7 @@ import java.util.concurrent.ConcurrentHashMap
|
|||
class AndroidSourceManager(
|
||||
private val context: Context,
|
||||
private val extensionManager: ExtensionManager,
|
||||
private val sourceRepository: SourceDataRepository,
|
||||
private val sourceRepository: StubSourceRepository,
|
||||
) : SourceManager {
|
||||
|
||||
private val downloadManager: DownloadManager by injectLazy()
|
||||
|
@ -55,7 +54,7 @@ class AndroidSourceManager(
|
|||
extensions.forEach { extension ->
|
||||
extension.sources.forEach {
|
||||
mutableMap[it.id] = it
|
||||
registerStubSource(it.toSourceData())
|
||||
registerStubSource(it.toStubSource())
|
||||
}
|
||||
}
|
||||
sourcesMapFlow.value = mutableMap
|
||||
|
@ -67,7 +66,7 @@ class AndroidSourceManager(
|
|||
.collectLatest { sources ->
|
||||
val mutableMap = stubSourcesMap.toMutableMap()
|
||||
sources.forEach {
|
||||
mutableMap[it.id] = StubSource(it)
|
||||
mutableMap[it.id] = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -92,26 +91,25 @@ class AndroidSourceManager(
|
|||
return stubSourcesMap.values.filterNot { it.id in onlineSourceIds }
|
||||
}
|
||||
|
||||
private fun registerStubSource(sourceData: SourceData) {
|
||||
private fun registerStubSource(source: StubSource) {
|
||||
scope.launch {
|
||||
val (id, lang, name) = sourceData
|
||||
val dbSourceData = sourceRepository.getSourceData(id)
|
||||
if (dbSourceData == sourceData) return@launch
|
||||
sourceRepository.upsertSourceData(id, lang, name)
|
||||
if (dbSourceData != null) {
|
||||
downloadManager.renameSource(StubSource(dbSourceData), StubSource(sourceData))
|
||||
val dbSource = sourceRepository.getStubSource(source.id)
|
||||
if (dbSource == source) return@launch
|
||||
sourceRepository.upsertStubSource(source.id, source.lang, source.name)
|
||||
if (dbSource != null) {
|
||||
downloadManager.renameSource(dbSource, source)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun createStubSource(id: Long): StubSource {
|
||||
sourceRepository.getSourceData(id)?.let {
|
||||
return StubSource(it)
|
||||
sourceRepository.getStubSource(id)?.let {
|
||||
return it
|
||||
}
|
||||
extensionManager.getSourceData(id)?.let {
|
||||
registerStubSource(it)
|
||||
return StubSource(it)
|
||||
return it
|
||||
}
|
||||
return StubSource(SourceData(id, "", ""))
|
||||
return StubSource(id, "", "")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.source
|
|||
import android.graphics.drawable.Drawable
|
||||
import eu.kanade.domain.source.service.SourcePreferences
|
||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||
import tachiyomi.domain.source.model.SourceData
|
||||
import tachiyomi.domain.source.model.StubSource
|
||||
import tachiyomi.source.local.isLocal
|
||||
import uy.kohesive.injekt.Injekt
|
||||
|
@ -13,7 +12,7 @@ fun Source.icon(): Drawable? = Injekt.get<ExtensionManager>().getAppIconForSourc
|
|||
|
||||
fun Source.getPreferenceKey(): String = "source_$id"
|
||||
|
||||
fun Source.toSourceData(): SourceData = SourceData(id = id, lang = lang, name = name)
|
||||
fun Source.toStubSource(): StubSource = StubSource(id = id, lang = lang, name = name)
|
||||
|
||||
fun Source.getNameForMangaInfo(): String {
|
||||
val preferences = Injekt.get<SourcePreferences>()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package tachiyomi.data.source
|
||||
|
||||
import tachiyomi.domain.source.model.Source
|
||||
import tachiyomi.domain.source.model.SourceData
|
||||
import tachiyomi.domain.source.model.StubSource
|
||||
|
||||
val sourceMapper: (eu.kanade.tachiyomi.source.Source) -> Source = { source ->
|
||||
Source(
|
||||
|
@ -13,6 +13,6 @@ val sourceMapper: (eu.kanade.tachiyomi.source.Source) -> Source = { source ->
|
|||
)
|
||||
}
|
||||
|
||||
val sourceDataMapper: (Long, String, String) -> SourceData = { id, lang, name ->
|
||||
SourceData(id, lang, name)
|
||||
val sourceDataMapper: (Long, String, String) -> StubSource = { id, lang, name ->
|
||||
StubSource(id, lang, name)
|
||||
}
|
||||
|
|
|
@ -2,22 +2,22 @@ package tachiyomi.data.source
|
|||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import tachiyomi.data.DatabaseHandler
|
||||
import tachiyomi.domain.source.model.SourceData
|
||||
import tachiyomi.domain.source.repository.SourceDataRepository
|
||||
import tachiyomi.domain.source.model.StubSource
|
||||
import tachiyomi.domain.source.repository.StubSourceRepository
|
||||
|
||||
class SourceDataRepositoryImpl(
|
||||
class StubSourceRepositoryImpl(
|
||||
private val handler: DatabaseHandler,
|
||||
) : SourceDataRepository {
|
||||
) : StubSourceRepository {
|
||||
|
||||
override fun subscribeAll(): Flow<List<SourceData>> {
|
||||
override fun subscribeAll(): Flow<List<StubSource>> {
|
||||
return handler.subscribeToList { sourcesQueries.findAll(sourceDataMapper) }
|
||||
}
|
||||
|
||||
override suspend fun getSourceData(id: Long): SourceData? {
|
||||
override suspend fun getStubSource(id: Long): StubSource? {
|
||||
return handler.awaitOneOrNull { sourcesQueries.findOne(id, sourceDataMapper) }
|
||||
}
|
||||
|
||||
override suspend fun upsertSourceData(id: Long, lang: String, name: String) {
|
||||
override suspend fun upsertStubSource(id: Long, lang: String, name: String) {
|
||||
handler.await { sourcesQueries.upsert(id, lang, name) }
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package tachiyomi.domain.source.model
|
||||
|
||||
data class SourceData(
|
||||
val id: Long,
|
||||
val lang: String,
|
||||
val name: String,
|
||||
) {
|
||||
|
||||
val isMissingInfo: Boolean = name.isBlank() || lang.isBlank()
|
||||
}
|
|
@ -7,13 +7,13 @@ import eu.kanade.tachiyomi.source.model.SManga
|
|||
import rx.Observable
|
||||
|
||||
@Suppress("OverridingDeprecatedMember")
|
||||
class StubSource(private val sourceData: SourceData) : Source {
|
||||
class StubSource(
|
||||
override val id: Long,
|
||||
override val name: String,
|
||||
override val lang: String,
|
||||
) : Source {
|
||||
|
||||
override val id: Long = sourceData.id
|
||||
|
||||
override val name: String = sourceData.name.ifBlank { id.toString() }
|
||||
|
||||
override val lang: String = sourceData.lang
|
||||
val isInvalid: Boolean = name.isBlank() || lang.isBlank()
|
||||
|
||||
override suspend fun getMangaDetails(manga: SManga): SManga {
|
||||
throw SourceNotInstalledException()
|
||||
|
@ -43,7 +43,7 @@ class StubSource(private val sourceData: SourceData) : Source {
|
|||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return if (sourceData.isMissingInfo.not()) "$name (${lang.uppercase()})" else id.toString()
|
||||
return if (isInvalid.not()) "$name (${lang.uppercase()})" else id.toString()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
package tachiyomi.domain.source.repository
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import tachiyomi.domain.source.model.SourceData
|
||||
|
||||
interface SourceDataRepository {
|
||||
fun subscribeAll(): Flow<List<SourceData>>
|
||||
|
||||
suspend fun getSourceData(id: Long): SourceData?
|
||||
|
||||
suspend fun upsertSourceData(id: Long, lang: String, name: String)
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package tachiyomi.domain.source.repository
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import tachiyomi.domain.source.model.StubSource
|
||||
|
||||
interface StubSourceRepository {
|
||||
fun subscribeAll(): Flow<List<StubSource>>
|
||||
|
||||
suspend fun getStubSource(id: Long): StubSource?
|
||||
|
||||
suspend fun upsertStubSource(id: Long, lang: String, name: String)
|
||||
}
|
Reference in a new issue