mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	Refactor some tracking-related logic
This commit is contained in:
		@@ -1,8 +1,8 @@
 | 
			
		||||
package eu.kanade.domain
 | 
			
		||||
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.SetReadStatus
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.SyncChapterProgressWithTrack
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
 | 
			
		||||
import eu.kanade.domain.download.interactor.DeleteDownload
 | 
			
		||||
import eu.kanade.domain.extension.interactor.GetExtensionLanguages
 | 
			
		||||
import eu.kanade.domain.extension.interactor.GetExtensionSources
 | 
			
		||||
@@ -127,7 +127,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(), get()) }
 | 
			
		||||
        addFactory { SyncChapterProgressWithTrack(get(), get(), get()) }
 | 
			
		||||
 | 
			
		||||
        addSingletonFactory<HistoryRepository> { HistoryRepositoryImpl(get()) }
 | 
			
		||||
        addFactory { GetHistory(get()) }
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ import tachiyomi.domain.chapter.model.toChapterUpdate
 | 
			
		||||
import tachiyomi.domain.track.interactor.InsertTrack
 | 
			
		||||
import tachiyomi.domain.track.model.Track
 | 
			
		||||
 | 
			
		||||
class SyncChaptersWithTrackServiceTwoWay(
 | 
			
		||||
class SyncChapterProgressWithTrack(
 | 
			
		||||
    private val updateChapter: UpdateChapter,
 | 
			
		||||
    private val insertTrack: InsertTrack,
 | 
			
		||||
    private val getChapterByMangaId: GetChapterByMangaId,
 | 
			
		||||
@@ -1,14 +1,13 @@
 | 
			
		||||
package eu.kanade.domain.track.interactor
 | 
			
		||||
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.SyncChapterProgressWithTrack
 | 
			
		||||
import eu.kanade.domain.track.model.toDbTrack
 | 
			
		||||
import eu.kanade.domain.track.model.toDomainTrack
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.TrackManager
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.TrackService
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
@@ -16,28 +15,34 @@ class RefreshTracks(
 | 
			
		||||
    private val getTracks: GetTracks,
 | 
			
		||||
    private val trackManager: TrackManager,
 | 
			
		||||
    private val insertTrack: InsertTrack,
 | 
			
		||||
    private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay,
 | 
			
		||||
    private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack,
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    suspend fun await(mangaId: Long) {
 | 
			
		||||
        supervisorScope {
 | 
			
		||||
            getTracks.await(mangaId)
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetches updated tracking data from all logged in trackers.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Failed updates.
 | 
			
		||||
     */
 | 
			
		||||
    suspend fun await(mangaId: Long): List<Pair<TrackService?, Throwable>> {
 | 
			
		||||
        return supervisorScope {
 | 
			
		||||
            return@supervisorScope getTracks.await(mangaId)
 | 
			
		||||
                .map { track ->
 | 
			
		||||
                    async {
 | 
			
		||||
                        val service = trackManager.getService(track.syncId)
 | 
			
		||||
                        if (service != null && service.isLoggedIn) {
 | 
			
		||||
                            try {
 | 
			
		||||
                        return@async try {
 | 
			
		||||
                            if (service?.isLoggedIn == true) {
 | 
			
		||||
                                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)
 | 
			
		||||
                                syncChapterProgressWithTrack.await(mangaId, track, service)
 | 
			
		||||
                            }
 | 
			
		||||
                            null
 | 
			
		||||
                        } catch (e: Throwable) {
 | 
			
		||||
                            service to e
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                .awaitAll()
 | 
			
		||||
                .filterNotNull()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -127,7 +127,7 @@ private fun ColumnScope.FilterPage(
 | 
			
		||||
            trackServices.map { service ->
 | 
			
		||||
                val filterTracker by screenModel.libraryPreferences.filterTracking(service.id.toInt()).collectAsState()
 | 
			
		||||
                TriStateItem(
 | 
			
		||||
                    label = stringResource(service.nameRes()),
 | 
			
		||||
                    label = service.name,
 | 
			
		||||
                    state = filterTracker,
 | 
			
		||||
                    onClick = { screenModel.toggleTracker(service.id.toInt()) },
 | 
			
		||||
                )
 | 
			
		||||
 
 | 
			
		||||
@@ -114,9 +114,7 @@ object SettingsTrackingScreen : SearchableSettings {
 | 
			
		||||
        if (enhancedTrackers.second.isNotEmpty()) {
 | 
			
		||||
            val missingSourcesInfo = stringResource(
 | 
			
		||||
                R.string.enhanced_services_not_installed,
 | 
			
		||||
                enhancedTrackers.second
 | 
			
		||||
                    .map { stringResource(it.nameRes()) }
 | 
			
		||||
                    .joinToString(),
 | 
			
		||||
                enhancedTrackers.second.joinToString { it.name },
 | 
			
		||||
            )
 | 
			
		||||
            enhancedTrackerInfo += "\n\n$missingSourcesInfo"
 | 
			
		||||
        }
 | 
			
		||||
@@ -130,37 +128,37 @@ object SettingsTrackingScreen : SearchableSettings {
 | 
			
		||||
                title = stringResource(R.string.services),
 | 
			
		||||
                preferenceItems = listOf(
 | 
			
		||||
                    Preference.PreferenceItem.TrackingPreference(
 | 
			
		||||
                        title = stringResource(trackManager.myAnimeList.nameRes()),
 | 
			
		||||
                        title = trackManager.myAnimeList.name,
 | 
			
		||||
                        service = trackManager.myAnimeList,
 | 
			
		||||
                        login = { context.openInBrowser(MyAnimeListApi.authUrl(), forceDefaultBrowser = true) },
 | 
			
		||||
                        logout = { dialog = LogoutDialog(trackManager.myAnimeList) },
 | 
			
		||||
                    ),
 | 
			
		||||
                    Preference.PreferenceItem.TrackingPreference(
 | 
			
		||||
                        title = stringResource(trackManager.aniList.nameRes()),
 | 
			
		||||
                        title = trackManager.aniList.name,
 | 
			
		||||
                        service = trackManager.aniList,
 | 
			
		||||
                        login = { context.openInBrowser(AnilistApi.authUrl(), forceDefaultBrowser = true) },
 | 
			
		||||
                        logout = { dialog = LogoutDialog(trackManager.aniList) },
 | 
			
		||||
                    ),
 | 
			
		||||
                    Preference.PreferenceItem.TrackingPreference(
 | 
			
		||||
                        title = stringResource(trackManager.kitsu.nameRes()),
 | 
			
		||||
                        title = trackManager.kitsu.name,
 | 
			
		||||
                        service = trackManager.kitsu,
 | 
			
		||||
                        login = { dialog = LoginDialog(trackManager.kitsu, R.string.email) },
 | 
			
		||||
                        logout = { dialog = LogoutDialog(trackManager.kitsu) },
 | 
			
		||||
                    ),
 | 
			
		||||
                    Preference.PreferenceItem.TrackingPreference(
 | 
			
		||||
                        title = stringResource(trackManager.mangaUpdates.nameRes()),
 | 
			
		||||
                        title = trackManager.mangaUpdates.name,
 | 
			
		||||
                        service = trackManager.mangaUpdates,
 | 
			
		||||
                        login = { dialog = LoginDialog(trackManager.mangaUpdates, R.string.username) },
 | 
			
		||||
                        logout = { dialog = LogoutDialog(trackManager.mangaUpdates) },
 | 
			
		||||
                    ),
 | 
			
		||||
                    Preference.PreferenceItem.TrackingPreference(
 | 
			
		||||
                        title = stringResource(trackManager.shikimori.nameRes()),
 | 
			
		||||
                        title = trackManager.shikimori.name,
 | 
			
		||||
                        service = trackManager.shikimori,
 | 
			
		||||
                        login = { context.openInBrowser(ShikimoriApi.authUrl(), forceDefaultBrowser = true) },
 | 
			
		||||
                        logout = { dialog = LogoutDialog(trackManager.shikimori) },
 | 
			
		||||
                    ),
 | 
			
		||||
                    Preference.PreferenceItem.TrackingPreference(
 | 
			
		||||
                        title = stringResource(trackManager.bangumi.nameRes()),
 | 
			
		||||
                        title = trackManager.bangumi.name,
 | 
			
		||||
                        service = trackManager.bangumi,
 | 
			
		||||
                        login = { context.openInBrowser(BangumiApi.authUrl(), forceDefaultBrowser = true) },
 | 
			
		||||
                        logout = { dialog = LogoutDialog(trackManager.bangumi) },
 | 
			
		||||
@@ -173,7 +171,7 @@ object SettingsTrackingScreen : SearchableSettings {
 | 
			
		||||
                preferenceItems = enhancedTrackers.first
 | 
			
		||||
                    .map { service ->
 | 
			
		||||
                        Preference.PreferenceItem.TrackingPreference(
 | 
			
		||||
                            title = stringResource(service.nameRes()),
 | 
			
		||||
                            title = service.name,
 | 
			
		||||
                            service = service,
 | 
			
		||||
                            login = { (service as EnhancedTrackService).loginNoop() },
 | 
			
		||||
                            logout = service::logout,
 | 
			
		||||
@@ -202,7 +200,7 @@ object SettingsTrackingScreen : SearchableSettings {
 | 
			
		||||
            title = {
 | 
			
		||||
                Row(verticalAlignment = Alignment.CenterVertically) {
 | 
			
		||||
                    Text(
 | 
			
		||||
                        text = stringResource(R.string.login_title, stringResource(service.nameRes())),
 | 
			
		||||
                        text = stringResource(R.string.login_title, service.name),
 | 
			
		||||
                        modifier = Modifier.weight(1f),
 | 
			
		||||
                    )
 | 
			
		||||
                    IconButton(onClick = onDismissRequest) {
 | 
			
		||||
@@ -310,7 +308,7 @@ object SettingsTrackingScreen : SearchableSettings {
 | 
			
		||||
            onDismissRequest = onDismissRequest,
 | 
			
		||||
            title = {
 | 
			
		||||
                Text(
 | 
			
		||||
                    text = stringResource(R.string.logout_title, stringResource(service.nameRes())),
 | 
			
		||||
                    text = stringResource(R.string.logout_title, service.name),
 | 
			
		||||
                    textAlign = TextAlign.Center,
 | 
			
		||||
                    modifier = Modifier.fillMaxWidth(),
 | 
			
		||||
                )
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ fun TrackingPreferenceWidget(
 | 
			
		||||
        ) {
 | 
			
		||||
            TrackLogoIcon(service)
 | 
			
		||||
            Text(
 | 
			
		||||
                text = stringResource(service.nameRes()),
 | 
			
		||||
                text = service.name,
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .weight(1f)
 | 
			
		||||
                    .padding(horizontal = 16.dp),
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,6 @@ import androidx.compose.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.graphics.Color
 | 
			
		||||
import androidx.compose.ui.res.painterResource
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.TrackService
 | 
			
		||||
import tachiyomi.presentation.core.util.clickableNoIndication
 | 
			
		||||
@@ -36,7 +35,7 @@ fun TrackLogoIcon(
 | 
			
		||||
    ) {
 | 
			
		||||
        Image(
 | 
			
		||||
            painter = painterResource(service.getLogo()),
 | 
			
		||||
            contentDescription = stringResource(service.nameRes()),
 | 
			
		||||
            contentDescription = service.name,
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,7 @@ class BackupFileValidator(
 | 
			
		||||
        val missingTrackers = trackers
 | 
			
		||||
            .mapNotNull { trackManager.getService(it.toLong()) }
 | 
			
		||||
            .filter { !it.isLoggedIn }
 | 
			
		||||
            .map { context.getString(it.nameRes()) }
 | 
			
		||||
            .map { it.name }
 | 
			
		||||
            .sorted()
 | 
			
		||||
 | 
			
		||||
        return Results(missingSources, missingTrackers)
 | 
			
		||||
 
 | 
			
		||||
@@ -283,7 +283,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
 | 
			
		||||
                                    }
 | 
			
		||||
 | 
			
		||||
                                    if (libraryPreferences.autoUpdateTrackers().get()) {
 | 
			
		||||
                                        refreshTracks.await(manga.id)
 | 
			
		||||
                                        refreshTracks(manga.id)
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
@@ -409,13 +409,20 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
 | 
			
		||||
 | 
			
		||||
                val manga = libraryManga.manga
 | 
			
		||||
                notifier.showProgressNotification(listOf(manga), progressCount++, mangaToUpdate.size)
 | 
			
		||||
                refreshTracks.await(manga.id)
 | 
			
		||||
                refreshTracks(manga.id)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            notifier.cancelProgressNotification()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private suspend fun refreshTracks(mangaId: Long) {
 | 
			
		||||
        refreshTracks.await(mangaId).forEach { (_, e) ->
 | 
			
		||||
            // Ignore errors and continue
 | 
			
		||||
            logcat(LogPriority.ERROR, e)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private suspend fun withUpdateNotification(
 | 
			
		||||
        updatingManga: CopyOnWriteArrayList<Manga>,
 | 
			
		||||
        completed: AtomicInteger,
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@ class TrackManager(context: Context) {
 | 
			
		||||
    val kitsu = Kitsu(KITSU)
 | 
			
		||||
    val shikimori = Shikimori(SHIKIMORI)
 | 
			
		||||
    val bangumi = Bangumi(BANGUMI)
 | 
			
		||||
    val komga = Komga(context, KOMGA)
 | 
			
		||||
    val komga = Komga(KOMGA)
 | 
			
		||||
    val mangaUpdates = MangaUpdates(MANGA_UPDATES)
 | 
			
		||||
    val kavita = Kavita(context, KAVITA)
 | 
			
		||||
    val suwayomi = Suwayomi(SUWAYOMI)
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ import androidx.annotation.CallSuper
 | 
			
		||||
import androidx.annotation.ColorInt
 | 
			
		||||
import androidx.annotation.DrawableRes
 | 
			
		||||
import androidx.annotation.StringRes
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.SyncChapterProgressWithTrack
 | 
			
		||||
import eu.kanade.domain.track.model.toDbTrack
 | 
			
		||||
import eu.kanade.domain.track.model.toDomainTrack
 | 
			
		||||
import eu.kanade.domain.track.service.TrackPreferences
 | 
			
		||||
@@ -28,20 +28,16 @@ import uy.kohesive.injekt.injectLazy
 | 
			
		||||
import java.time.ZoneOffset
 | 
			
		||||
import tachiyomi.domain.track.model.Track as DomainTrack
 | 
			
		||||
 | 
			
		||||
abstract class TrackService(val id: Long) {
 | 
			
		||||
abstract class TrackService(val id: Long, val name: String) {
 | 
			
		||||
 | 
			
		||||
    val trackPreferences: TrackPreferences by injectLazy()
 | 
			
		||||
    val networkService: NetworkHelper by injectLazy()
 | 
			
		||||
    private val insertTrack: InsertTrack by injectLazy()
 | 
			
		||||
    private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay by injectLazy()
 | 
			
		||||
    private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack by injectLazy()
 | 
			
		||||
 | 
			
		||||
    open val client: OkHttpClient
 | 
			
		||||
        get() = networkService.client
 | 
			
		||||
 | 
			
		||||
    // Name of the manga sync service to display
 | 
			
		||||
    @StringRes
 | 
			
		||||
    abstract fun nameRes(): Int
 | 
			
		||||
 | 
			
		||||
    // Application and remote support for reading dates
 | 
			
		||||
    open val supportsReadingDates: Boolean = false
 | 
			
		||||
 | 
			
		||||
@@ -103,7 +99,7 @@ abstract class TrackService(val id: Long) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO: move this to an interactor, and update all trackers based on common data
 | 
			
		||||
    suspend fun registerTracking(item: Track, mangaId: Long) {
 | 
			
		||||
    suspend fun register(item: Track, mangaId: Long) {
 | 
			
		||||
        item.manga_id = mangaId
 | 
			
		||||
        try {
 | 
			
		||||
            withIOContext {
 | 
			
		||||
@@ -147,7 +143,7 @@ abstract class TrackService(val id: Long) {
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                syncChaptersWithTrackServiceTwoWay.await(mangaId, track, this@TrackService)
 | 
			
		||||
                syncChapterProgressWithTrack.await(mangaId, track, this@TrackService)
 | 
			
		||||
            }
 | 
			
		||||
        } catch (e: Throwable) {
 | 
			
		||||
            withUIContext { Injekt.get<Application>().toast(e.message) }
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ import kotlinx.serialization.json.Json
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
import tachiyomi.domain.track.model.Track as DomainTrack
 | 
			
		||||
 | 
			
		||||
class Anilist(id: Long) : TrackService(id), DeletableTrackService {
 | 
			
		||||
class Anilist(id: Long) : TrackService(id, "AniList"), DeletableTrackService {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        const val READING = 1
 | 
			
		||||
@@ -49,9 +49,6 @@ class Anilist(id: Long) : TrackService(id), DeletableTrackService {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @StringRes
 | 
			
		||||
    override fun nameRes() = R.string.tracker_anilist
 | 
			
		||||
 | 
			
		||||
    override fun getLogo() = R.drawable.ic_tracker_anilist
 | 
			
		||||
 | 
			
		||||
    override fun getLogoColor() = Color.rgb(18, 25, 35)
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ import kotlinx.serialization.encodeToString
 | 
			
		||||
import kotlinx.serialization.json.Json
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
 | 
			
		||||
class Bangumi(id: Long) : TrackService(id) {
 | 
			
		||||
class Bangumi(id: Long) : TrackService(id, "Bangumi") {
 | 
			
		||||
 | 
			
		||||
    private val json: Json by injectLazy()
 | 
			
		||||
 | 
			
		||||
@@ -18,9 +18,6 @@ class Bangumi(id: Long) : TrackService(id) {
 | 
			
		||||
 | 
			
		||||
    private val api by lazy { BangumiApi(client, interceptor) }
 | 
			
		||||
 | 
			
		||||
    @StringRes
 | 
			
		||||
    override fun nameRes() = R.string.tracker_bangumi
 | 
			
		||||
 | 
			
		||||
    override fun getScoreList(): List<String> {
 | 
			
		||||
        return IntRange(0, 10).map(Int::toString)
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ import tachiyomi.domain.manga.model.Manga
 | 
			
		||||
import java.security.MessageDigest
 | 
			
		||||
import tachiyomi.domain.track.model.Track as DomainTrack
 | 
			
		||||
 | 
			
		||||
class Kavita(private val context: Context, id: Long) : TrackService(id), EnhancedTrackService {
 | 
			
		||||
class Kavita(private val context: Context, id: Long) : TrackService(id, "Kavita"), EnhancedTrackService {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        const val UNREAD = 1
 | 
			
		||||
@@ -27,9 +27,6 @@ class Kavita(private val context: Context, id: Long) : TrackService(id), Enhance
 | 
			
		||||
    private val interceptor by lazy { KavitaInterceptor(this) }
 | 
			
		||||
    val api by lazy { KavitaApi(client, interceptor) }
 | 
			
		||||
 | 
			
		||||
    @StringRes
 | 
			
		||||
    override fun nameRes() = R.string.tracker_kavita
 | 
			
		||||
 | 
			
		||||
    override fun getLogo(): Int = R.drawable.ic_tracker_kavita
 | 
			
		||||
 | 
			
		||||
    override fun getLogoColor() = Color.rgb(74, 198, 148)
 | 
			
		||||
 
 | 
			
		||||
@@ -115,8 +115,8 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun getLatestChapterRead(url: String): Float {
 | 
			
		||||
        val serieId = getIdFromUrl(url)
 | 
			
		||||
        val requestUrl = "${getApiFromUrl(url)}/Tachiyomi/latest-chapter?seriesId=$serieId"
 | 
			
		||||
        val seriesId = getIdFromUrl(url)
 | 
			
		||||
        val requestUrl = "${getApiFromUrl(url)}/Tachiyomi/latest-chapter?seriesId=$seriesId"
 | 
			
		||||
        try {
 | 
			
		||||
            with(json) {
 | 
			
		||||
                authClient.newCall(GET(requestUrl)).execute().use {
 | 
			
		||||
@@ -137,21 +137,21 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
 | 
			
		||||
 | 
			
		||||
    suspend fun getTrackSearch(url: String): TrackSearch = withIOContext {
 | 
			
		||||
        try {
 | 
			
		||||
            val serieDto: SeriesDto = with(json) {
 | 
			
		||||
            val seriesDto: SeriesDto = with(json) {
 | 
			
		||||
                authClient.newCall(GET(url))
 | 
			
		||||
                    .awaitSuccess()
 | 
			
		||||
                    .parseAs()
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            val track = serieDto.toTrack()
 | 
			
		||||
            val track = seriesDto.toTrack()
 | 
			
		||||
            track.apply {
 | 
			
		||||
                cover_url = serieDto.thumbnail_url.toString()
 | 
			
		||||
                cover_url = seriesDto.thumbnail_url.toString()
 | 
			
		||||
                tracking_url = url
 | 
			
		||||
                total_chapters = getTotalChapters(url)
 | 
			
		||||
 | 
			
		||||
                title = serieDto.name
 | 
			
		||||
                status = when (serieDto.pagesRead) {
 | 
			
		||||
                    serieDto.pages -> Kavita.COMPLETED
 | 
			
		||||
                title = seriesDto.name
 | 
			
		||||
                status = when (seriesDto.pagesRead) {
 | 
			
		||||
                    seriesDto.pages -> Kavita.COMPLETED
 | 
			
		||||
                    0 -> Kavita.UNREAD
 | 
			
		||||
                    else -> Kavita.READING
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ import kotlinx.serialization.json.Json
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
import java.text.DecimalFormat
 | 
			
		||||
 | 
			
		||||
class Kitsu(id: Long) : TrackService(id), DeletableTrackService {
 | 
			
		||||
class Kitsu(id: Long) : TrackService(id, "Kitsu"), DeletableTrackService {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        const val READING = 1
 | 
			
		||||
@@ -22,9 +22,6 @@ class Kitsu(id: Long) : TrackService(id), DeletableTrackService {
 | 
			
		||||
        const val PLAN_TO_READ = 5
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @StringRes
 | 
			
		||||
    override fun nameRes() = R.string.tracker_kitsu
 | 
			
		||||
 | 
			
		||||
    override val supportsReadingDates: Boolean = true
 | 
			
		||||
 | 
			
		||||
    private val json: Json by injectLazy()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.track.komga
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.graphics.Color
 | 
			
		||||
import androidx.annotation.StringRes
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
@@ -14,7 +13,7 @@ import okhttp3.OkHttpClient
 | 
			
		||||
import tachiyomi.domain.manga.model.Manga
 | 
			
		||||
import tachiyomi.domain.track.model.Track as DomainTrack
 | 
			
		||||
 | 
			
		||||
class Komga(private val context: Context, id: Long) : TrackService(id), EnhancedTrackService {
 | 
			
		||||
class Komga(id: Long) : TrackService(id, "Komga"), EnhancedTrackService {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        const val UNREAD = 1
 | 
			
		||||
@@ -29,9 +28,6 @@ class Komga(private val context: Context, id: Long) : TrackService(id), Enhanced
 | 
			
		||||
 | 
			
		||||
    val api by lazy { KomgaApi(client) }
 | 
			
		||||
 | 
			
		||||
    @StringRes
 | 
			
		||||
    override fun nameRes() = R.string.tracker_komga
 | 
			
		||||
 | 
			
		||||
    override fun getLogo() = R.drawable.ic_tracker_komga
 | 
			
		||||
 | 
			
		||||
    override fun getLogoColor() = Color.rgb(51, 37, 50)
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ import tachiyomi.core.util.lang.withIOContext
 | 
			
		||||
import tachiyomi.core.util.system.logcat
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
 | 
			
		||||
const val READLIST_API = "/api/v1/readlists"
 | 
			
		||||
private const val READLIST_API = "/api/v1/readlists"
 | 
			
		||||
 | 
			
		||||
class KomgaApi(private val client: OkHttpClient) {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ import eu.kanade.tachiyomi.data.track.mangaupdates.dto.copyTo
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.mangaupdates.dto.toTrackSearch
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
 | 
			
		||||
 | 
			
		||||
class MangaUpdates(id: Long) : TrackService(id), DeletableTrackService {
 | 
			
		||||
class MangaUpdates(id: Long) : TrackService(id, "MangaUpdates"), DeletableTrackService {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        const val READING_LIST = 0
 | 
			
		||||
@@ -24,9 +24,6 @@ class MangaUpdates(id: Long) : TrackService(id), DeletableTrackService {
 | 
			
		||||
 | 
			
		||||
    private val api by lazy { MangaUpdatesApi(interceptor, client) }
 | 
			
		||||
 | 
			
		||||
    @StringRes
 | 
			
		||||
    override fun nameRes(): Int = R.string.tracker_manga_updates
 | 
			
		||||
 | 
			
		||||
    override fun getLogo(): Int = R.drawable.ic_manga_updates
 | 
			
		||||
 | 
			
		||||
    override fun getLogoColor(): Int = Color.rgb(146, 160, 173)
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ import kotlinx.serialization.encodeToString
 | 
			
		||||
import kotlinx.serialization.json.Json
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
 | 
			
		||||
class MyAnimeList(id: Long) : TrackService(id), DeletableTrackService {
 | 
			
		||||
class MyAnimeList(id: Long) : TrackService(id, "MyAnimeList"), DeletableTrackService {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        const val READING = 1
 | 
			
		||||
@@ -30,9 +30,6 @@ class MyAnimeList(id: Long) : TrackService(id), DeletableTrackService {
 | 
			
		||||
    private val interceptor by lazy { MyAnimeListInterceptor(this, getPassword()) }
 | 
			
		||||
    private val api by lazy { MyAnimeListApi(client, interceptor) }
 | 
			
		||||
 | 
			
		||||
    @StringRes
 | 
			
		||||
    override fun nameRes() = R.string.tracker_myanimelist
 | 
			
		||||
 | 
			
		||||
    override val supportsReadingDates: Boolean = true
 | 
			
		||||
 | 
			
		||||
    override fun getLogo() = R.drawable.ic_tracker_mal
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ import kotlinx.serialization.encodeToString
 | 
			
		||||
import kotlinx.serialization.json.Json
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
 | 
			
		||||
class Shikimori(id: Long) : TrackService(id), DeletableTrackService {
 | 
			
		||||
class Shikimori(id: Long) : TrackService(id, "Shikimori"), DeletableTrackService {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        const val READING = 1
 | 
			
		||||
@@ -28,9 +28,6 @@ class Shikimori(id: Long) : TrackService(id), DeletableTrackService {
 | 
			
		||||
 | 
			
		||||
    private val api by lazy { ShikimoriApi(client, interceptor) }
 | 
			
		||||
 | 
			
		||||
    @StringRes
 | 
			
		||||
    override fun nameRes() = R.string.tracker_shikimori
 | 
			
		||||
 | 
			
		||||
    override fun getScoreList(): List<String> {
 | 
			
		||||
        return IntRange(0, 10).map(Int::toString)
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -122,7 +122,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun findLibManga(track: Track, user_id: String): Track? {
 | 
			
		||||
    suspend fun findLibManga(track: Track, userId: String): Track? {
 | 
			
		||||
        return withIOContext {
 | 
			
		||||
            val urlMangas = "$apiUrl/mangas".toUri().buildUpon()
 | 
			
		||||
                .appendPath(track.media_id.toString())
 | 
			
		||||
@@ -134,7 +134,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            val url = "$apiUrl/v2/user_rates".toUri().buildUpon()
 | 
			
		||||
                .appendQueryParameter("user_id", user_id)
 | 
			
		||||
                .appendQueryParameter("user_id", userId)
 | 
			
		||||
                .appendQueryParameter("target_id", track.media_id.toString())
 | 
			
		||||
                .appendQueryParameter("target_type", "Manga")
 | 
			
		||||
                .build()
 | 
			
		||||
 
 | 
			
		||||
@@ -11,13 +11,10 @@ import eu.kanade.tachiyomi.source.Source
 | 
			
		||||
import tachiyomi.domain.manga.model.Manga as DomainManga
 | 
			
		||||
import tachiyomi.domain.track.model.Track as DomainTrack
 | 
			
		||||
 | 
			
		||||
class Suwayomi(id: Long) : TrackService(id), EnhancedTrackService {
 | 
			
		||||
class Suwayomi(id: Long) : TrackService(id, "Suwayomi"), EnhancedTrackService {
 | 
			
		||||
 | 
			
		||||
    val api by lazy { TachideskApi() }
 | 
			
		||||
 | 
			
		||||
    @StringRes
 | 
			
		||||
    override fun nameRes() = R.string.tracker_suwayomi
 | 
			
		||||
 | 
			
		||||
    override fun getLogo() = R.drawable.ic_tracker_suwayomi
 | 
			
		||||
 | 
			
		||||
    override fun getLogoColor() = Color.rgb(255, 35, 35) // TODO
 | 
			
		||||
 
 | 
			
		||||
@@ -28,19 +28,19 @@ class TachideskApi {
 | 
			
		||||
    private val network: NetworkHelper by injectLazy()
 | 
			
		||||
    private val json: Json by injectLazy()
 | 
			
		||||
 | 
			
		||||
    val client: OkHttpClient =
 | 
			
		||||
    private val client: OkHttpClient =
 | 
			
		||||
        network.client.newBuilder()
 | 
			
		||||
            .dns(Dns.SYSTEM) // don't use DNS over HTTPS as it breaks IP addressing
 | 
			
		||||
            .build()
 | 
			
		||||
 | 
			
		||||
    fun headersBuilder(): Headers.Builder = Headers.Builder().apply {
 | 
			
		||||
    private fun headersBuilder(): Headers.Builder = Headers.Builder().apply {
 | 
			
		||||
        if (basePassword.isNotEmpty() && baseLogin.isNotEmpty()) {
 | 
			
		||||
            val credentials = Credentials.basic(baseLogin, basePassword)
 | 
			
		||||
            add("Authorization", credentials)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val headers: Headers by lazy { headersBuilder().build() }
 | 
			
		||||
    private val headers: Headers by lazy { headersBuilder().build() }
 | 
			
		||||
 | 
			
		||||
    private val baseUrl by lazy { getPrefBaseUrl() }
 | 
			
		||||
    private val baseLogin by lazy { getPrefBaseLogin() }
 | 
			
		||||
@@ -100,7 +100,7 @@ class TachideskApi {
 | 
			
		||||
        return getTrackSearch(track.tracking_url)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val tachideskExtensionId by lazy {
 | 
			
		||||
    private val tachideskExtensionId by lazy {
 | 
			
		||||
        val key = "tachidesk/en/1"
 | 
			
		||||
        val bytes = MessageDigest.getInstance("MD5").digest(key.toByteArray())
 | 
			
		||||
        (0..7).map { bytes[it].toLong() and 0xff shl 8 * (7 - it) }.reduce(Long::or) and Long.MAX_VALUE
 | 
			
		||||
@@ -110,6 +110,10 @@ class TachideskApi {
 | 
			
		||||
        Injekt.get<Application>().getSharedPreferences("source_$tachideskExtensionId", 0x0000)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun getPrefBaseUrl(): String = preferences.getString(ADDRESS_TITLE, ADDRESS_DEFAULT)!!
 | 
			
		||||
    private fun getPrefBaseLogin(): String = preferences.getString(LOGIN_TITLE, LOGIN_DEFAULT)!!
 | 
			
		||||
    private fun getPrefBasePassword(): String = preferences.getString(PASSWORD_TITLE, PASSWORD_DEFAULT)!!
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        private const val ADDRESS_TITLE = "Server URL Address"
 | 
			
		||||
        private const val ADDRESS_DEFAULT = ""
 | 
			
		||||
@@ -118,8 +122,4 @@ class TachideskApi {
 | 
			
		||||
        private const val PASSWORD_TITLE = "Password (Basic Auth)"
 | 
			
		||||
        private const val PASSWORD_DEFAULT = ""
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun getPrefBaseUrl(): String = preferences.getString(ADDRESS_TITLE, ADDRESS_DEFAULT)!!
 | 
			
		||||
    private fun getPrefBaseLogin(): String = preferences.getString(LOGIN_TITLE, LOGIN_DEFAULT)!!
 | 
			
		||||
    private fun getPrefBasePassword(): String = preferences.getString(PASSWORD_TITLE, PASSWORD_DEFAULT)!!
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ import cafe.adriel.voyager.core.model.StateScreenModel
 | 
			
		||||
import cafe.adriel.voyager.core.model.coroutineScope
 | 
			
		||||
import eu.kanade.core.preference.asState
 | 
			
		||||
import eu.kanade.domain.base.BasePreferences
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.SyncChapterProgressWithTrack
 | 
			
		||||
import eu.kanade.domain.manga.interactor.UpdateManga
 | 
			
		||||
import eu.kanade.domain.manga.model.toDomainManga
 | 
			
		||||
import eu.kanade.domain.source.service.SourcePreferences
 | 
			
		||||
@@ -77,7 +77,7 @@ class BrowseSourceScreenModel(
 | 
			
		||||
    private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
 | 
			
		||||
    private val updateManga: UpdateManga = Injekt.get(),
 | 
			
		||||
    private val insertTrack: InsertTrack = Injekt.get(),
 | 
			
		||||
    private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay = Injekt.get(),
 | 
			
		||||
    private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack = Injekt.get(),
 | 
			
		||||
) : StateScreenModel<BrowseSourceScreenModel.State>(State(Listing.valueOf(listingQuery))) {
 | 
			
		||||
 | 
			
		||||
    private val loggedServices by lazy { Injekt.get<TrackManager>().services.filter { it.isLoggedIn } }
 | 
			
		||||
@@ -297,7 +297,7 @@ class BrowseSourceScreenModel(
 | 
			
		||||
                        (service as TrackService).bind(track)
 | 
			
		||||
                        insertTrack.await(track.toDomainTrack()!!)
 | 
			
		||||
 | 
			
		||||
                        syncChaptersWithTrackServiceTwoWay.await(manga.id, track.toDomainTrack()!!, service)
 | 
			
		||||
                        syncChapterProgressWithTrack.await(manga.id, track.toDomainTrack()!!, service)
 | 
			
		||||
                    }
 | 
			
		||||
                } catch (e: Exception) {
 | 
			
		||||
                    logcat(LogPriority.WARN, e) { "Could not match manga: ${manga.title} with service $service" }
 | 
			
		||||
 
 | 
			
		||||
@@ -323,7 +323,7 @@ class MangaScreenModel(
 | 
			
		||||
                        launchIO {
 | 
			
		||||
                            try {
 | 
			
		||||
                                service.match(manga)?.let { track ->
 | 
			
		||||
                                    (service as TrackService).registerTracking(track, mangaId)
 | 
			
		||||
                                    (service as TrackService).register(track, mangaId)
 | 
			
		||||
                                }
 | 
			
		||||
                            } catch (e: Exception) {
 | 
			
		||||
                                logcat(LogPriority.WARN, e) {
 | 
			
		||||
 
 | 
			
		||||
@@ -39,9 +39,8 @@ import cafe.adriel.voyager.core.model.rememberScreenModel
 | 
			
		||||
import cafe.adriel.voyager.navigator.LocalNavigator
 | 
			
		||||
import cafe.adriel.voyager.navigator.Navigator
 | 
			
		||||
import cafe.adriel.voyager.navigator.currentOrThrow
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
 | 
			
		||||
import eu.kanade.domain.track.interactor.RefreshTracks
 | 
			
		||||
import eu.kanade.domain.track.model.toDbTrack
 | 
			
		||||
import eu.kanade.domain.track.model.toDomainTrack
 | 
			
		||||
import eu.kanade.domain.ui.UiPreferences
 | 
			
		||||
import eu.kanade.presentation.track.TrackChapterSelector
 | 
			
		||||
import eu.kanade.presentation.track.TrackDateSelector
 | 
			
		||||
@@ -74,7 +73,6 @@ import tachiyomi.domain.manga.interactor.GetManga
 | 
			
		||||
import tachiyomi.domain.source.service.SourceManager
 | 
			
		||||
import tachiyomi.domain.track.interactor.DeleteTrack
 | 
			
		||||
import tachiyomi.domain.track.interactor.GetTracks
 | 
			
		||||
import tachiyomi.domain.track.interactor.InsertTrack
 | 
			
		||||
import tachiyomi.domain.track.model.Track
 | 
			
		||||
import tachiyomi.presentation.core.components.material.AlertDialogContent
 | 
			
		||||
import tachiyomi.presentation.core.components.material.padding
 | 
			
		||||
@@ -208,7 +206,7 @@ data class TrackInfoDialogHomeScreen(
 | 
			
		||||
                val manga = Injekt.get<GetManga>().await(mangaId) ?: return@launchNonCancellable
 | 
			
		||||
                try {
 | 
			
		||||
                    val matchResult = item.service.match(manga) ?: throw Exception()
 | 
			
		||||
                    item.service.registerTracking(matchResult, mangaId)
 | 
			
		||||
                    item.service.register(matchResult, mangaId)
 | 
			
		||||
                } catch (e: Exception) {
 | 
			
		||||
                    withUIContext { Injekt.get<Application>().toast(R.string.error_no_match) }
 | 
			
		||||
                }
 | 
			
		||||
@@ -216,38 +214,25 @@ data class TrackInfoDialogHomeScreen(
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private suspend fun refreshTrackers() {
 | 
			
		||||
            val insertTrack = Injekt.get<InsertTrack>()
 | 
			
		||||
            val syncChaptersWithTrackServiceTwoWay = Injekt.get<SyncChaptersWithTrackServiceTwoWay>()
 | 
			
		||||
            val refreshTracks = Injekt.get<RefreshTracks>()
 | 
			
		||||
            val context = Injekt.get<Application>()
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                val trackItems = getTracks.await(mangaId).mapToTrackItem()
 | 
			
		||||
                for (trackItem in trackItems) {
 | 
			
		||||
                    try {
 | 
			
		||||
                        val track = trackItem.track ?: continue
 | 
			
		||||
                        val domainTrack = trackItem.service.refresh(track.toDbTrack()).toDomainTrack() ?: continue
 | 
			
		||||
                        insertTrack.await(domainTrack)
 | 
			
		||||
                        syncChaptersWithTrackServiceTwoWay.await(mangaId, domainTrack, trackItem.service)
 | 
			
		||||
                    } catch (e: Exception) {
 | 
			
		||||
                        logcat(
 | 
			
		||||
                            LogPriority.ERROR,
 | 
			
		||||
                            e,
 | 
			
		||||
                        ) { "Failed to refresh track data mangaId=$mangaId for service ${trackItem.service.id}" }
 | 
			
		||||
                        withUIContext {
 | 
			
		||||
                            context.toast(
 | 
			
		||||
                                context.getString(
 | 
			
		||||
                                    R.string.track_error,
 | 
			
		||||
                                    context.getString(trackItem.service.nameRes()),
 | 
			
		||||
                                    e.message,
 | 
			
		||||
                                ),
 | 
			
		||||
                            )
 | 
			
		||||
                        }
 | 
			
		||||
            refreshTracks.await(mangaId)
 | 
			
		||||
                .filter { it.first != null }
 | 
			
		||||
                .forEach { (track, e) ->
 | 
			
		||||
                    logcat(LogPriority.ERROR, e) {
 | 
			
		||||
                        "Failed to refresh track data mangaId=$mangaId for service ${track!!.id}"
 | 
			
		||||
                    }
 | 
			
		||||
                    withUIContext {
 | 
			
		||||
                        context.toast(
 | 
			
		||||
                            context.getString(
 | 
			
		||||
                                R.string.track_error,
 | 
			
		||||
                                track!!.name,
 | 
			
		||||
                                e.message,
 | 
			
		||||
                            ),
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } catch (e: Exception) {
 | 
			
		||||
                logcat(LogPriority.ERROR, e) { "Failed to refresh track data mangaId=$mangaId" }
 | 
			
		||||
                withUIContext { context.toast(e.message) }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private fun List<Track>.mapToTrackItem(): List<TrackItem> {
 | 
			
		||||
@@ -581,7 +566,7 @@ private data class TrackDateRemoverScreen(
 | 
			
		||||
                )
 | 
			
		||||
            },
 | 
			
		||||
            text = {
 | 
			
		||||
                val serviceName = stringResource(sm.getServiceNameRes())
 | 
			
		||||
                val serviceName = sm.getServiceName()
 | 
			
		||||
                Text(
 | 
			
		||||
                    text = if (start) {
 | 
			
		||||
                        stringResource(R.string.track_remove_start_date_conf_text, serviceName)
 | 
			
		||||
@@ -618,7 +603,7 @@ private data class TrackDateRemoverScreen(
 | 
			
		||||
        private val start: Boolean,
 | 
			
		||||
    ) : ScreenModel {
 | 
			
		||||
 | 
			
		||||
        fun getServiceNameRes() = service.nameRes()
 | 
			
		||||
        fun getServiceName() = service.name
 | 
			
		||||
 | 
			
		||||
        fun removeDate() {
 | 
			
		||||
            coroutineScope.launchNonCancellable {
 | 
			
		||||
@@ -703,7 +688,7 @@ data class TrackServiceSearchScreen(
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun registerTracking(item: TrackSearch) {
 | 
			
		||||
            coroutineScope.launchNonCancellable { service.registerTracking(item, mangaId) }
 | 
			
		||||
            coroutineScope.launchNonCancellable { service.register(item, mangaId) }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun updateSelection(selected: TrackSearch) {
 | 
			
		||||
@@ -734,7 +719,7 @@ private data class TrackServiceRemoveScreen(
 | 
			
		||||
                service = Injekt.get<TrackManager>().getService(serviceId)!!,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        val serviceName = stringResource(sm.getServiceNameRes())
 | 
			
		||||
        val serviceName = sm.getServiceName()
 | 
			
		||||
        var removeRemoteTrack by remember { mutableStateOf(false) }
 | 
			
		||||
        AlertDialogContent(
 | 
			
		||||
            modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars),
 | 
			
		||||
@@ -799,7 +784,7 @@ private data class TrackServiceRemoveScreen(
 | 
			
		||||
        private val deleteTrack: DeleteTrack = Injekt.get(),
 | 
			
		||||
    ) : ScreenModel {
 | 
			
		||||
 | 
			
		||||
        fun getServiceNameRes() = service.nameRes()
 | 
			
		||||
        fun getServiceName() = service.name
 | 
			
		||||
 | 
			
		||||
        fun isServiceDeletable() = service is DeletableTrackService
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user