Remove SourceData and use StubSource directly for database (#9429)

This commit is contained in:
Andreas 2023-05-03 16:33:05 +02:00 committed by GitHub
parent b328f0e344
commit f63573f25f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 81 additions and 97 deletions

View file

@ -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()) }

View file

@ -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()

View file

@ -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,
)
}

View file

@ -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,
)
}
}

View file

@ -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, "", "")
}
}

View file

@ -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>()

View file

@ -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)
}

View file

@ -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) }
}
}

View file

@ -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()
}

View file

@ -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()
}
}

View file

@ -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)
}

View file

@ -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)
}