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.history.HistoryRepositoryImpl
import tachiyomi.data.manga.MangaRepositoryImpl import tachiyomi.data.manga.MangaRepositoryImpl
import tachiyomi.data.release.ReleaseServiceImpl import tachiyomi.data.release.ReleaseServiceImpl
import tachiyomi.data.source.SourceDataRepositoryImpl
import tachiyomi.data.source.SourceRepositoryImpl import tachiyomi.data.source.SourceRepositoryImpl
import tachiyomi.data.source.StubSourceRepositoryImpl
import tachiyomi.data.track.TrackRepositoryImpl import tachiyomi.data.track.TrackRepositoryImpl
import tachiyomi.data.updates.UpdatesRepositoryImpl import tachiyomi.data.updates.UpdatesRepositoryImpl
import tachiyomi.domain.category.interactor.CreateCategoryWithName 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.release.service.ReleaseService
import tachiyomi.domain.source.interactor.GetRemoteManga import tachiyomi.domain.source.interactor.GetRemoteManga
import tachiyomi.domain.source.interactor.GetSourcesWithNonLibraryManga import tachiyomi.domain.source.interactor.GetSourcesWithNonLibraryManga
import tachiyomi.domain.source.repository.SourceDataRepository
import tachiyomi.domain.source.repository.SourceRepository import tachiyomi.domain.source.repository.SourceRepository
import tachiyomi.domain.source.repository.StubSourceRepository
import tachiyomi.domain.track.interactor.DeleteTrack import tachiyomi.domain.track.interactor.DeleteTrack
import tachiyomi.domain.track.interactor.GetTracks import tachiyomi.domain.track.interactor.GetTracks
import tachiyomi.domain.track.interactor.GetTracksPerManga import tachiyomi.domain.track.interactor.GetTracksPerManga
@ -139,7 +139,7 @@ class DomainModule : InjektModule {
addFactory { GetUpdates(get()) } addFactory { GetUpdates(get()) }
addSingletonFactory<SourceRepository> { SourceRepositoryImpl(get(), get()) } addSingletonFactory<SourceRepository> { SourceRepositoryImpl(get(), get()) }
addSingletonFactory<SourceDataRepository> { SourceDataRepositoryImpl(get()) } addSingletonFactory<StubSourceRepository> { StubSourceRepositoryImpl(get()) }
addFactory { GetEnabledSources(get(), get()) } addFactory { GetEnabledSources(get(), get()) }
addFactory { GetLanguagesWithSources(get(), get()) } addFactory { GetLanguagesWithSources(get(), get()) }
addFactory { GetRemoteManga(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.domain.source.service.SourcePreferences
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi 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.Extension
import eu.kanade.tachiyomi.extension.model.InstallStep import eu.kanade.tachiyomi.extension.model.InstallStep
import eu.kanade.tachiyomi.extension.model.LoadResult 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.launchNow
import tachiyomi.core.util.lang.withUIContext import tachiyomi.core.util.lang.withUIContext
import tachiyomi.core.util.system.logcat 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.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.Locale import java.util.Locale
@ -73,12 +72,12 @@ class ExtensionManager(
private val _availableExtensionsFlow = MutableStateFlow(emptyList<Extension.Available>()) private val _availableExtensionsFlow = MutableStateFlow(emptyList<Extension.Available>())
val availableExtensionsFlow = _availableExtensionsFlow.asStateFlow() 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>) { private fun setupAvailableExtensionsSourcesDataMap(extensions: List<Extension.Available>) {
if (extensions.isEmpty()) return if (extensions.isEmpty()) return
availableExtensionsSourcesData = extensions availableExtensionsSourcesData = extensions
.flatMap { ext -> ext.sources.map { it.toSourceData() } } .flatMap { ext -> ext.sources.map { it.toStubSource() } }
.associateBy { it.id } .associateBy { it.id }
} }
@ -145,8 +144,8 @@ class ExtensionManager(
// Use the source lang as some aren't present on the extension level. // Use the source lang as some aren't present on the extension level.
val availableLanguages = extensions val availableLanguages = extensions
.flatMap(Extension.Available::sources) .flatMap(Extension.Available::sources)
.distinctBy(AvailableSources::lang) .distinctBy(Extension.Available.Source::lang)
.map(AvailableSources::lang) .map(Extension.Available.Source::lang)
val deviceLanguage = Locale.getDefault().language val deviceLanguage = Locale.getDefault().language
val defaultLanguages = preferences.enabledLanguages().defaultValue() val defaultLanguages = preferences.enabledLanguages().defaultValue()

View file

@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.extension.api
import android.content.Context import android.content.Context
import eu.kanade.tachiyomi.extension.ExtensionManager 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.Extension
import eu.kanade.tachiyomi.extension.model.LoadResult import eu.kanade.tachiyomi.extension.model.LoadResult
import eu.kanade.tachiyomi.extension.util.ExtensionLoader import eu.kanade.tachiyomi.extension.util.ExtensionLoader
@ -124,24 +123,13 @@ internal class ExtensionGithubApi {
isNsfw = it.nsfw == 1, isNsfw = it.nsfw == 1,
hasReadme = it.hasReadme == 1, hasReadme = it.hasReadme == 1,
hasChangelog = it.hasChangelog == 1, hasChangelog = it.hasChangelog == 1,
sources = it.sources?.toExtensionSources().orEmpty(), sources = it.sources?.map(extensionSourceMapper).orEmpty(),
apkName = it.apk, apkName = it.apk,
iconUrl = "${getUrlPrefix()}icon/${it.apk.replace(".apk", ".png")}", 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 { fun getApkUrl(extension: Extension.Available): String {
return "${getUrlPrefix()}apk/${extension.apkName}" return "${getUrlPrefix()}apk/${extension.apkName}"
} }
@ -183,3 +171,12 @@ private data class ExtensionSourceJsonObject(
val name: String, val name: String,
val baseUrl: 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 android.graphics.drawable.Drawable
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
import tachiyomi.domain.source.model.SourceData import tachiyomi.domain.source.model.StubSource
sealed class Extension { sealed class Extension {
@ -44,10 +44,26 @@ sealed class Extension {
override val isNsfw: Boolean, override val isNsfw: Boolean,
override val hasReadme: Boolean, override val hasReadme: Boolean,
override val hasChangelog: Boolean, override val hasChangelog: Boolean,
val sources: List<AvailableSources>, val sources: List<Source>,
val apkName: String, val apkName: String,
val iconUrl: 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( data class Untrusted(
override val name: String, override val name: String,
@ -62,18 +78,3 @@ sealed class Extension {
override val hasChangelog: Boolean = false, override val hasChangelog: Boolean = false,
) : Extension() ) : 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.flow.map
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import tachiyomi.domain.source.model.SourceData
import tachiyomi.domain.source.model.StubSource 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.domain.source.service.SourceManager
import tachiyomi.source.local.LocalSource import tachiyomi.source.local.LocalSource
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
@ -26,7 +25,7 @@ import java.util.concurrent.ConcurrentHashMap
class AndroidSourceManager( class AndroidSourceManager(
private val context: Context, private val context: Context,
private val extensionManager: ExtensionManager, private val extensionManager: ExtensionManager,
private val sourceRepository: SourceDataRepository, private val sourceRepository: StubSourceRepository,
) : SourceManager { ) : SourceManager {
private val downloadManager: DownloadManager by injectLazy() private val downloadManager: DownloadManager by injectLazy()
@ -55,7 +54,7 @@ class AndroidSourceManager(
extensions.forEach { extension -> extensions.forEach { extension ->
extension.sources.forEach { extension.sources.forEach {
mutableMap[it.id] = it mutableMap[it.id] = it
registerStubSource(it.toSourceData()) registerStubSource(it.toStubSource())
} }
} }
sourcesMapFlow.value = mutableMap sourcesMapFlow.value = mutableMap
@ -67,7 +66,7 @@ class AndroidSourceManager(
.collectLatest { sources -> .collectLatest { sources ->
val mutableMap = stubSourcesMap.toMutableMap() val mutableMap = stubSourcesMap.toMutableMap()
sources.forEach { 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 } return stubSourcesMap.values.filterNot { it.id in onlineSourceIds }
} }
private fun registerStubSource(sourceData: SourceData) { private fun registerStubSource(source: StubSource) {
scope.launch { scope.launch {
val (id, lang, name) = sourceData val dbSource = sourceRepository.getStubSource(source.id)
val dbSourceData = sourceRepository.getSourceData(id) if (dbSource == source) return@launch
if (dbSourceData == sourceData) return@launch sourceRepository.upsertStubSource(source.id, source.lang, source.name)
sourceRepository.upsertSourceData(id, lang, name) if (dbSource != null) {
if (dbSourceData != null) { downloadManager.renameSource(dbSource, source)
downloadManager.renameSource(StubSource(dbSourceData), StubSource(sourceData))
} }
} }
} }
private suspend fun createStubSource(id: Long): StubSource { private suspend fun createStubSource(id: Long): StubSource {
sourceRepository.getSourceData(id)?.let { sourceRepository.getStubSource(id)?.let {
return StubSource(it) return it
} }
extensionManager.getSourceData(id)?.let { extensionManager.getSourceData(id)?.let {
registerStubSource(it) 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 android.graphics.drawable.Drawable
import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.tachiyomi.extension.ExtensionManager import eu.kanade.tachiyomi.extension.ExtensionManager
import tachiyomi.domain.source.model.SourceData
import tachiyomi.domain.source.model.StubSource import tachiyomi.domain.source.model.StubSource
import tachiyomi.source.local.isLocal import tachiyomi.source.local.isLocal
import uy.kohesive.injekt.Injekt 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.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 { fun Source.getNameForMangaInfo(): String {
val preferences = Injekt.get<SourcePreferences>() val preferences = Injekt.get<SourcePreferences>()

View file

@ -1,7 +1,7 @@
package tachiyomi.data.source package tachiyomi.data.source
import tachiyomi.domain.source.model.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 -> val sourceMapper: (eu.kanade.tachiyomi.source.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 -> val sourceDataMapper: (Long, String, String) -> StubSource = { id, lang, name ->
SourceData(id, lang, name) StubSource(id, lang, name)
} }

View file

@ -2,22 +2,22 @@ package tachiyomi.data.source
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import tachiyomi.data.DatabaseHandler import tachiyomi.data.DatabaseHandler
import tachiyomi.domain.source.model.SourceData import tachiyomi.domain.source.model.StubSource
import tachiyomi.domain.source.repository.SourceDataRepository import tachiyomi.domain.source.repository.StubSourceRepository
class SourceDataRepositoryImpl( class StubSourceRepositoryImpl(
private val handler: DatabaseHandler, private val handler: DatabaseHandler,
) : SourceDataRepository { ) : StubSourceRepository {
override fun subscribeAll(): Flow<List<SourceData>> { override fun subscribeAll(): Flow<List<StubSource>> {
return handler.subscribeToList { sourcesQueries.findAll(sourceDataMapper) } 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) } 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) } 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 import rx.Observable
@Suppress("OverridingDeprecatedMember") @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 val isInvalid: Boolean = name.isBlank() || lang.isBlank()
override val name: String = sourceData.name.ifBlank { id.toString() }
override val lang: String = sourceData.lang
override suspend fun getMangaDetails(manga: SManga): SManga { override suspend fun getMangaDetails(manga: SManga): SManga {
throw SourceNotInstalledException() throw SourceNotInstalledException()
@ -43,7 +43,7 @@ class StubSource(private val sourceData: SourceData) : Source {
} }
override fun toString(): String { 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)
}