Merge branch 'master' into Failed-Updates-feature-added
This commit is contained in:
commit
c0801a20d1
26 changed files with 153 additions and 169 deletions
|
@ -194,7 +194,7 @@ dependencies {
|
|||
implementation(androidx.bundles.workmanager)
|
||||
|
||||
// RxJava
|
||||
implementation(libs.bundles.reactivex)
|
||||
implementation(libs.rxjava)
|
||||
implementation(libs.flowreactivenetwork)
|
||||
|
||||
// Networking
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
}
|
||||
|
||||
-keepclassmembers class * implements android.os.Parcelable {
|
||||
public static final ** CREATOR;
|
||||
public static final ** CREATOR;
|
||||
}
|
||||
|
||||
-keep class androidx.annotation.Keep
|
||||
|
|
2
app/proguard-rules.pro
vendored
2
app/proguard-rules.pro
vendored
|
@ -11,8 +11,8 @@
|
|||
-keep,allowoptimization class kotlin.time.** { public protected *; }
|
||||
-keep,allowoptimization class okhttp3.** { public protected *; }
|
||||
-keep,allowoptimization class okio.** { public protected *; }
|
||||
-keep,allowoptimization class rx.** { public protected *; }
|
||||
-keep,allowoptimization class org.jsoup.** { public protected *; }
|
||||
-keep,allowoptimization class rx.** { public protected *; }
|
||||
-keep,allowoptimization class app.cash.quickjs.** { public protected *; }
|
||||
-keep,allowoptimization class uy.kohesive.injekt.** { public protected *; }
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import eu.kanade.domain.source.interactor.SetMigrateSorting
|
|||
import eu.kanade.domain.source.interactor.ToggleLanguage
|
||||
import eu.kanade.domain.source.interactor.ToggleSource
|
||||
import eu.kanade.domain.source.interactor.ToggleSourcePin
|
||||
import eu.kanade.domain.track.interactor.RefreshTracks
|
||||
import eu.kanade.domain.track.interactor.TrackChapter
|
||||
import tachiyomi.data.category.CategoryRepositoryImpl
|
||||
import tachiyomi.data.chapter.ChapterRepositoryImpl
|
||||
|
@ -115,6 +116,7 @@ class DomainModule : InjektModule {
|
|||
|
||||
addSingletonFactory<TrackRepository> { TrackRepositoryImpl(get()) }
|
||||
addFactory { TrackChapter(get(), get(), get(), get()) }
|
||||
addFactory { RefreshTracks(get(), get(), get(), get()) }
|
||||
addFactory { DeleteTrack(get()) }
|
||||
addFactory { GetTracksPerManga(get()) }
|
||||
addFactory { GetTracks(get()) }
|
||||
|
@ -127,7 +129,7 @@ class DomainModule : InjektModule {
|
|||
addFactory { SetReadStatus(get(), get(), get(), get()) }
|
||||
addFactory { ShouldUpdateDbChapter() }
|
||||
addFactory { SyncChaptersWithSource(get(), get(), get(), get(), get(), get(), get()) }
|
||||
addFactory { SyncChaptersWithTrackServiceTwoWay(get(), get()) }
|
||||
addFactory { SyncChaptersWithTrackServiceTwoWay(get(), get(), get()) }
|
||||
|
||||
addSingletonFactory<HistoryRepository> { HistoryRepositoryImpl(get()) }
|
||||
addFactory { GetHistory(get()) }
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package eu.kanade.domain.chapter.interactor
|
||||
|
||||
import eu.kanade.domain.track.model.toDbTrack
|
||||
import eu.kanade.tachiyomi.data.track.EnhancedTrackService
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.chapter.interactor.GetChapterByMangaId
|
||||
import tachiyomi.domain.chapter.interactor.UpdateChapter
|
||||
import tachiyomi.domain.chapter.model.Chapter
|
||||
import tachiyomi.domain.chapter.model.toChapterUpdate
|
||||
import tachiyomi.domain.track.interactor.InsertTrack
|
||||
import tachiyomi.domain.track.model.Track
|
||||
|
@ -13,14 +14,22 @@ import tachiyomi.domain.track.model.Track
|
|||
class SyncChaptersWithTrackServiceTwoWay(
|
||||
private val updateChapter: UpdateChapter,
|
||||
private val insertTrack: InsertTrack,
|
||||
private val getChapterByMangaId: GetChapterByMangaId,
|
||||
) {
|
||||
|
||||
suspend fun await(
|
||||
chapters: List<Chapter>,
|
||||
mangaId: Long,
|
||||
remoteTrack: Track,
|
||||
service: TrackService,
|
||||
) {
|
||||
val sortedChapters = chapters.sortedBy { it.chapterNumber }
|
||||
if (service !is EnhancedTrackService) {
|
||||
return
|
||||
}
|
||||
|
||||
val sortedChapters = getChapterByMangaId.await(mangaId)
|
||||
.sortedBy { it.chapterNumber }
|
||||
.filter { it.isRecognizedNumber }
|
||||
|
||||
val chapterUpdates = sortedChapters
|
||||
.filter { chapter -> chapter.chapterNumber <= remoteTrack.lastChapterRead && !chapter.read }
|
||||
.map { it.copy(read = true).toChapterUpdate() }
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package eu.kanade.domain.track.interactor
|
||||
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.track.model.toDbTrack
|
||||
import eu.kanade.domain.track.model.toDomainTrack
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.track.interactor.GetTracks
|
||||
import tachiyomi.domain.track.interactor.InsertTrack
|
||||
|
||||
class RefreshTracks(
|
||||
private val getTracks: GetTracks,
|
||||
private val trackManager: TrackManager,
|
||||
private val insertTrack: InsertTrack,
|
||||
private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay,
|
||||
) {
|
||||
|
||||
suspend fun await(mangaId: Long) {
|
||||
supervisorScope {
|
||||
getTracks.await(mangaId)
|
||||
.map { track ->
|
||||
async {
|
||||
val service = trackManager.getService(track.syncId)
|
||||
if (service != null && service.isLoggedIn) {
|
||||
try {
|
||||
val updatedTrack = service.refresh(track.toDbTrack())
|
||||
insertTrack.await(updatedTrack.toDomainTrack()!!)
|
||||
syncChaptersWithTrackServiceTwoWay.await(mangaId, track, service)
|
||||
} catch (e: Throwable) {
|
||||
// Ignore errors and continue
|
||||
logcat(LogPriority.ERROR, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,33 +24,31 @@ class TrackChapter(
|
|||
suspend fun await(context: Context, mangaId: Long, chapterNumber: Double) = coroutineScope {
|
||||
launchNonCancellable {
|
||||
val tracks = getTracks.await(mangaId)
|
||||
|
||||
if (tracks.isEmpty()) return@launchNonCancellable
|
||||
|
||||
tracks.mapNotNull { track ->
|
||||
val service = trackManager.getService(track.syncId)
|
||||
if (service != null && service.isLogged && chapterNumber > track.lastChapterRead) {
|
||||
val updatedTrack = track.copy(lastChapterRead = chapterNumber)
|
||||
if (service == null || !service.isLoggedIn || chapterNumber <= track.lastChapterRead) {
|
||||
return@mapNotNull null
|
||||
}
|
||||
|
||||
async {
|
||||
runCatching {
|
||||
try {
|
||||
service.update(updatedTrack.toDbTrack(), true)
|
||||
insertTrack.await(updatedTrack)
|
||||
} catch (e: Exception) {
|
||||
delayedTrackingStore.addItem(updatedTrack)
|
||||
DelayedTrackingUpdateJob.setupTask(context)
|
||||
throw e
|
||||
}
|
||||
val updatedTrack = track.copy(lastChapterRead = chapterNumber)
|
||||
async {
|
||||
runCatching {
|
||||
try {
|
||||
service.update(updatedTrack.toDbTrack(), true)
|
||||
insertTrack.await(updatedTrack)
|
||||
} catch (e: Exception) {
|
||||
delayedTrackingStore.addItem(updatedTrack)
|
||||
DelayedTrackingUpdateJob.setupTask(context)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
.mapNotNull { it.exceptionOrNull() }
|
||||
.forEach { logcat(LogPriority.INFO, it) }
|
||||
.forEach { logcat(LogPriority.WARN, it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ class DelayedTrackingUpdateJob(context: Context, workerParams: WorkerParameters)
|
|||
.forEach { track ->
|
||||
try {
|
||||
val service = trackManager.getService(track.syncId)
|
||||
if (service != null && service.isLogged) {
|
||||
if (service != null && service.isLoggedIn) {
|
||||
logcat(LogPriority.DEBUG) { "Updating delayed track item: ${track.id}, last chapter read: ${track.lastChapterRead}" }
|
||||
service.update(track.toDbTrack(), true)
|
||||
insertTrack.await(track)
|
||||
|
|
|
@ -164,7 +164,7 @@ internal fun PreferenceItem(
|
|||
TrackingPreferenceWidget(
|
||||
service = this,
|
||||
checked = uName.isNotEmpty(),
|
||||
onClick = { if (isLogged) item.logout() else item.login() },
|
||||
onClick = { if (isLoggedIn) item.logout() else item.login() },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,16 +4,26 @@ import android.content.Context
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.network.HttpException
|
||||
import eu.kanade.tachiyomi.source.online.LicensedMangaChaptersException
|
||||
import eu.kanade.tachiyomi.util.system.isOnline
|
||||
import tachiyomi.data.source.NoResultsException
|
||||
import tachiyomi.domain.source.model.SourceNotInstalledException
|
||||
import java.net.UnknownHostException
|
||||
|
||||
context(Context)
|
||||
val Throwable.formattedMessage: String
|
||||
get() {
|
||||
when (this) {
|
||||
is HttpException -> return getString(R.string.exception_http, code)
|
||||
is UnknownHostException -> {
|
||||
return if (!isOnline()) {
|
||||
getString(R.string.exception_offline)
|
||||
} else {
|
||||
getString(R.string.exception_unknown_host, message)
|
||||
}
|
||||
}
|
||||
|
||||
is NoResultsException -> return getString(R.string.no_results_found)
|
||||
is SourceNotInstalledException -> return getString(R.string.loader_not_implemented_error)
|
||||
is HttpException -> return "$message: ${getString(R.string.http_error_hint)}"
|
||||
is LicensedMangaChaptersException -> return getString(R.string.licensed_manga_chapters_error)
|
||||
}
|
||||
return when (val className = this::class.simpleName) {
|
||||
|
|
|
@ -135,7 +135,7 @@ object Migrations {
|
|||
// Force MAL log out due to login flow change
|
||||
// v52: switched from scraping to WebView
|
||||
// v53: switched from WebView to OAuth
|
||||
if (trackManager.myAnimeList.isLogged) {
|
||||
if (trackManager.myAnimeList.isLoggedIn) {
|
||||
trackManager.myAnimeList.logout()
|
||||
context.toast(R.string.myanimelist_relogin)
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ class BackupFileValidator(
|
|||
.distinct()
|
||||
val missingTrackers = trackers
|
||||
.mapNotNull { trackManager.getService(it.toLong()) }
|
||||
.filter { !it.isLogged }
|
||||
.filter { !it.isLoggedIn }
|
||||
.map { context.getString(it.nameRes()) }
|
||||
.sorted()
|
||||
|
||||
|
|
|
@ -15,19 +15,14 @@ import androidx.work.WorkQuery
|
|||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.copyFrom
|
||||
import eu.kanade.domain.manga.model.toSManga
|
||||
import eu.kanade.domain.track.model.toDbTrack
|
||||
import eu.kanade.domain.track.model.toDomainTrack
|
||||
import eu.kanade.domain.track.interactor.RefreshTracks
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.data.track.EnhancedTrackService
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.source.UnmeteredSource
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.model.UpdateStrategy
|
||||
|
@ -43,7 +38,6 @@ import kotlinx.coroutines.awaitAll
|
|||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.ensureActive
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
import kotlinx.coroutines.sync.Semaphore
|
||||
import kotlinx.coroutines.sync.withPermit
|
||||
import logcat.LogPriority
|
||||
|
@ -52,7 +46,6 @@ import tachiyomi.core.util.lang.withIOContext
|
|||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.category.interactor.GetCategories
|
||||
import tachiyomi.domain.category.model.Category
|
||||
import tachiyomi.domain.chapter.interactor.GetChapterByMangaId
|
||||
import tachiyomi.domain.chapter.model.Chapter
|
||||
import tachiyomi.domain.chapter.model.NoChaptersException
|
||||
import tachiyomi.domain.download.service.DownloadPreferences
|
||||
|
@ -73,8 +66,6 @@ import tachiyomi.domain.manga.model.Manga
|
|||
import tachiyomi.domain.manga.model.toMangaUpdate
|
||||
import tachiyomi.domain.source.model.SourceNotInstalledException
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.domain.track.interactor.GetTracks
|
||||
import tachiyomi.domain.track.interactor.InsertTrack
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.time.ZonedDateTime
|
||||
|
@ -91,17 +82,13 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||
private val downloadPreferences: DownloadPreferences = Injekt.get()
|
||||
private val libraryPreferences: LibraryPreferences = Injekt.get()
|
||||
private val downloadManager: DownloadManager = Injekt.get()
|
||||
private val trackManager: TrackManager = Injekt.get()
|
||||
private val coverCache: CoverCache = Injekt.get()
|
||||
private val getLibraryManga: GetLibraryManga = Injekt.get()
|
||||
private val getManga: GetManga = Injekt.get()
|
||||
private val updateManga: UpdateManga = Injekt.get()
|
||||
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get()
|
||||
private val getCategories: GetCategories = Injekt.get()
|
||||
private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get()
|
||||
private val getTracks: GetTracks = Injekt.get()
|
||||
private val insertTrack: InsertTrack = Injekt.get()
|
||||
private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay = Injekt.get()
|
||||
private val refreshTracks: RefreshTracks = Injekt.get()
|
||||
private val setFetchInterval: SetFetchInterval = Injekt.get()
|
||||
private val failedUpdatesManager: FailedUpdatesRepository = Injekt.get()
|
||||
|
||||
|
@ -303,8 +290,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||
}
|
||||
|
||||
if (libraryPreferences.autoUpdateTrackers().get()) {
|
||||
val loggedServices = trackManager.services.filter { it.isLogged }
|
||||
updateTrackings(manga, loggedServices)
|
||||
refreshTracks.await(manga.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -423,49 +409,19 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||
private suspend fun updateTrackings() {
|
||||
coroutineScope {
|
||||
var progressCount = 0
|
||||
val loggedServices = trackManager.services.filter { it.isLogged }
|
||||
|
||||
mangaToUpdate.forEach { libraryManga ->
|
||||
val manga = libraryManga.manga
|
||||
|
||||
ensureActive()
|
||||
|
||||
val manga = libraryManga.manga
|
||||
notifier.showProgressNotification(listOf(manga), progressCount++, mangaToUpdate.size)
|
||||
|
||||
// Update the tracking details.
|
||||
updateTrackings(manga, loggedServices)
|
||||
refreshTracks.await(manga.id)
|
||||
}
|
||||
|
||||
notifier.cancelProgressNotification()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateTrackings(manga: Manga, loggedServices: List<TrackService>) {
|
||||
getTracks.await(manga.id)
|
||||
.map { track ->
|
||||
supervisorScope {
|
||||
async {
|
||||
val service = trackManager.getService(track.syncId)
|
||||
if (service != null && service in loggedServices) {
|
||||
try {
|
||||
val updatedTrack = service.refresh(track.toDbTrack())
|
||||
insertTrack.await(updatedTrack.toDomainTrack()!!)
|
||||
|
||||
if (service is EnhancedTrackService) {
|
||||
val chapters = getChapterByMangaId.await(manga.id)
|
||||
syncChaptersWithTrackServiceTwoWay.await(chapters, track, service)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
// Ignore errors and continue
|
||||
logcat(LogPriority.ERROR, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
}
|
||||
|
||||
private suspend fun withUpdateNotification(
|
||||
updatingManga: CopyOnWriteArrayList<Manga>,
|
||||
completed: AtomicInteger,
|
||||
|
|
|
@ -39,5 +39,5 @@ class TrackManager(context: Context) {
|
|||
|
||||
fun getService(id: Long) = services.find { it.id == id }
|
||||
|
||||
fun hasLoggedServices() = services.any { it.isLogged }
|
||||
fun hasLoggedServices() = services.any { it.isLoggedIn }
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ abstract class TrackService(val id: Long) {
|
|||
val trackPreferences: TrackPreferences by injectLazy()
|
||||
val networkService: NetworkHelper by injectLazy()
|
||||
private val insertTrack: InsertTrack by injectLazy()
|
||||
private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay by injectLazy()
|
||||
|
||||
open val client: OkHttpClient
|
||||
get() = networkService.client
|
||||
|
@ -89,7 +90,7 @@ abstract class TrackService(val id: Long) {
|
|||
trackPreferences.setTrackCredentials(this, "", "")
|
||||
}
|
||||
|
||||
open val isLogged: Boolean
|
||||
open val isLoggedIn: Boolean
|
||||
get() = getUsername().isNotEmpty() &&
|
||||
getPassword().isNotEmpty()
|
||||
|
||||
|
@ -101,6 +102,7 @@ abstract class TrackService(val id: Long) {
|
|||
trackPreferences.setTrackCredentials(this, username, password)
|
||||
}
|
||||
|
||||
// TODO: move this to an interactor, and update all trackers based on common data
|
||||
suspend fun registerTracking(item: Track, mangaId: Long) {
|
||||
item.manga_id = mangaId
|
||||
try {
|
||||
|
@ -113,6 +115,7 @@ abstract class TrackService(val id: Long) {
|
|||
|
||||
insertTrack.await(track)
|
||||
|
||||
// TODO: merge into SyncChaptersWithTrackServiceTwoWay?
|
||||
// Update chapter progress if newer chapters marked read locally
|
||||
if (hasReadChapters) {
|
||||
val latestLocalReadChapterNumber = allChapters
|
||||
|
@ -144,9 +147,7 @@ abstract class TrackService(val id: Long) {
|
|||
}
|
||||
}
|
||||
|
||||
if (this is EnhancedTrackService) {
|
||||
Injekt.get<SyncChaptersWithTrackServiceTwoWay>().await(allChapters, track, this@TrackService)
|
||||
}
|
||||
syncChaptersWithTrackServiceTwoWay.await(mangaId, track, this@TrackService)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
withUIContext { Injekt.get<Application>().toast(e.message) }
|
||||
|
|
|
@ -45,7 +45,6 @@ import tachiyomi.core.util.system.logcat
|
|||
import tachiyomi.domain.category.interactor.GetCategories
|
||||
import tachiyomi.domain.category.interactor.SetMangaCategories
|
||||
import tachiyomi.domain.category.model.Category
|
||||
import tachiyomi.domain.chapter.interactor.GetChapterByMangaId
|
||||
import tachiyomi.domain.chapter.interactor.SetMangaDefaultChapterFlags
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.domain.manga.interactor.GetDuplicateLibraryManga
|
||||
|
@ -72,7 +71,6 @@ class BrowseSourceScreenModel(
|
|||
private val getRemoteManga: GetRemoteManga = Injekt.get(),
|
||||
private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(),
|
||||
private val getCategories: GetCategories = Injekt.get(),
|
||||
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
||||
private val setMangaCategories: SetMangaCategories = Injekt.get(),
|
||||
private val setMangaDefaultChapterFlags: SetMangaDefaultChapterFlags = Injekt.get(),
|
||||
private val getManga: GetManga = Injekt.get(),
|
||||
|
@ -82,7 +80,7 @@ class BrowseSourceScreenModel(
|
|||
private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay = Injekt.get(),
|
||||
) : StateScreenModel<BrowseSourceScreenModel.State>(State(Listing.valueOf(listingQuery))) {
|
||||
|
||||
private val loggedServices by lazy { Injekt.get<TrackManager>().services.filter { it.isLogged } }
|
||||
private val loggedServices by lazy { Injekt.get<TrackManager>().services.filter { it.isLoggedIn } }
|
||||
|
||||
var displayMode by sourcePreferences.sourceDisplayMode().asState(coroutineScope)
|
||||
|
||||
|
@ -299,8 +297,7 @@ class BrowseSourceScreenModel(
|
|||
(service as TrackService).bind(track)
|
||||
insertTrack.await(track.toDomainTrack()!!)
|
||||
|
||||
val chapters = getChapterByMangaId.await(manga.id)
|
||||
syncChaptersWithTrackServiceTwoWay.await(chapters, track.toDomainTrack()!!, service)
|
||||
syncChaptersWithTrackServiceTwoWay.await(manga.id, track.toDomainTrack()!!, service)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.WARN, e) { "Could not match manga: ${manga.title} with service $service" }
|
||||
|
|
|
@ -366,7 +366,7 @@ class LibraryScreenModel(
|
|||
* @return map of track id with the filter value
|
||||
*/
|
||||
private fun getTrackingFilterFlow(): Flow<Map<Long, TriState>> {
|
||||
val loggedServices = trackManager.services.filter { it.isLogged }
|
||||
val loggedServices = trackManager.services.filter { it.isLoggedIn }
|
||||
return if (loggedServices.isNotEmpty()) {
|
||||
val prefFlows = loggedServices
|
||||
.map { libraryPreferences.filterTracking(it.id.toInt()).changes() }
|
||||
|
|
|
@ -26,7 +26,7 @@ class LibrarySettingsScreenModel(
|
|||
) : ScreenModel {
|
||||
|
||||
val trackServices
|
||||
get() = trackManager.services.filter { it.isLogged }
|
||||
get() = trackManager.services.filter { it.isLoggedIn }
|
||||
|
||||
fun toggleFilter(preference: (LibraryPreferences) -> Preference<TriState>) {
|
||||
preference(libraryPreferences).getAndSet {
|
||||
|
|
|
@ -105,7 +105,7 @@ class MangaScreenModel(
|
|||
private val successState: State.Success?
|
||||
get() = state.value as? State.Success
|
||||
|
||||
private val loggedServices by lazy { trackManager.services.filter { it.isLogged } }
|
||||
private val loggedServices by lazy { trackManager.services.filter { it.isLoggedIn } }
|
||||
|
||||
val manga: Manga?
|
||||
get() = successState?.manga
|
||||
|
|
|
@ -71,7 +71,6 @@ import tachiyomi.core.util.lang.withIOContext
|
|||
import tachiyomi.core.util.lang.withUIContext
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.manga.interactor.GetManga
|
||||
import tachiyomi.domain.manga.interactor.GetMangaWithChapters
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.domain.track.interactor.DeleteTrack
|
||||
import tachiyomi.domain.track.interactor.GetTracks
|
||||
|
@ -218,8 +217,7 @@ data class TrackInfoDialogHomeScreen(
|
|||
|
||||
private suspend fun refreshTrackers() {
|
||||
val insertTrack = Injekt.get<InsertTrack>()
|
||||
val getMangaWithChapters = Injekt.get<GetMangaWithChapters>()
|
||||
val syncTwoWayService = Injekt.get<SyncChaptersWithTrackServiceTwoWay>()
|
||||
val syncChaptersWithTrackServiceTwoWay = Injekt.get<SyncChaptersWithTrackServiceTwoWay>()
|
||||
val context = Injekt.get<Application>()
|
||||
|
||||
try {
|
||||
|
@ -229,11 +227,7 @@ data class TrackInfoDialogHomeScreen(
|
|||
val track = trackItem.track ?: continue
|
||||
val domainTrack = trackItem.service.refresh(track.toDbTrack()).toDomainTrack() ?: continue
|
||||
insertTrack.await(domainTrack)
|
||||
|
||||
if (trackItem.service is EnhancedTrackService) {
|
||||
val allChapters = getMangaWithChapters.awaitChapters(mangaId)
|
||||
syncTwoWayService.await(allChapters, domainTrack, trackItem.service)
|
||||
}
|
||||
syncChaptersWithTrackServiceTwoWay.await(mangaId, domainTrack, trackItem.service)
|
||||
} catch (e: Exception) {
|
||||
logcat(
|
||||
LogPriority.ERROR,
|
||||
|
@ -257,7 +251,7 @@ data class TrackInfoDialogHomeScreen(
|
|||
}
|
||||
|
||||
private fun List<Track>.mapToTrackItem(): List<TrackItem> {
|
||||
val loggedServices = Injekt.get<TrackManager>().services.filter { it.isLogged }
|
||||
val loggedServices = Injekt.get<TrackManager>().services.filter { it.isLoggedIn }
|
||||
val source = Injekt.get<SourceManager>().getOrStub(sourceId)
|
||||
return loggedServices
|
||||
// Map to TrackItem
|
||||
|
|
|
@ -36,7 +36,7 @@ class StatsScreenModel(
|
|||
private val trackManager: TrackManager = Injekt.get(),
|
||||
) : StateScreenModel<StatsScreenState>(StatsScreenState.Loading) {
|
||||
|
||||
private val loggedServices by lazy { trackManager.services.fastFilter { it.isLogged } }
|
||||
private val loggedServices by lazy { trackManager.services.fastFilter { it.isLoggedIn } }
|
||||
|
||||
init {
|
||||
coroutineScope.launchIO {
|
||||
|
|
|
@ -6,20 +6,19 @@ import eu.kanade.tachiyomi.source.model.SChapter
|
|||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import rx.Observable
|
||||
|
||||
@Suppress("OverridingDeprecatedMember")
|
||||
class StubSource(
|
||||
override val id: Long,
|
||||
override val lang: String,
|
||||
override val name: String,
|
||||
) : Source {
|
||||
|
||||
val isInvalid: Boolean = name.isBlank() || lang.isBlank()
|
||||
private val isInvalid: Boolean = name.isBlank() || lang.isBlank()
|
||||
|
||||
override suspend fun getMangaDetails(manga: SManga): SManga {
|
||||
throw SourceNotInstalledException()
|
||||
}
|
||||
|
||||
@Deprecated("Use the 1.x API instead", replaceWith = ReplaceWith("getMangaDetails"))
|
||||
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getMangaDetails"))
|
||||
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
||||
return Observable.error(SourceNotInstalledException())
|
||||
}
|
||||
|
@ -28,7 +27,7 @@ class StubSource(
|
|||
throw SourceNotInstalledException()
|
||||
}
|
||||
|
||||
@Deprecated("Use the 1.x API instead", replaceWith = ReplaceWith("getChapterList"))
|
||||
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getChapterList"))
|
||||
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
|
||||
return Observable.error(SourceNotInstalledException())
|
||||
}
|
||||
|
@ -37,7 +36,7 @@ class StubSource(
|
|||
throw SourceNotInstalledException()
|
||||
}
|
||||
|
||||
@Deprecated("Use the 1.x API instead", replaceWith = ReplaceWith("getPageList"))
|
||||
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getPageList"))
|
||||
override fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
|
||||
return Observable.error(SourceNotInstalledException())
|
||||
}
|
||||
|
|
|
@ -25,4 +25,4 @@ kotlin.mpp.androidSourceSetLayoutVersion=2
|
|||
android.useAndroidX=true
|
||||
android.defaults.buildfeatures.buildconfig=true
|
||||
android.nonTransitiveRClass=false
|
||||
android.nonFinalResIds=false
|
||||
#android.nonFinalResIds=false
|
|
@ -13,7 +13,6 @@ desugar = "com.android.tools:desugar_jdk_libs:2.0.3"
|
|||
android-shortcut-gradle = "com.github.zellius:android-shortcut-gradle-plugin:0.1.2"
|
||||
google-services-gradle = "com.google.gms:google-services:4.3.15"
|
||||
|
||||
rxandroid = "io.reactivex:rxandroid:1.2.1"
|
||||
rxjava = "io.reactivex:rxjava:1.3.8"
|
||||
flowreactivenetwork = "ru.beryukhov:flowreactivenetwork:1.0.4"
|
||||
|
||||
|
@ -94,7 +93,6 @@ voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", vers
|
|||
kotlinter = "org.jmailen.gradle:kotlinter-gradle:3.13.0"
|
||||
|
||||
[bundles]
|
||||
reactivex = ["rxandroid", "rxjava"]
|
||||
okhttp = ["okhttp-core", "okhttp-logging", "okhttp-dnsoverhttps"]
|
||||
js-engine = ["quickjs-android"]
|
||||
sqlite = ["sqlite-framework", "sqlite-ktx", "sqlite-android"]
|
||||
|
|
|
@ -620,8 +620,6 @@
|
|||
<!-- missing prompt after Compose rewrite #7901 -->
|
||||
<string name="no_more_results">No more results</string>
|
||||
<string name="no_results_found">No results found</string>
|
||||
<!-- Do not translate "WebView" -->
|
||||
<string name="http_error_hint">Check website in WebView</string>
|
||||
<string name="licensed_manga_chapters_error">Licensed - No chapters to show</string>
|
||||
<string name="local_source">Local source</string>
|
||||
<string name="other_source">Other</string>
|
||||
|
@ -964,35 +962,8 @@
|
|||
<string name="remove_manga">You are about to remove \"%s\" from your library</string>
|
||||
|
||||
<!-- Common exceptions -->
|
||||
<string name="exception_unknown">Unknown network error</string>
|
||||
<string name="exception_socket_error">Socket error</string>
|
||||
<string name="exception_bind_port">Failed to bind to the port</string>
|
||||
<string name="exception_io_interrupted">IO operation interrupted</string>
|
||||
<string name="exception_http_retry">HTTP operation needs to retry</string>
|
||||
<string name="exception_port_unreachable">Port unreachable</string>
|
||||
<string name="exception_io_error">IO error occurred</string>
|
||||
<string name="exception_internet_connection">No internet connection</string>
|
||||
<string name="exception_timed_out">Operation timed out</string>
|
||||
<string name="exception_ssl_connection">SSL connection error</string>
|
||||
<string name="exception_ssl_certificate">SSL certificate expired</string>
|
||||
<string name="exception_ssl_not_valid">SSL certificate not yet valid</string>
|
||||
<string name="exception_ssl_parsing">Error parsing SSL certificate</string>
|
||||
<string name="exception_ssl_encoding">Error encoding SSL certificate</string>
|
||||
<string name="exception_unrecoverable_key">Unrecoverable key encountered</string>
|
||||
<string name="exception_key_management">Issue with key management</string>
|
||||
<string name="exception_algorithm">Algorithm not available</string>
|
||||
<string name="exception_keystore">Keystore error</string>
|
||||
<string name="exception_security_provider">Security provider not found</string>
|
||||
<string name="exception_signature_validation">Issue with signature validation</string>
|
||||
<string name="exception_key_specification">Invalid key specification</string>
|
||||
<string name="exception_domain">Domain not resolved</string>
|
||||
<string name="exception_route_to_host">No route to host</string>
|
||||
<string name="exception_uri_syntax">Invalid URI syntax</string>
|
||||
<string name="exception_malformed_url">Malformed URL</string>
|
||||
<string name="exception_protocol_proxy_type">Invalid protocol or proxy type</string>
|
||||
<string name="exception_cancelled">Operation was cancelled</string>
|
||||
<string name="exception_interrupted">Operation was interrupted</string>
|
||||
<string name="exception_unexpected_state">Unexpected state encountered</string>
|
||||
<string name="exception_not_supported">Operation not supported</string>
|
||||
<string name="exception_invalid_argument">Invalid argument provided</string>
|
||||
<!-- Do not translate "WebView" -->
|
||||
<string name="exception_http">HTTP %d, check website in WebView</string>
|
||||
<string name="exception_offline">No Internet connection</string>
|
||||
<string name="exception_unknown_host">Couldn\'t reach %s</string>
|
||||
</resources>
|
||||
|
|
|
@ -24,13 +24,44 @@ interface Source {
|
|||
val lang: String
|
||||
get() = ""
|
||||
|
||||
/**
|
||||
* Get the updated details for a manga.
|
||||
*
|
||||
* @param manga the manga to update.
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
suspend fun getMangaDetails(manga: SManga): SManga {
|
||||
return fetchMangaDetails(manga).awaitSingle()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the available chapters for a manga.
|
||||
*
|
||||
* @param manga the manga to update.
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
suspend fun getChapterList(manga: SManga): List<SChapter> {
|
||||
return fetchChapterList(manga).awaitSingle()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of pages a chapter has. Pages should be returned
|
||||
* in the expected order; the index is ignored.
|
||||
*
|
||||
* @param chapter the chapter.
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
suspend fun getPageList(chapter: SChapter): List<Page> {
|
||||
return fetchPageList(chapter).awaitSingle()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an observable with the updated details for a manga.
|
||||
*
|
||||
* @param manga the manga to update.
|
||||
*/
|
||||
@Deprecated(
|
||||
"Use the 1.x API instead",
|
||||
"Use the non-RxJava API instead",
|
||||
ReplaceWith("getMangaDetails"),
|
||||
)
|
||||
fun fetchMangaDetails(manga: SManga): Observable<SManga> = throw IllegalStateException("Not used")
|
||||
|
@ -41,7 +72,7 @@ interface Source {
|
|||
* @param manga the manga to update.
|
||||
*/
|
||||
@Deprecated(
|
||||
"Use the 1.x API instead",
|
||||
"Use the non-RxJava API instead",
|
||||
ReplaceWith("getChapterList"),
|
||||
)
|
||||
fun fetchChapterList(manga: SManga): Observable<List<SChapter>> = throw IllegalStateException("Not used")
|
||||
|
@ -53,33 +84,8 @@ interface Source {
|
|||
* @param chapter the chapter.
|
||||
*/
|
||||
@Deprecated(
|
||||
"Use the 1.x API instead",
|
||||
"Use the non-RxJava API instead",
|
||||
ReplaceWith("getPageList"),
|
||||
)
|
||||
fun fetchPageList(chapter: SChapter): Observable<List<Page>> = Observable.empty()
|
||||
|
||||
/**
|
||||
* [1.x API] Get the updated details for a manga.
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
suspend fun getMangaDetails(manga: SManga): SManga {
|
||||
return fetchMangaDetails(manga).awaitSingle()
|
||||
}
|
||||
|
||||
/**
|
||||
* [1.x API] Get all the available chapters for a manga.
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
suspend fun getChapterList(manga: SManga): List<SChapter> {
|
||||
return fetchChapterList(manga).awaitSingle()
|
||||
}
|
||||
|
||||
/**
|
||||
* [1.x API] Get the list of pages a chapter has. Pages should be returned
|
||||
* in the expected order; the index is ignored.
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
suspend fun getPageList(chapter: SChapter): List<Page> {
|
||||
return fetchPageList(chapter).awaitSingle()
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue