123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801 |
- package eu.kanade.tachiyomi.ui.manga
- import android.content.Context
- import android.net.Uri
- import android.os.Bundle
- import com.jakewharton.rxrelay.PublishRelay
- import eu.kanade.tachiyomi.data.cache.CoverCache
- import eu.kanade.tachiyomi.data.database.DatabaseHelper
- import eu.kanade.tachiyomi.data.database.models.Category
- import eu.kanade.tachiyomi.data.database.models.Chapter
- import eu.kanade.tachiyomi.data.database.models.Manga
- import eu.kanade.tachiyomi.data.database.models.MangaCategory
- import eu.kanade.tachiyomi.data.database.models.Track
- import eu.kanade.tachiyomi.data.database.models.toMangaInfo
- import eu.kanade.tachiyomi.data.download.DownloadManager
- import eu.kanade.tachiyomi.data.download.model.Download
- import eu.kanade.tachiyomi.data.preference.PreferencesHelper
- import eu.kanade.tachiyomi.data.track.TrackManager
- import eu.kanade.tachiyomi.data.track.TrackService
- import eu.kanade.tachiyomi.source.LocalSource
- import eu.kanade.tachiyomi.source.Source
- import eu.kanade.tachiyomi.source.model.toSChapter
- import eu.kanade.tachiyomi.source.model.toSManga
- import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
- import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
- import eu.kanade.tachiyomi.ui.manga.track.TrackItem
- import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper
- import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
- import eu.kanade.tachiyomi.util.isLocal
- import eu.kanade.tachiyomi.util.lang.launchIO
- import eu.kanade.tachiyomi.util.lang.withUIContext
- import eu.kanade.tachiyomi.util.prepUpdateCover
- import eu.kanade.tachiyomi.util.removeCovers
- import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
- import eu.kanade.tachiyomi.util.system.toast
- import eu.kanade.tachiyomi.util.updateCoverLastModified
- import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State
- import kotlinx.coroutines.Job
- import kotlinx.coroutines.async
- import kotlinx.coroutines.awaitAll
- import kotlinx.coroutines.supervisorScope
- import rx.Observable
- import rx.Subscription
- import rx.android.schedulers.AndroidSchedulers
- import rx.schedulers.Schedulers
- import timber.log.Timber
- import uy.kohesive.injekt.Injekt
- import uy.kohesive.injekt.api.get
- import java.util.Date
- class MangaPresenter(
- val manga: Manga,
- val source: Source,
- val preferences: PreferencesHelper = Injekt.get(),
- private val db: DatabaseHelper = Injekt.get(),
- private val trackManager: TrackManager = Injekt.get(),
- private val downloadManager: DownloadManager = Injekt.get(),
- private val coverCache: CoverCache = Injekt.get()
- ) : BasePresenter<MangaController>() {
- /**
- * Subscription to update the manga from the source.
- */
- private var fetchMangaJob: Job? = null
- /**
- * List of chapters of the manga. It's always unfiltered and unsorted.
- */
- var chapters: List<ChapterItem> = emptyList()
- private set
- /**
- * Subject of list of chapters to allow updating the view without going to DB.
- */
- private val chaptersRelay: PublishRelay<List<ChapterItem>> by lazy {
- PublishRelay.create<List<ChapterItem>>()
- }
- /**
- * Whether the chapter list has been requested to the source.
- */
- var hasRequested = false
- private set
- /**
- * Subscription to retrieve the new list of chapters from the source.
- */
- private var fetchChaptersJob: Job? = null
- /**
- * Subscription to observe download status changes.
- */
- private var observeDownloadsStatusSubscription: Subscription? = null
- private var observeDownloadsPageSubscription: Subscription? = null
- private var _trackList: List<TrackItem> = emptyList()
- val trackList get() = _trackList
- private val loggedServices by lazy { trackManager.services.filter { it.isLogged } }
- private var trackSubscription: Subscription? = null
- private var searchTrackerJob: Job? = null
- private var refreshTrackersJob: Job? = null
- override fun onCreate(savedState: Bundle?) {
- super.onCreate(savedState)
- if (!manga.favorite) {
- ChapterSettingsHelper.applySettingDefaults(manga)
- }
- // Manga info - start
- getMangaObservable()
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeLatestCache({ view, manga -> view.onNextMangaInfo(manga, source) })
- getTrackingObservable()
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeLatestCache(MangaController::onTrackingCount) { _, error -> Timber.e(error) }
- // Prepare the relay.
- chaptersRelay.flatMap { applyChapterFilters(it) }
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeLatestCache(MangaController::onNextChapters) { _, error -> Timber.e(error) }
- // Manga info - end
- // Chapters list - start
- // Add the subscription that retrieves the chapters from the database, keeps subscribed to
- // changes, and sends the list of chapters to the relay.
- add(
- db.getChapters(manga).asRxObservable()
- .map { chapters ->
- // Convert every chapter to a model.
- chapters.map { it.toModel() }
- }
- .doOnNext { chapters ->
- // Find downloaded chapters
- setDownloadedChapters(chapters)
- // Store the last emission
- this.chapters = chapters
- // Listen for download status changes
- observeDownloads()
- }
- .subscribe { chaptersRelay.call(it) }
- )
- // Chapters list - end
- fetchTrackers()
- }
- // Manga info - start
- private fun getMangaObservable(): Observable<Manga> {
- return db.getManga(manga.url, manga.source).asRxObservable()
- }
- private fun getTrackingObservable(): Observable<Int> {
- if (!trackManager.hasLoggedServices()) {
- return Observable.just(0)
- }
- return db.getTracks(manga).asRxObservable()
- .map { tracks ->
- val loggedServices = trackManager.services.filter { it.isLogged }.map { it.id }
- tracks.filter { it.sync_id in loggedServices }
- }
- .map { it.size }
- }
- /**
- * Fetch manga information from source.
- */
- fun fetchMangaFromSource(manualFetch: Boolean = false) {
- if (fetchMangaJob?.isActive == true) return
- fetchMangaJob = presenterScope.launchIO {
- try {
- val networkManga = source.getMangaDetails(manga.toMangaInfo())
- val sManga = networkManga.toSManga()
- manga.prepUpdateCover(coverCache, sManga, manualFetch)
- manga.copyFrom(sManga)
- manga.initialized = true
- db.insertManga(manga).executeAsBlocking()
- withUIContext { view?.onFetchMangaInfoDone() }
- } catch (e: Throwable) {
- withUIContext { view?.onFetchMangaInfoError(e) }
- }
- }
- }
- /**
- * Update favorite status of manga, (removes / adds) manga (to / from) library.
- *
- * @return the new status of the manga.
- */
- fun toggleFavorite(): Boolean {
- manga.favorite = !manga.favorite
- manga.date_added = when (manga.favorite) {
- true -> Date().time
- false -> 0
- }
- if (!manga.favorite) {
- manga.removeCovers(coverCache)
- }
- db.insertManga(manga).executeAsBlocking()
- return manga.favorite
- }
- /**
- * Returns true if the manga has any downloads.
- */
- fun hasDownloads(): Boolean {
- return downloadManager.getDownloadCount(manga) > 0
- }
- /**
- * Deletes all the downloads for the manga.
- */
- fun deleteDownloads() {
- downloadManager.deleteManga(manga, source)
- }
- /**
- * Get user categories.
- *
- * @return List of categories, not including the default category
- */
- fun getCategories(): List<Category> {
- return db.getCategories().executeAsBlocking()
- }
- /**
- * Gets the category id's the manga is in, if the manga is not in a category, returns the default id.
- *
- * @param manga the manga to get categories from.
- * @return Array of category ids the manga is in, if none returns default id
- */
- fun getMangaCategoryIds(manga: Manga): Array<Int> {
- val categories = db.getCategoriesForManga(manga).executeAsBlocking()
- return categories.mapNotNull { it.id }.toTypedArray()
- }
- /**
- * Move the given manga to categories.
- *
- * @param manga the manga to move.
- * @param categories the selected categories.
- */
- fun moveMangaToCategories(manga: Manga, categories: List<Category>) {
- val mc = categories.filter { it.id != 0 }.map { MangaCategory.create(manga, it) }
- db.setMangaCategories(mc, listOf(manga))
- }
- /**
- * Move the given manga to the category.
- *
- * @param manga the manga to move.
- * @param category the selected category, or null for default category.
- */
- fun moveMangaToCategory(manga: Manga, category: Category?) {
- moveMangaToCategories(manga, listOfNotNull(category))
- }
- /**
- * Update cover with local file.
- *
- * @param manga the manga edited.
- * @param context Context.
- * @param data uri of the cover resource.
- */
- fun editCover(manga: Manga, context: Context, data: Uri) {
- Observable
- .fromCallable {
- context.contentResolver.openInputStream(data)?.use {
- if (manga.isLocal()) {
- LocalSource.updateCover(context, manga, it)
- manga.updateCoverLastModified(db)
- } else if (manga.favorite) {
- coverCache.setCustomCoverToCache(manga, it)
- manga.updateCoverLastModified(db)
- }
- }
- }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeFirst(
- { view, _ -> view.onSetCoverSuccess() },
- { view, e -> view.onSetCoverError(e) }
- )
- }
- fun deleteCustomCover(manga: Manga) {
- Observable
- .fromCallable {
- coverCache.deleteCustomCover(manga)
- manga.updateCoverLastModified(db)
- }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeFirst(
- { view, _ -> view.onSetCoverSuccess() },
- { view, e -> view.onSetCoverError(e) }
- )
- }
- // Manga info - end
- // Chapters list - start
- private fun observeDownloads() {
- observeDownloadsStatusSubscription?.let { remove(it) }
- observeDownloadsStatusSubscription = downloadManager.queue.getStatusObservable()
- .observeOn(Schedulers.io())
- .onBackpressureLatest()
- .filter { download -> download.manga.id == manga.id }
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeLatestCache(
- { view, it ->
- onDownloadStatusChange(it)
- view.onChapterDownloadUpdate(it)
- },
- { _, error ->
- Timber.e(error)
- }
- )
- observeDownloadsPageSubscription?.let { remove(it) }
- observeDownloadsPageSubscription = downloadManager.queue.getProgressObservable()
- .observeOn(Schedulers.io())
- .onBackpressureLatest()
- .filter { download -> download.manga.id == manga.id }
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeLatestCache(MangaController::onChapterDownloadUpdate) { _, error ->
- Timber.e(error)
- }
- }
- /**
- * Converts a chapter from the database to an extended model, allowing to store new fields.
- */
- private fun Chapter.toModel(): ChapterItem {
- // Create the model object.
- val model = ChapterItem(this, manga)
- // Find an active download for this chapter.
- val download = downloadManager.queue.find { it.chapter.id == id }
- if (download != null) {
- // If there's an active download, assign it.
- model.download = download
- }
- return model
- }
- /**
- * Finds and assigns the list of downloaded chapters.
- *
- * @param chapters the list of chapter from the database.
- */
- private fun setDownloadedChapters(chapters: List<ChapterItem>) {
- chapters
- .filter { downloadManager.isChapterDownloaded(it, manga) }
- .forEach { it.status = Download.State.DOWNLOADED }
- }
- /**
- * Requests an updated list of chapters from the source.
- */
- fun fetchChaptersFromSource(manualFetch: Boolean = false) {
- hasRequested = true
- if (fetchChaptersJob?.isActive == true) return
- fetchChaptersJob = presenterScope.launchIO {
- try {
- val chapters = source.getChapterList(manga.toMangaInfo())
- .map { it.toSChapter() }
- val (newChapters, _) = syncChaptersWithSource(db, chapters, manga, source)
- if (manualFetch) {
- downloadNewChapters(newChapters)
- }
- withUIContext { view?.onFetchChaptersDone() }
- } catch (e: Throwable) {
- withUIContext { view?.onFetchChaptersError(e) }
- }
- }
- }
- /**
- * Updates the UI after applying the filters.
- */
- private fun refreshChapters() {
- chaptersRelay.call(chapters)
- }
- /**
- * Applies the view filters to the list of chapters obtained from the database.
- * @param chapters the list of chapters from the database
- * @return an observable of the list of chapters filtered and sorted.
- */
- private fun applyChapterFilters(chapters: List<ChapterItem>): Observable<List<ChapterItem>> {
- var observable = Observable.from(chapters).subscribeOn(Schedulers.io())
- val unreadFilter = onlyUnread()
- if (unreadFilter == State.INCLUDE) {
- observable = observable.filter { !it.read }
- } else if (unreadFilter == State.EXCLUDE) {
- observable = observable.filter { it.read }
- }
- val downloadedFilter = onlyDownloaded()
- if (downloadedFilter == State.INCLUDE) {
- observable = observable.filter { it.isDownloaded || it.manga.isLocal() }
- } else if (downloadedFilter == State.EXCLUDE) {
- observable = observable.filter { !it.isDownloaded && !it.manga.isLocal() }
- }
- val bookmarkedFilter = onlyBookmarked()
- if (bookmarkedFilter == State.INCLUDE) {
- observable = observable.filter { it.bookmark }
- } else if (bookmarkedFilter == State.EXCLUDE) {
- observable = observable.filter { !it.bookmark }
- }
- return observable.toSortedList(getChapterSort())
- }
- fun getChapterSort(): (Chapter, Chapter) -> Int {
- return when (manga.sorting) {
- Manga.SORTING_SOURCE -> when (sortDescending()) {
- true -> { c1, c2 -> c1.source_order.compareTo(c2.source_order) }
- false -> { c1, c2 -> c2.source_order.compareTo(c1.source_order) }
- }
- Manga.SORTING_NUMBER -> when (sortDescending()) {
- true -> { c1, c2 -> c2.chapter_number.compareTo(c1.chapter_number) }
- false -> { c1, c2 -> c1.chapter_number.compareTo(c2.chapter_number) }
- }
- Manga.SORTING_UPLOAD_DATE -> when (sortDescending()) {
- true -> { c1, c2 -> c2.date_upload.compareTo(c1.date_upload) }
- false -> { c1, c2 -> c1.date_upload.compareTo(c2.date_upload) }
- }
- else -> throw NotImplementedError("Unimplemented sorting method")
- }
- }
- /**
- * Called when a download for the active manga changes status.
- * @param download the download whose status changed.
- */
- private fun onDownloadStatusChange(download: Download) {
- // Assign the download to the model object.
- if (download.status == Download.State.QUEUE) {
- chapters.find { it.id == download.chapter.id }?.let {
- if (it.download == null) {
- it.download = download
- }
- }
- }
- // Force UI update if downloaded filter active and download finished.
- if (onlyDownloaded() != State.IGNORE && download.status == Download.State.DOWNLOADED) {
- refreshChapters()
- }
- }
- /**
- * Returns the next unread chapter or null if everything is read.
- */
- fun getNextUnreadChapter(): ChapterItem? {
- return chapters.sortedWith(getChapterSort()).findLast { !it.read }
- }
- /**
- * Mark the selected chapter list as read/unread.
- * @param selectedChapters the list of selected chapters.
- * @param read whether to mark chapters as read or unread.
- */
- fun markChaptersRead(selectedChapters: List<ChapterItem>, read: Boolean) {
- val chapters = selectedChapters.map { chapter ->
- chapter.read = read
- if (!read) {
- chapter.last_page_read = 0
- }
- chapter
- }
- launchIO {
- db.updateChaptersProgress(chapters).executeAsBlocking()
- if (preferences.removeAfterMarkedAsRead()) {
- deleteChapters(chapters.filter { it.read })
- }
- }
- }
- /**
- * Downloads the given list of chapters with the manager.
- * @param chapters the list of chapters to download.
- */
- fun downloadChapters(chapters: List<Chapter>) {
- downloadManager.downloadChapters(manga, chapters)
- }
- /**
- * Bookmarks the given list of chapters.
- * @param selectedChapters the list of chapters to bookmark.
- */
- fun bookmarkChapters(selectedChapters: List<ChapterItem>, bookmarked: Boolean) {
- launchIO {
- selectedChapters
- .forEach {
- it.bookmark = bookmarked
- db.updateChapterProgress(it).executeAsBlocking()
- }
- }
- }
- /**
- * Deletes the given list of chapter.
- * @param chapters the list of chapters to delete.
- */
- fun deleteChapters(chapters: List<ChapterItem>) {
- launchIO {
- try {
- downloadManager.deleteChapters(chapters, manga, source).forEach {
- if (it is ChapterItem) {
- it.status = Download.State.NOT_DOWNLOADED
- it.download = null
- }
- }
- if (onlyDownloaded() != State.IGNORE) {
- refreshChapters()
- }
- view?.onChaptersDeleted(chapters)
- } catch (e: Throwable) {
- view?.onChaptersDeletedError(e)
- }
- }
- }
- private fun downloadNewChapters(chapters: List<Chapter>) {
- if (chapters.isEmpty() || !manga.shouldDownloadNewChapters(db, preferences)) return
- downloadChapters(chapters)
- }
- /**
- * Reverses the sorting and requests an UI update.
- */
- fun reverseSortOrder() {
- manga.setChapterOrder(if (sortDescending()) Manga.SORT_ASC else Manga.SORT_DESC)
- db.updateFlags(manga).executeAsBlocking()
- refreshChapters()
- }
- /**
- * Sets the read filter and requests an UI update.
- * @param state whether to display only unread chapters or all chapters.
- */
- fun setUnreadFilter(state: State) {
- manga.readFilter = when (state) {
- State.IGNORE -> Manga.SHOW_ALL
- State.INCLUDE -> Manga.SHOW_UNREAD
- State.EXCLUDE -> Manga.SHOW_READ
- }
- db.updateFlags(manga).executeAsBlocking()
- refreshChapters()
- }
- /**
- * Sets the download filter and requests an UI update.
- * @param state whether to display only downloaded chapters or all chapters.
- */
- fun setDownloadedFilter(state: State) {
- manga.downloadedFilter = when (state) {
- State.IGNORE -> Manga.SHOW_ALL
- State.INCLUDE -> Manga.SHOW_DOWNLOADED
- State.EXCLUDE -> Manga.SHOW_NOT_DOWNLOADED
- }
- db.updateFlags(manga).executeAsBlocking()
- refreshChapters()
- }
- /**
- * Sets the bookmark filter and requests an UI update.
- * @param state whether to display only bookmarked chapters or all chapters.
- */
- fun setBookmarkedFilter(state: State) {
- manga.bookmarkedFilter = when (state) {
- State.IGNORE -> Manga.SHOW_ALL
- State.INCLUDE -> Manga.SHOW_BOOKMARKED
- State.EXCLUDE -> Manga.SHOW_NOT_BOOKMARKED
- }
- db.updateFlags(manga).executeAsBlocking()
- refreshChapters()
- }
- /**
- * Sets the active display mode.
- * @param mode the mode to set.
- */
- fun setDisplayMode(mode: Int) {
- manga.displayMode = mode
- db.updateFlags(manga).executeAsBlocking()
- }
- /**
- * Sets the sorting method and requests an UI update.
- * @param sort the sorting mode.
- */
- fun setSorting(sort: Int) {
- manga.sorting = sort
- db.updateFlags(manga).executeAsBlocking()
- refreshChapters()
- }
- /**
- * Whether downloaded only mode is enabled.
- */
- fun forceDownloaded(): Boolean {
- return manga.favorite && preferences.downloadedOnly().get()
- }
- /**
- * Whether the display only downloaded filter is enabled.
- */
- fun onlyDownloaded(): State {
- if (forceDownloaded()) {
- return State.INCLUDE
- }
- return when (manga.downloadedFilter) {
- Manga.SHOW_DOWNLOADED -> State.INCLUDE
- Manga.SHOW_NOT_DOWNLOADED -> State.EXCLUDE
- else -> State.IGNORE
- }
- }
- /**
- * Whether the display only downloaded filter is enabled.
- */
- fun onlyBookmarked(): State {
- return when (manga.bookmarkedFilter) {
- Manga.SHOW_BOOKMARKED -> State.INCLUDE
- Manga.SHOW_NOT_BOOKMARKED -> State.EXCLUDE
- else -> State.IGNORE
- }
- }
- /**
- * Whether the display only unread filter is enabled.
- */
- fun onlyUnread(): State {
- return when (manga.readFilter) {
- Manga.SHOW_UNREAD -> State.INCLUDE
- Manga.SHOW_READ -> State.EXCLUDE
- else -> State.IGNORE
- }
- }
- /**
- * Whether the sorting method is descending or ascending.
- */
- fun sortDescending(): Boolean {
- return manga.sortDescending()
- }
- // Chapters list - end
- // Track sheet - start
- private fun fetchTrackers() {
- trackSubscription?.let { remove(it) }
- trackSubscription = db.getTracks(manga)
- .asRxObservable()
- .map { tracks ->
- loggedServices.map { service ->
- TrackItem(tracks.find { it.sync_id == service.id }, service)
- }
- }
- .observeOn(AndroidSchedulers.mainThread())
- .doOnNext { _trackList = it }
- .subscribeLatestCache(MangaController::onNextTrackers)
- }
- fun refreshTrackers() {
- refreshTrackersJob?.cancel()
- refreshTrackersJob = launchIO {
- supervisorScope {
- try {
- trackList
- .filter { it.track != null }
- .map {
- async {
- val track = it.service.refresh(it.track!!)
- db.insertTrack(track).executeAsBlocking()
- }
- }
- .awaitAll()
- withUIContext { view?.onTrackingRefreshDone() }
- } catch (e: Throwable) {
- withUIContext { view?.onTrackingRefreshError(e) }
- }
- }
- }
- }
- fun trackingSearch(query: String, service: TrackService) {
- searchTrackerJob?.cancel()
- searchTrackerJob = launchIO {
- try {
- val results = service.search(query)
- withUIContext { view?.onTrackingSearchResults(results) }
- } catch (e: Throwable) {
- withUIContext { view?.onTrackingSearchResultsError(e) }
- }
- }
- }
- fun registerTracking(item: Track?, service: TrackService) {
- if (item != null) {
- item.manga_id = manga.id!!
- launchIO {
- try {
- service.bind(item)
- db.insertTrack(item).executeAsBlocking()
- } catch (e: Throwable) {
- withUIContext { view?.applicationContext?.toast(e.message) }
- }
- }
- } else {
- unregisterTracking(service)
- }
- }
- fun unregisterTracking(service: TrackService) {
- db.deleteTrackForManga(manga, service).executeAsBlocking()
- }
- private fun updateRemote(track: Track, service: TrackService) {
- launchIO {
- try {
- service.update(track)
- db.insertTrack(track).executeAsBlocking()
- withUIContext { view?.onTrackingRefreshDone() }
- } catch (e: Throwable) {
- withUIContext { view?.onTrackingRefreshError(e) }
- // Restart on error to set old values
- fetchTrackers()
- }
- }
- }
- fun setTrackerStatus(item: TrackItem, index: Int) {
- val track = item.track!!
- track.status = item.service.getStatusList()[index]
- if (track.status == item.service.getCompletionStatus() && track.total_chapters != 0) {
- track.last_chapter_read = track.total_chapters
- }
- updateRemote(track, item.service)
- }
- fun setTrackerScore(item: TrackItem, index: Int) {
- val track = item.track!!
- track.score = item.service.indexToScore(index)
- updateRemote(track, item.service)
- }
- fun setTrackerLastChapterRead(item: TrackItem, chapterNumber: Int) {
- val track = item.track!!
- track.last_chapter_read = chapterNumber
- if (track.total_chapters != 0 && track.last_chapter_read == track.total_chapters) {
- track.status = item.service.getCompletionStatus()
- }
- updateRemote(track, item.service)
- }
- fun setTrackerStartDate(item: TrackItem, date: Long) {
- val track = item.track!!
- track.started_reading_date = date
- updateRemote(track, item.service)
- }
- fun setTrackerFinishDate(item: TrackItem, date: Long) {
- val track = item.track!!
- track.finished_reading_date = date
- updateRemote(track, item.service)
- }
- // Track sheet - end
- }
|