mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	Move tracking to a bottom sheet (#4364)
* Move tracking to a bottom sheet * Give methods better names and remove unnecessary annotation
This commit is contained in:
		@@ -37,6 +37,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.data.download.DownloadService
 | 
			
		||||
import eu.kanade.tachiyomi.data.download.model.Download
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
 | 
			
		||||
import eu.kanade.tachiyomi.databinding.MangaControllerBinding
 | 
			
		||||
import eu.kanade.tachiyomi.source.LocalSource
 | 
			
		||||
import eu.kanade.tachiyomi.source.Source
 | 
			
		||||
@@ -62,7 +63,9 @@ import eu.kanade.tachiyomi.ui.manga.chapter.DownloadCustomChaptersDialog
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.chapter.MangaChaptersHeaderAdapter
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.chapter.base.BaseChaptersAdapter
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoHeaderAdapter
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.track.TrackController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.track.TrackItem
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.track.TrackSearchDialog
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.track.TrackSheet
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
 | 
			
		||||
import eu.kanade.tachiyomi.ui.recent.history.HistoryController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController
 | 
			
		||||
@@ -160,6 +163,8 @@ class MangaController :
 | 
			
		||||
    private var isRefreshingInfo = false
 | 
			
		||||
    private var isRefreshingChapters = false
 | 
			
		||||
 | 
			
		||||
    private var trackSheet: TrackSheet? = null
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        setHasOptionsMenu(true)
 | 
			
		||||
    }
 | 
			
		||||
@@ -246,6 +251,8 @@ class MangaController :
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        trackSheet = TrackSheet(this, manga!!)
 | 
			
		||||
 | 
			
		||||
        updateFilterIconState()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -461,7 +468,7 @@ class MangaController :
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onTrackingClick() {
 | 
			
		||||
        router.pushController(TrackController(manga).withFadeTransaction())
 | 
			
		||||
        trackSheet?.show()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun addToLibrary(manga: Manga) {
 | 
			
		||||
@@ -1030,6 +1037,35 @@ class MangaController :
 | 
			
		||||
 | 
			
		||||
    // Chapters list - end
 | 
			
		||||
 | 
			
		||||
    // Tracker sheet - start
 | 
			
		||||
    fun onNextTrackers(trackers: List<TrackItem>) {
 | 
			
		||||
        trackSheet?.onNextTrackers(trackers)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onTrackingRefreshDone() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onTrackingRefreshError(error: Throwable) {
 | 
			
		||||
        Timber.e(error)
 | 
			
		||||
        activity?.toast(error.message)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onTrackingSearchResults(results: List<TrackSearch>) {
 | 
			
		||||
        getTrackingSearchDialog()?.onSearchResults(results)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onTrackingSearchResultsError(error: Throwable) {
 | 
			
		||||
        Timber.e(error)
 | 
			
		||||
        activity?.toast(error.message)
 | 
			
		||||
        getTrackingSearchDialog()?.onSearchResultsError()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun getTrackingSearchDialog(): TrackSearchDialog? {
 | 
			
		||||
        return trackSheet?.getSearchDialog()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Tracker sheet - end
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        const val FROM_SOURCE_EXTRA = "from_source"
 | 
			
		||||
        const val MANGA_EXTRA = "manga"
 | 
			
		||||
 
 | 
			
		||||
@@ -10,17 +10,20 @@ 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
 | 
			
		||||
@@ -29,9 +32,13 @@ 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
 | 
			
		||||
@@ -86,6 +93,15 @@ class MangaPresenter(
 | 
			
		||||
    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 searchJob: Job? = null
 | 
			
		||||
    private var refreshJob: Job? = null
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedState: Bundle?) {
 | 
			
		||||
        super.onCreate(savedState)
 | 
			
		||||
 | 
			
		||||
@@ -134,6 +150,8 @@ class MangaPresenter(
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        // Chapters list - end
 | 
			
		||||
 | 
			
		||||
        fetchTrackers()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Manga info - start
 | 
			
		||||
@@ -645,4 +663,128 @@ class MangaPresenter(
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 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 trackingRefresh() {
 | 
			
		||||
        refreshJob?.cancel()
 | 
			
		||||
        refreshJob = 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) {
 | 
			
		||||
        searchJob?.cancel()
 | 
			
		||||
        searchJob = 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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,14 +16,17 @@ import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
 | 
			
		||||
class SetTrackChaptersDialog<T> : DialogController
 | 
			
		||||
        where T : Controller, T : SetTrackChaptersDialog.Listener {
 | 
			
		||||
        where T : Controller {
 | 
			
		||||
 | 
			
		||||
    private val item: TrackItem
 | 
			
		||||
 | 
			
		||||
    constructor(target: T, item: TrackItem) : super(
 | 
			
		||||
    private lateinit var listener: Listener
 | 
			
		||||
 | 
			
		||||
    constructor(target: T, listener: Listener, item: TrackItem) : super(
 | 
			
		||||
        bundleOf(KEY_ITEM_TRACK to item.track)
 | 
			
		||||
    ) {
 | 
			
		||||
        targetController = target
 | 
			
		||||
        this.listener = listener
 | 
			
		||||
        this.item = item
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -46,7 +49,7 @@ class SetTrackChaptersDialog<T> : DialogController
 | 
			
		||||
                val np: NumberPicker = view.findViewById(R.id.chapters_picker)
 | 
			
		||||
                np.clearFocus()
 | 
			
		||||
 | 
			
		||||
                (targetController as? Listener)?.setChaptersRead(item, np.value)
 | 
			
		||||
                listener.setChaptersRead(item, np.value)
 | 
			
		||||
            }
 | 
			
		||||
            .negativeButton(android.R.string.cancel)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,16 +15,19 @@ import uy.kohesive.injekt.api.get
 | 
			
		||||
import java.util.Calendar
 | 
			
		||||
 | 
			
		||||
class SetTrackReadingDatesDialog<T> : DialogController
 | 
			
		||||
        where T : Controller, T : SetTrackReadingDatesDialog.Listener {
 | 
			
		||||
        where T : Controller {
 | 
			
		||||
 | 
			
		||||
    private val item: TrackItem
 | 
			
		||||
 | 
			
		||||
    private val dateToUpdate: ReadingDate
 | 
			
		||||
 | 
			
		||||
    constructor(target: T, dateToUpdate: ReadingDate, item: TrackItem) : super(
 | 
			
		||||
    private lateinit var listener: Listener
 | 
			
		||||
 | 
			
		||||
    constructor(target: T, listener: Listener, dateToUpdate: ReadingDate, item: TrackItem) : super(
 | 
			
		||||
        bundleOf(KEY_ITEM_TRACK to item.track)
 | 
			
		||||
    ) {
 | 
			
		||||
        targetController = target
 | 
			
		||||
        this.listener = listener
 | 
			
		||||
        this.item = item
 | 
			
		||||
        this.dateToUpdate = dateToUpdate
 | 
			
		||||
    }
 | 
			
		||||
@@ -38,8 +41,6 @@ class SetTrackReadingDatesDialog<T> : DialogController
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onCreateDialog(savedViewState: Bundle?): Dialog {
 | 
			
		||||
        val listener = (targetController as? Listener)
 | 
			
		||||
 | 
			
		||||
        return MaterialDialog(activity!!)
 | 
			
		||||
            .title(
 | 
			
		||||
                when (dateToUpdate) {
 | 
			
		||||
 
 | 
			
		||||
@@ -16,14 +16,17 @@ import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
 | 
			
		||||
class SetTrackScoreDialog<T> : DialogController
 | 
			
		||||
        where T : Controller, T : SetTrackScoreDialog.Listener {
 | 
			
		||||
        where T : Controller {
 | 
			
		||||
 | 
			
		||||
    private val item: TrackItem
 | 
			
		||||
 | 
			
		||||
    constructor(target: T, item: TrackItem) : super(
 | 
			
		||||
    private lateinit var listener: Listener
 | 
			
		||||
 | 
			
		||||
    constructor(target: T, listener: Listener, item: TrackItem) : super(
 | 
			
		||||
        bundleOf(KEY_ITEM_TRACK to item.track)
 | 
			
		||||
    ) {
 | 
			
		||||
        targetController = target
 | 
			
		||||
        this.listener = listener
 | 
			
		||||
        this.item = item
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -46,7 +49,7 @@ class SetTrackScoreDialog<T> : DialogController
 | 
			
		||||
                val np: NumberPicker = view.findViewById(R.id.score_picker)
 | 
			
		||||
                np.clearFocus()
 | 
			
		||||
 | 
			
		||||
                (targetController as? Listener)?.setScore(item, np.value)
 | 
			
		||||
                listener.setScore(item, np.value)
 | 
			
		||||
            }
 | 
			
		||||
            .negativeButton(android.R.string.cancel)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -14,14 +14,17 @@ import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
 | 
			
		||||
class SetTrackStatusDialog<T> : DialogController
 | 
			
		||||
        where T : Controller, T : SetTrackStatusDialog.Listener {
 | 
			
		||||
        where T : Controller {
 | 
			
		||||
 | 
			
		||||
    private val item: TrackItem
 | 
			
		||||
 | 
			
		||||
    constructor(target: T, item: TrackItem) : super(
 | 
			
		||||
    private lateinit var listener: Listener
 | 
			
		||||
 | 
			
		||||
    constructor(target: T, listener: Listener, item: TrackItem) : super(
 | 
			
		||||
        bundleOf(KEY_ITEM_TRACK to item.track)
 | 
			
		||||
    ) {
 | 
			
		||||
        targetController = target
 | 
			
		||||
        this.listener = listener
 | 
			
		||||
        this.item = item
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -46,7 +49,7 @@ class SetTrackStatusDialog<T> : DialogController
 | 
			
		||||
                initialSelection = selectedIndex,
 | 
			
		||||
                waitForPositiveButton = false
 | 
			
		||||
            ) { dialog, position, _ ->
 | 
			
		||||
                (targetController as? Listener)?.setStatus(item, position)
 | 
			
		||||
                listener.setStatus(item, position)
 | 
			
		||||
                dialog.dismiss()
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ import android.view.ViewGroup
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import eu.kanade.tachiyomi.databinding.TrackItemBinding
 | 
			
		||||
 | 
			
		||||
class TrackAdapter(controller: TrackController) : RecyclerView.Adapter<TrackHolder>() {
 | 
			
		||||
class TrackAdapter(listener: OnClickListener) : RecyclerView.Adapter<TrackHolder>() {
 | 
			
		||||
 | 
			
		||||
    private lateinit var binding: TrackItemBinding
 | 
			
		||||
 | 
			
		||||
@@ -17,7 +17,7 @@ class TrackAdapter(controller: TrackController) : RecyclerView.Adapter<TrackHold
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    val rowClickListener: OnClickListener = controller
 | 
			
		||||
    val rowClickListener: OnClickListener = listener
 | 
			
		||||
 | 
			
		||||
    fun getItem(index: Int): TrackItem? {
 | 
			
		||||
        return items.getOrNull(index)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,200 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.manga.track
 | 
			
		||||
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import androidx.core.net.toUri
 | 
			
		||||
import androidx.core.os.bundleOf
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
 | 
			
		||||
import eu.kanade.tachiyomi.databinding.TrackControllerBinding
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.toast
 | 
			
		||||
import kotlinx.coroutines.flow.launchIn
 | 
			
		||||
import kotlinx.coroutines.flow.onEach
 | 
			
		||||
import reactivecircus.flowbinding.swiperefreshlayout.refreshes
 | 
			
		||||
import timber.log.Timber
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
 | 
			
		||||
class TrackController :
 | 
			
		||||
    NucleusController<TrackControllerBinding, TrackPresenter>,
 | 
			
		||||
    TrackAdapter.OnClickListener,
 | 
			
		||||
    SetTrackStatusDialog.Listener,
 | 
			
		||||
    SetTrackChaptersDialog.Listener,
 | 
			
		||||
    SetTrackScoreDialog.Listener,
 | 
			
		||||
    SetTrackReadingDatesDialog.Listener {
 | 
			
		||||
 | 
			
		||||
    constructor(manga: Manga?) : super(
 | 
			
		||||
        bundleOf(MANGA_EXTRA to (manga?.id ?: 0))
 | 
			
		||||
    ) {
 | 
			
		||||
        this.manga = manga
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    constructor(mangaId: Long) : this(
 | 
			
		||||
        Injekt.get<DatabaseHelper>().getManga(mangaId).executeAsBlocking()
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    @Suppress("unused")
 | 
			
		||||
    constructor(bundle: Bundle) : this(bundle.getLong(MANGA_EXTRA))
 | 
			
		||||
 | 
			
		||||
    var manga: Manga? = null
 | 
			
		||||
        private set
 | 
			
		||||
 | 
			
		||||
    private var adapter: TrackAdapter? = null
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        // There's no menu, but this avoids a bug when coming from the catalogue, where the menu
 | 
			
		||||
        // disappears if the searchview is expanded
 | 
			
		||||
        setHasOptionsMenu(true)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getTitle(): String? {
 | 
			
		||||
        return manga?.title
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun createPresenter(): TrackPresenter {
 | 
			
		||||
        return TrackPresenter(manga!!)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
 | 
			
		||||
        binding = TrackControllerBinding.inflate(inflater)
 | 
			
		||||
        return binding.root
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onViewCreated(view: View) {
 | 
			
		||||
        super.onViewCreated(view)
 | 
			
		||||
 | 
			
		||||
        if (manga == null) return
 | 
			
		||||
 | 
			
		||||
        adapter = TrackAdapter(this)
 | 
			
		||||
        binding.trackRecycler.layoutManager = LinearLayoutManager(view.context)
 | 
			
		||||
        binding.trackRecycler.adapter = adapter
 | 
			
		||||
        binding.swipeRefresh.isEnabled = false
 | 
			
		||||
        binding.swipeRefresh.refreshes()
 | 
			
		||||
            .onEach { presenter.refresh() }
 | 
			
		||||
            .launchIn(viewScope)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onDestroyView(view: View) {
 | 
			
		||||
        adapter = null
 | 
			
		||||
        super.onDestroyView(view)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onNextTrackings(trackings: List<TrackItem>) {
 | 
			
		||||
        val atLeastOneLink = trackings.any { it.track != null }
 | 
			
		||||
        adapter?.items = trackings
 | 
			
		||||
        binding.swipeRefresh.isEnabled = atLeastOneLink
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onSearchResults(results: List<TrackSearch>) {
 | 
			
		||||
        getSearchDialog()?.onSearchResults(results)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Suppress("UNUSED_PARAMETER")
 | 
			
		||||
    fun onSearchResultsError(error: Throwable) {
 | 
			
		||||
        Timber.e(error)
 | 
			
		||||
        activity?.toast(error.message)
 | 
			
		||||
        getSearchDialog()?.onSearchResultsError()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun getSearchDialog(): TrackSearchDialog? {
 | 
			
		||||
        return router.getControllerWithTag(TAG_SEARCH_CONTROLLER) as? TrackSearchDialog
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onRefreshDone() {
 | 
			
		||||
        binding.swipeRefresh.isRefreshing = false
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onRefreshError(error: Throwable) {
 | 
			
		||||
        binding.swipeRefresh.isRefreshing = false
 | 
			
		||||
        activity?.toast(error.message)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onLogoClick(position: Int) {
 | 
			
		||||
        val track = adapter?.getItem(position)?.track ?: return
 | 
			
		||||
 | 
			
		||||
        if (track.tracking_url.isNotBlank()) {
 | 
			
		||||
            activity?.startActivity(Intent(Intent.ACTION_VIEW, track.tracking_url.toUri()))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onSetClick(position: Int) {
 | 
			
		||||
        val item = adapter?.getItem(position) ?: return
 | 
			
		||||
        TrackSearchDialog(this, item.service).showDialog(router, TAG_SEARCH_CONTROLLER)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onTitleLongClick(position: Int) {
 | 
			
		||||
        adapter?.getItem(position)?.track?.title?.let {
 | 
			
		||||
            activity?.copyToClipboard(it, it)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onStatusClick(position: Int) {
 | 
			
		||||
        val item = adapter?.getItem(position) ?: return
 | 
			
		||||
        if (item.track == null) return
 | 
			
		||||
 | 
			
		||||
        SetTrackStatusDialog(this, item).showDialog(router)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onChaptersClick(position: Int) {
 | 
			
		||||
        val item = adapter?.getItem(position) ?: return
 | 
			
		||||
        if (item.track == null) return
 | 
			
		||||
 | 
			
		||||
        SetTrackChaptersDialog(this, item).showDialog(router)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onScoreClick(position: Int) {
 | 
			
		||||
        val item = adapter?.getItem(position) ?: return
 | 
			
		||||
        if (item.track == null) return
 | 
			
		||||
 | 
			
		||||
        SetTrackScoreDialog(this, item).showDialog(router)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onStartDateClick(position: Int) {
 | 
			
		||||
        val item = adapter?.getItem(position) ?: return
 | 
			
		||||
        if (item.track == null) return
 | 
			
		||||
 | 
			
		||||
        SetTrackReadingDatesDialog(this, SetTrackReadingDatesDialog.ReadingDate.Start, item).showDialog(router)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onFinishDateClick(position: Int) {
 | 
			
		||||
        val item = adapter?.getItem(position) ?: return
 | 
			
		||||
        if (item.track == null) return
 | 
			
		||||
 | 
			
		||||
        SetTrackReadingDatesDialog(this, SetTrackReadingDatesDialog.ReadingDate.Finish, item).showDialog(router)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun setStatus(item: TrackItem, selection: Int) {
 | 
			
		||||
        presenter.setStatus(item, selection)
 | 
			
		||||
        binding.swipeRefresh.isRefreshing = true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun setScore(item: TrackItem, score: Int) {
 | 
			
		||||
        presenter.setScore(item, score)
 | 
			
		||||
        binding.swipeRefresh.isRefreshing = true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun setChaptersRead(item: TrackItem, chaptersRead: Int) {
 | 
			
		||||
        presenter.setLastChapterRead(item, chaptersRead)
 | 
			
		||||
        binding.swipeRefresh.isRefreshing = true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun setReadingDate(item: TrackItem, type: SetTrackReadingDatesDialog.ReadingDate, date: Long) {
 | 
			
		||||
        when (type) {
 | 
			
		||||
            SetTrackReadingDatesDialog.ReadingDate.Start -> presenter.setStartDate(item, date)
 | 
			
		||||
            SetTrackReadingDatesDialog.ReadingDate.Finish -> presenter.setFinishDate(item, date)
 | 
			
		||||
        }
 | 
			
		||||
        binding.swipeRefresh.isRefreshing = true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private companion object {
 | 
			
		||||
        const val MANGA_EXTRA = "manga"
 | 
			
		||||
        const val TAG_SEARCH_CONTROLLER = "track_search_controller"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,164 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.manga.track
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Track
 | 
			
		||||
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.ui.base.presenter.BasePresenter
 | 
			
		||||
import eu.kanade.tachiyomi.util.lang.launchIO
 | 
			
		||||
import eu.kanade.tachiyomi.util.lang.withUIContext
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.toast
 | 
			
		||||
import kotlinx.coroutines.Job
 | 
			
		||||
import kotlinx.coroutines.async
 | 
			
		||||
import kotlinx.coroutines.awaitAll
 | 
			
		||||
import kotlinx.coroutines.supervisorScope
 | 
			
		||||
import rx.Subscription
 | 
			
		||||
import rx.android.schedulers.AndroidSchedulers
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
 | 
			
		||||
class TrackPresenter(
 | 
			
		||||
    val manga: Manga,
 | 
			
		||||
    preferences: PreferencesHelper = Injekt.get(),
 | 
			
		||||
    private val db: DatabaseHelper = Injekt.get(),
 | 
			
		||||
    private val trackManager: TrackManager = Injekt.get()
 | 
			
		||||
) : BasePresenter<TrackController>() {
 | 
			
		||||
 | 
			
		||||
    private val context = preferences.context
 | 
			
		||||
 | 
			
		||||
    private var trackList: List<TrackItem> = emptyList()
 | 
			
		||||
 | 
			
		||||
    private val loggedServices by lazy { trackManager.services.filter { it.isLogged } }
 | 
			
		||||
 | 
			
		||||
    private var trackSubscription: Subscription? = null
 | 
			
		||||
    private var searchJob: Job? = null
 | 
			
		||||
    private var refreshJob: Job? = null
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedState: Bundle?) {
 | 
			
		||||
        super.onCreate(savedState)
 | 
			
		||||
        fetchTrackings()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun fetchTrackings() {
 | 
			
		||||
        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(TrackController::onNextTrackings)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun refresh() {
 | 
			
		||||
        refreshJob?.cancel()
 | 
			
		||||
        refreshJob = launchIO {
 | 
			
		||||
            supervisorScope {
 | 
			
		||||
                try {
 | 
			
		||||
                    trackList
 | 
			
		||||
                        .filter { it.track != null }
 | 
			
		||||
                        .map {
 | 
			
		||||
                            async {
 | 
			
		||||
                                val track = it.service.refresh(it.track!!)
 | 
			
		||||
                                db.insertTrack(track).executeAsBlocking()
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        .awaitAll()
 | 
			
		||||
 | 
			
		||||
                    withUIContext { view?.onRefreshDone() }
 | 
			
		||||
                } catch (e: Throwable) {
 | 
			
		||||
                    withUIContext { view?.onRefreshError(e) }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun search(query: String, service: TrackService) {
 | 
			
		||||
        searchJob?.cancel()
 | 
			
		||||
        searchJob = launchIO {
 | 
			
		||||
            try {
 | 
			
		||||
                val results = service.search(query)
 | 
			
		||||
                withUIContext { view?.onSearchResults(results) }
 | 
			
		||||
            } catch (e: Throwable) {
 | 
			
		||||
                withUIContext { view?.onSearchResultsError(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 { context.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?.onRefreshDone() }
 | 
			
		||||
            } catch (e: Throwable) {
 | 
			
		||||
                withUIContext { view?.onRefreshError(e) }
 | 
			
		||||
 | 
			
		||||
                // Restart on error to set old values
 | 
			
		||||
                fetchTrackings()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setStatus(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 setScore(item: TrackItem, index: Int) {
 | 
			
		||||
        val track = item.track!!
 | 
			
		||||
        track.score = item.service.indexToScore(index)
 | 
			
		||||
        updateRemote(track, item.service)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setLastChapterRead(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 setStartDate(item: TrackItem, date: Long) {
 | 
			
		||||
        val track = item.track!!
 | 
			
		||||
        track.started_reading_date = date
 | 
			
		||||
        updateRemote(track, item.service)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setFinishDate(item: TrackItem, date: Long) {
 | 
			
		||||
        val track = item.track!!
 | 
			
		||||
        track.finished_reading_date = date
 | 
			
		||||
        updateRemote(track, item.service)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -15,6 +15,7 @@ import eu.kanade.tachiyomi.data.track.TrackService
 | 
			
		||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
 | 
			
		||||
import eu.kanade.tachiyomi.databinding.TrackSearchDialogBinding
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.MangaController
 | 
			
		||||
import kotlinx.coroutines.flow.debounce
 | 
			
		||||
import kotlinx.coroutines.flow.filter
 | 
			
		||||
import kotlinx.coroutines.flow.launchIn
 | 
			
		||||
@@ -36,9 +37,9 @@ class TrackSearchDialog : DialogController {
 | 
			
		||||
    private val service: TrackService
 | 
			
		||||
 | 
			
		||||
    private val trackController
 | 
			
		||||
        get() = targetController as TrackController
 | 
			
		||||
        get() = targetController as MangaController
 | 
			
		||||
 | 
			
		||||
    constructor(target: TrackController, service: TrackService) : super(
 | 
			
		||||
    constructor(target: MangaController, service: TrackService) : super(
 | 
			
		||||
        bundleOf(KEY_SERVICE to service.id)
 | 
			
		||||
    ) {
 | 
			
		||||
        targetController = target
 | 
			
		||||
@@ -105,7 +106,7 @@ class TrackSearchDialog : DialogController {
 | 
			
		||||
        val binding = binding ?: return
 | 
			
		||||
        binding.progress.isVisible = true
 | 
			
		||||
        binding.trackSearchList.isVisible = false
 | 
			
		||||
        trackController.presenter.search(query, service)
 | 
			
		||||
        trackController.presenter.trackingSearch(query, service)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onSearchResults(results: List<TrackSearch>) {
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,144 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.manga.track
 | 
			
		||||
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import androidx.core.net.toUri
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.databinding.TrackControllerBinding
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.MangaController
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
 | 
			
		||||
import eu.kanade.tachiyomi.widget.sheet.BaseBottomSheetDialog
 | 
			
		||||
 | 
			
		||||
class TrackSheet(
 | 
			
		||||
    val controller: MangaController,
 | 
			
		||||
    val manga: Manga
 | 
			
		||||
) : BaseBottomSheetDialog(controller.activity!!),
 | 
			
		||||
    TrackAdapter.OnClickListener,
 | 
			
		||||
    SetTrackStatusDialog.Listener,
 | 
			
		||||
    SetTrackChaptersDialog.Listener,
 | 
			
		||||
    SetTrackScoreDialog.Listener,
 | 
			
		||||
    SetTrackReadingDatesDialog.Listener {
 | 
			
		||||
 | 
			
		||||
    private lateinit var binding: TrackControllerBinding
 | 
			
		||||
 | 
			
		||||
    private lateinit var sheetBehavior: BottomSheetBehavior<*>
 | 
			
		||||
 | 
			
		||||
    private lateinit var adapter: TrackAdapter
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
 | 
			
		||||
        binding = TrackControllerBinding.inflate(layoutInflater)
 | 
			
		||||
        setContentView(binding.root)
 | 
			
		||||
 | 
			
		||||
        adapter = TrackAdapter(this)
 | 
			
		||||
        binding.trackRecycler.layoutManager = LinearLayoutManager(context)
 | 
			
		||||
        binding.trackRecycler.adapter = adapter
 | 
			
		||||
 | 
			
		||||
        sheetBehavior = BottomSheetBehavior.from(binding.root.parent as ViewGroup)
 | 
			
		||||
 | 
			
		||||
        adapter.items = controller.presenter.trackList
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onStart() {
 | 
			
		||||
        super.onStart()
 | 
			
		||||
        sheetBehavior.skipCollapsed = true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun show() {
 | 
			
		||||
        super.show()
 | 
			
		||||
        controller.presenter.trackingRefresh()
 | 
			
		||||
        sheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onNextTrackers(trackers: List<TrackItem>) {
 | 
			
		||||
        if (this::adapter.isInitialized) {
 | 
			
		||||
            adapter.items = trackers
 | 
			
		||||
            adapter.notifyDataSetChanged()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onLogoClick(position: Int) {
 | 
			
		||||
        val track = adapter.getItem(position)?.track ?: return
 | 
			
		||||
 | 
			
		||||
        if (track.tracking_url.isNotBlank()) {
 | 
			
		||||
            controller.activity?.startActivity(Intent(Intent.ACTION_VIEW, track.tracking_url.toUri()))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onSetClick(position: Int) {
 | 
			
		||||
        val item = adapter.getItem(position) ?: return
 | 
			
		||||
        TrackSearchDialog(controller, item.service).showDialog(controller.router, TAG_SEARCH_CONTROLLER)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onTitleLongClick(position: Int) {
 | 
			
		||||
        adapter.getItem(position)?.track?.title?.let {
 | 
			
		||||
            controller.activity?.copyToClipboard(it, it)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onStatusClick(position: Int) {
 | 
			
		||||
        val item = adapter.getItem(position) ?: return
 | 
			
		||||
        if (item.track == null) return
 | 
			
		||||
 | 
			
		||||
        SetTrackStatusDialog(controller, this, item).showDialog(controller.router)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onChaptersClick(position: Int) {
 | 
			
		||||
        val item = adapter.getItem(position) ?: return
 | 
			
		||||
        if (item.track == null) return
 | 
			
		||||
 | 
			
		||||
        SetTrackChaptersDialog(controller, this, item).showDialog(controller.router)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onScoreClick(position: Int) {
 | 
			
		||||
        val item = adapter.getItem(position) ?: return
 | 
			
		||||
        if (item.track == null) return
 | 
			
		||||
 | 
			
		||||
        SetTrackScoreDialog(controller, this, item).showDialog(controller.router)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onStartDateClick(position: Int) {
 | 
			
		||||
        val item = adapter.getItem(position) ?: return
 | 
			
		||||
        if (item.track == null) return
 | 
			
		||||
 | 
			
		||||
        SetTrackReadingDatesDialog(controller, this, SetTrackReadingDatesDialog.ReadingDate.Start, item).showDialog(controller.router)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onFinishDateClick(position: Int) {
 | 
			
		||||
        val item = adapter.getItem(position) ?: return
 | 
			
		||||
        if (item.track == null) return
 | 
			
		||||
 | 
			
		||||
        SetTrackReadingDatesDialog(controller, this, SetTrackReadingDatesDialog.ReadingDate.Finish, item).showDialog(controller.router)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun setStatus(item: TrackItem, selection: Int) {
 | 
			
		||||
        controller.presenter.setTrackerStatus(item, selection)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun setChaptersRead(item: TrackItem, chaptersRead: Int) {
 | 
			
		||||
        controller.presenter.setTrackerLastChapterRead(item, chaptersRead)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun setScore(item: TrackItem, score: Int) {
 | 
			
		||||
        controller.presenter.setTrackerScore(item, score)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun setReadingDate(item: TrackItem, type: SetTrackReadingDatesDialog.ReadingDate, date: Long) {
 | 
			
		||||
        when (type) {
 | 
			
		||||
            SetTrackReadingDatesDialog.ReadingDate.Start -> controller.presenter.setTrackerStartDate(item, date)
 | 
			
		||||
            SetTrackReadingDatesDialog.ReadingDate.Finish -> controller.presenter.setTrackerFinishDate(item, date)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getSearchDialog(): TrackSearchDialog? {
 | 
			
		||||
        return controller.router.getControllerWithTag(TAG_SEARCH_CONTROLLER) as? TrackSearchDialog
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private companion object {
 | 
			
		||||
        const val TAG_SEARCH_CONTROLLER = "track_search_controller"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user