Minor refactoring/documentation of manga details controller

It aint much but its something
This commit is contained in:
Jay 2020-04-22 01:18:08 -04:00
parent efb28e21a7
commit aab4e7fe5a

View File

@ -77,7 +77,6 @@ import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import eu.kanade.tachiyomi.ui.source.SourceController
import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
import eu.kanade.tachiyomi.ui.library.LibraryController
import eu.kanade.tachiyomi.ui.main.MainActivity
@ -90,6 +89,7 @@ import eu.kanade.tachiyomi.ui.manga.track.TrackingBottomSheet
import eu.kanade.tachiyomi.ui.migration.manga.design.PreMigrationController
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.ui.source.SourceController
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
import eu.kanade.tachiyomi.util.storage.getUriCompat
import eu.kanade.tachiyomi.util.system.ThemeUtil
@ -169,30 +169,16 @@ class MangaDetailsController : BaseController,
var refreshTracker: Int? = null
private var textAnim: ViewPropertyAnimator? = null
private var scrollAnim: ViewPropertyAnimator? = null
var isTablet = false
var chapterPopupMenu: Pair<Int, PopupMenu>? = null
// Tablet Layout
var isTablet = false
var tabletRecycler: RecyclerView? = null
/**
* Adapter containing a list of chapters.
*/
private var tabletAdapter: MangaDetailsAdapter? = null
/**
* Library search query.
*/
private var query = ""
/**
* Adapter containing a list of chapters.
*/
private var adapter: MangaDetailsAdapter? = null
/**
* Action mode for selections.
*/
private var actionMode: ActionMode? = null
// Hold a reference to the current animator, so that it can be canceled mid-way.
@ -201,10 +187,6 @@ class MangaDetailsController : BaseController,
var showScroll = false
var headerHeight = 0
init {
setHasOptionsMenu(true)
}
override fun getTitle(): String? {
return if (toolbarIsColored && !isTablet) manga?.title else null
}
@ -213,12 +195,33 @@ class MangaDetailsController : BaseController,
return inflater.inflate(R.layout.manga_details_controller, container, false)
}
//region UI Methods
override fun onViewCreated(view: View) {
super.onViewCreated(view)
coverColor = null
// Init RecyclerView and adapter
adapter = MangaDetailsAdapter(this, view.context)
presenter.onCreate()
setTabletMode(view)
setRecycler(view)
setPaletteColor()
setFastScroller()
swipe_refresh.isRefreshing = presenter.isLoading
if (manga?.initialized != true)
swipe_refresh.post { swipe_refresh.isRefreshing = true }
swipe_refresh.setOnRefreshListener { presenter.refreshAll() }
}
override fun onDestroyView(view: View) {
snack?.dismiss()
presenter.onDestroy()
adapter = null
trackingBottomSheet = null
super.onDestroyView(view)
}
/** Check if device is tablet, and create a second recycler to hold the details header if so */
private fun setTabletMode(view: View) {
isTablet = isTabletSize()
if (isTablet) {
tabletRecycler = RecyclerView(view.context)
@ -240,6 +243,11 @@ class MangaDetailsController : BaseController,
width = 1.dpToPx
}
}
}
/** Set adapter, insets, and scroll listener for recycler view */
private fun setRecycler(view: View) {
adapter = MangaDetailsAdapter(this, view.context)
recycler.adapter = adapter
adapter?.isSwipeEnabled = true
@ -273,8 +281,6 @@ class MangaDetailsController : BaseController,
v.updatePaddingRelative(bottom = insets.systemWindowInsetBottom)
}
presenter.onCreate()
fast_scroller.translationX = if (showScroll || isTablet) 0f else 25f.dpToPx
recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
@ -349,8 +355,10 @@ class MangaDetailsController : BaseController,
}
}
})
setPaletteColor()
}
private fun setFastScroller() {
fast_scroller.translationX = if (showScroll || isTablet) 0f else 25f.dpToPx
fast_scroller.setupWithRecyclerView(recycler, { position ->
val letter = adapter?.getSectionText(position)
when {
@ -382,14 +390,9 @@ class MangaDetailsController : BaseController,
colorToolbar(itemPosition > 0, false)
}
}
swipe_refresh.isRefreshing = presenter.isLoading
if (manga?.initialized != true)
swipe_refresh.post { swipe_refresh.isRefreshing = true }
swipe_refresh.setOnRefreshListener { presenter.refreshAll() }
}
/** Set the toolbar to fully transparent or colored and translucent */
fun colorToolbar(isColor: Boolean, animate: Boolean = true) {
if (isColor == toolbarIsColored) return
toolbarIsColored = isColor
@ -428,6 +431,7 @@ class MangaDetailsController : BaseController,
}
}
/** Get the color of the manga cover based on the current theme */
fun setPaletteColor() {
val view = view ?: return
GlideApp.with(view.context).load(manga)
@ -466,31 +470,49 @@ class MangaDetailsController : BaseController,
})
}
override fun onActivityResumed(activity: Activity) {
super.onActivityResumed(activity)
presenter.isLockedFromSearch = SecureActivityDelegate.shouldBeLocked()
presenter.headerItem.isLocked = presenter.isLockedFromSearch
presenter.fetchChapters(refreshTracker == null)
if (refreshTracker != null) {
trackingBottomSheet?.refreshItem(refreshTracker ?: 0)
presenter.refreshTrackers()
refreshTracker = null
}
val isCurrentController = router?.backstack?.lastOrNull()?.controller() ==
this
if (isCurrentController) {
setStatusBarAndToolbar()
/** Set toolbar theme for themes that are inverted (ie. light blue theme) */
private fun setActionBar(forThis: Boolean) {
val currentNightMode =
activity!!.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
// if the theme is using inverted toolbar color
if (currentNightMode == Configuration.UI_MODE_NIGHT_NO && ThemeUtil.isBlueTheme(
presenter.preferences.theme()
)
) {
if (forThis) (activity as MainActivity).appbar.context.setTheme(
R.style.ThemeOverlay_AppCompat_DayNight_ActionBar
)
else (activity as MainActivity).appbar.context.setTheme(
R.style.Theme_ActionBar_Dark_DayNight
)
val iconPrimary = view?.context?.getResourceColor(
if (forThis) android.R.attr.textColorPrimary
else R.attr.actionBarTintColor
) ?: Color.BLACK
(activity as MainActivity).toolbar.setTitleTextColor(iconPrimary)
(activity as MainActivity).drawerArrow?.color = iconPrimary
(activity as MainActivity).toolbar.overflowIcon?.setTint(iconPrimary)
if (forThis) activity!!.main_content.systemUiVisibility =
activity!!.main_content.systemUiVisibility.or(
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
)
else activity!!.main_content.systemUiVisibility =
activity!!.main_content.systemUiVisibility.rem(
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
)
}
}
fun showError(message: String) {
swipe_refresh?.isRefreshing = presenter.isLoading
view?.snack(message)
}
fun updateChapterDownload(download: Download) {
getHolder(download.chapter)?.notifyStatus(download.status, presenter.isLockedFromSearch,
download.progress)
private fun setStatusBarAndToolbar() {
activity?.window?.statusBarColor = if (toolbarIsColored) {
val translucentColor = ColorUtils.setAlphaComponent(coverColor ?: Color.TRANSPARENT, 175)
(activity as MainActivity).toolbar.setBackgroundColor(translucentColor)
translucentColor
} else Color.TRANSPARENT
(activity as MainActivity).appbar.setBackgroundColor(Color.TRANSPARENT)
(activity as MainActivity).toolbar.setBackgroundColor(activity?.window?.statusBarColor
?: Color.TRANSPARENT)
}
private fun isTabletSize(): Boolean {
@ -511,15 +533,26 @@ class MangaDetailsController : BaseController,
activity.windowManager?.defaultDisplay?.getMetrics(displayMetrics)
return displayMetrics.heightPixels.pxToDp >= 720
}
//endregion
private fun getHolder(chapter: Chapter): ChapterHolder? {
return recycler?.findViewHolderForItemId(chapter.id!!) as? ChapterHolder
//region Lifecycle methods
override fun onActivityResumed(activity: Activity) {
super.onActivityResumed(activity)
presenter.isLockedFromSearch = SecureActivityDelegate.shouldBeLocked()
presenter.headerItem.isLocked = presenter.isLockedFromSearch
presenter.fetchChapters(refreshTracker == null)
if (refreshTracker != null) {
trackingBottomSheet?.refreshItem(refreshTracker ?: 0)
presenter.refreshTrackers()
refreshTracker = null
}
val isCurrentController = router?.backstack?.lastOrNull()?.controller() ==
this
if (isCurrentController) {
setStatusBarAndToolbar()
}
}
private fun getHeader(): MangaHeaderHolder? {
return if (isTablet) tabletRecycler?.findViewHolderForAdapterPosition(0) as? MangaHeaderHolder
else recycler.findViewHolderForAdapterPosition(0) as? MangaHeaderHolder
}
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
super.onChangeStarted(handler, type)
@ -546,43 +579,39 @@ class MangaDetailsController : BaseController,
}
}
private fun setActionBar(forThis: Boolean) {
val currentNightMode =
activity!!.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
// if the theme is using inverted toolbar color
if (currentNightMode == Configuration.UI_MODE_NIGHT_NO && ThemeUtil.isBlueTheme(
presenter.preferences.theme()
)
) {
if (forThis)
(activity as MainActivity).appbar.context.setTheme(R.style
.ThemeOverlay_AppCompat_DayNight_ActionBar)
else
(activity as MainActivity).appbar.context.setTheme(R.style
.Theme_ActionBar_Dark_DayNight)
val iconPrimary = view?.context?.getResourceColor(
if (forThis) android.R.attr.textColorPrimary
else R.attr.actionBarTintColor
) ?: Color.BLACK
(activity as MainActivity).toolbar.setTitleTextColor(iconPrimary)
(activity as MainActivity).drawerArrow?.color = iconPrimary
(activity as MainActivity).toolbar.overflowIcon?.setTint(iconPrimary)
if (forThis) activity!!.main_content.systemUiVisibility =
activity!!.main_content.systemUiVisibility.or(
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
)
else activity!!.main_content.systemUiVisibility =
activity!!.main_content.systemUiVisibility.rem(
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
)
override fun handleBack(): Boolean {
if (manga_cover_full?.visibility == View.VISIBLE) {
manga_cover_full?.performClick()
return true
}
return super.handleBack()
}
//endregion
fun showError(message: String) {
swipe_refresh?.isRefreshing = presenter.isLoading
view?.snack(message)
}
fun setRefresh(enabled: Boolean) {
swipe_refresh.isRefreshing = enabled
}
//region Recycler methods
fun updateChapterDownload(download: Download) {
getHolder(download.chapter)?.notifyStatus(download.status, presenter.isLockedFromSearch,
download.progress)
}
private fun getHolder(chapter: Chapter): ChapterHolder? {
return recycler?.findViewHolderForItemId(chapter.id!!) as? ChapterHolder
}
private fun getHeader(): MangaHeaderHolder? {
return if (isTablet) tabletRecycler?.findViewHolderForAdapterPosition(0) as? MangaHeaderHolder
else recycler.findViewHolderForAdapterPosition(0) as? MangaHeaderHolder
}
fun updateHeader() {
swipe_refresh?.isRefreshing = presenter.isLoading
adapter?.setChapters(presenter.chapters)
@ -601,6 +630,18 @@ class MangaDetailsController : BaseController,
activity?.invalidateOptionsMenu()
}
private fun addMangaHeader() {
if (tabletAdapter?.scrollableHeaders?.isEmpty() == true) {
tabletAdapter?.removeAllScrollableHeaders()
tabletAdapter?.addScrollableHeader(presenter.headerItem)
adapter?.removeAllScrollableHeaders()
adapter?.addScrollableHeader(presenter.tabletChapterHeaderItem!!)
} else if (!isTablet && adapter?.scrollableHeaders?.isEmpty() == true) {
adapter?.removeAllScrollableHeaders()
adapter?.addScrollableHeader(presenter.headerItem)
}
}
fun refreshAdapter() = adapter?.notifyDataSetChanged()
override fun onItemClick(view: View?, position: Int): Boolean {
@ -659,6 +700,18 @@ class MangaDetailsController : BaseController,
popup.show()
}
override fun onActionStateChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
swipe_refresh.isEnabled = actionState != ItemTouchHelper.ACTION_STATE_SWIPE
}
override fun onItemMove(fromPosition: Int, toPosition: Int) {
}
override fun shouldMoveItem(fromPosition: Int, toPosition: Int): Boolean {
return true
}
//endregion
fun dismissPopup(position: Int) {
if (chapterPopupMenu != null && chapterPopupMenu?.first == position) {
chapterPopupMenu?.second?.dismiss()
@ -739,14 +792,7 @@ class MangaDetailsController : BaseController,
startActivity(intent)
}
override fun onDestroyView(view: View) {
snack?.dismiss()
presenter.onDestroy()
adapter = null
trackingBottomSheet = null
super.onDestroyView(view)
}
//region action bar menu methods
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.manga_details, menu)
val editItem = menu.findItem(R.id.action_edit)
@ -847,10 +893,8 @@ class MangaDetailsController : BaseController,
}
return true
}
//endregion
/**
* Called to run Intent with [Intent.ACTION_SEND], which show share dialog.
*/
override fun prepareToShareManga() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && coverDrawable != null)
GlideApp.with(activity!!).asBitmap().load(presenter.manga).into(object :
@ -867,9 +911,6 @@ class MangaDetailsController : BaseController,
else shareManga()
}
/**
* Called to run Intent with [Intent.ACTION_SEND], which show share dialog.
*/
fun shareManga(cover: File? = null) {
val context = view?.context ?: return
@ -947,6 +988,18 @@ class MangaDetailsController : BaseController,
}
}
private fun isLocked(): Boolean {
if (presenter.isLockedFromSearch) {
SecureActivityDelegate.promptLockIfNeeded(activity)
return true
}
return false
}
//region Interface methods
override fun coverColor(): Int? = coverColor
override fun topCoverHeight(): Int = headerHeight
override fun startDownloadNow(position: Int) {
val chapter = (adapter?.getItem(position) as? ChapterItem) ?: return
presenter.startDownloadingNow(chapter)
@ -979,9 +1032,6 @@ class MangaDetailsController : BaseController,
onItemClick(null, position)
}
override fun coverColor(): Int? = coverColor
override fun topCoverHeight(): Int = headerHeight
override fun readNextChapter() {
if (activity is SearchActivity && presenter.isLockedFromSearch) {
SecureActivityDelegate.promptLockIfNeeded(activity)
@ -1032,14 +1082,6 @@ class MangaDetailsController : BaseController,
ChaptersSortBottomSheet(this).show()
}
private fun isLocked(): Boolean {
if (presenter.isLockedFromSearch) {
SecureActivityDelegate.promptLockIfNeeded(activity)
return true
}
return false
}
override fun favoriteManga(longPress: Boolean) {
if (isLocked()) return
val manga = presenter.manga
@ -1158,21 +1200,15 @@ class MangaDetailsController : BaseController,
snack = view.snack(view.context.getString(R.string._copied_to_clipboard, contentType))
}
override fun handleBack(): Boolean {
if (manga_cover_full?.visibility == View.VISIBLE) {
manga_cover_full?.performClick()
return true
}
return super.handleBack()
}
override fun showTrackingSheet() {
if (isLocked()) return
trackingBottomSheet =
TrackingBottomSheet(this)
trackingBottomSheet?.show()
}
//endregion
//region Tracking methods
fun refreshTracking(trackings: List<TrackItem>) {
trackingBottomSheet?.onNextTrackings(trackings)
}
@ -1198,10 +1234,9 @@ class MangaDetailsController : BaseController,
Timber.e(error)
trackingBottomSheet?.onSearchResultsError(error)
}
//endregion
/**
* Creates the action mode if it's not created already.
*/
//region Action mode methods
private fun createActionModeIfNeeded() {
if (actionMode == null) {
actionMode = (activity as AppCompatActivity).startSupportActionMode(this)
@ -1231,6 +1266,12 @@ class MangaDetailsController : BaseController,
return true
}
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
mode?.title = view?.context?.getString(if (startingDLChapterPos == null)
R.string.select_starting_chapter else R.string.select_ending_chapter)
return false
}
override fun onDestroyActionMode(mode: ActionMode?) {
actionMode = null
setStatusBarAndToolbar()
@ -1245,38 +1286,7 @@ class MangaDetailsController : BaseController,
adapter?.clearSelection()
return
}
/**
* Called to set the last used catalogue at the top of the view.
*/
private fun addMangaHeader() {
if (tabletAdapter?.scrollableHeaders?.isEmpty() == true) {
tabletAdapter?.removeAllScrollableHeaders()
tabletAdapter?.addScrollableHeader(presenter.headerItem)
adapter?.removeAllScrollableHeaders()
adapter?.addScrollableHeader(presenter.tabletChapterHeaderItem!!)
} else if (!isTablet && adapter?.scrollableHeaders?.isEmpty() == true) {
adapter?.removeAllScrollableHeaders()
adapter?.addScrollableHeader(presenter.headerItem)
}
}
private fun setStatusBarAndToolbar() {
activity?.window?.statusBarColor = if (toolbarIsColored) {
val translucentColor = ColorUtils.setAlphaComponent(coverColor ?: Color.TRANSPARENT, 175)
(activity as MainActivity).toolbar.setBackgroundColor(translucentColor)
translucentColor
} else Color.TRANSPARENT
(activity as MainActivity).appbar.setBackgroundColor(Color.TRANSPARENT)
(activity as MainActivity).toolbar.setBackgroundColor(activity?.window?.statusBarColor
?: Color.TRANSPARENT)
}
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
mode?.title = view?.context?.getString(if (startingDLChapterPos == null)
R.string.select_starting_chapter else R.string.select_ending_chapter)
return false
}
//endregion
fun changeCover() {
if (manga?.favorite == true) {
@ -1310,17 +1320,6 @@ class MangaDetailsController : BaseController,
}
}
override fun onActionStateChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
swipe_refresh.isEnabled = actionState != ItemTouchHelper.ACTION_STATE_SWIPE
}
override fun onItemMove(fromPosition: Int, toPosition: Int) {
}
override fun shouldMoveItem(fromPosition: Int, toPosition: Int): Boolean {
return true
}
override fun zoomImageFromThumb(thumbView: View) {
// If there's an animation in progress, cancel it immediately and proceed with this one.
currentAnimator?.cancel()