mirror of
https://github.com/mihonapp/mihon.git
synced 2025-06-30 21:17:50 +02:00
Replace MotionLayout with full screen dialog (#5806)
* Remove MotionLayout and add full screen dialog for enlarged cover * Address some of the review comments
This commit is contained in:
@ -30,6 +30,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import coil.imageLoader
|
||||
import coil.request.ImageRequest
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
@ -73,6 +74,7 @@ import eu.kanade.tachiyomi.ui.manga.chapter.DeleteChaptersDialog
|
||||
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.MangaFullCoverDialog
|
||||
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoHeaderAdapter
|
||||
import eu.kanade.tachiyomi.ui.manga.track.TrackItem
|
||||
import eu.kanade.tachiyomi.ui.manga.track.TrackSearchDialog
|
||||
@ -179,6 +181,8 @@ class MangaController :
|
||||
|
||||
private var trackSheet: TrackSheet? = null
|
||||
|
||||
private var dialog: MangaFullCoverDialog? = null
|
||||
|
||||
init {
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
@ -435,7 +439,6 @@ class MangaController :
|
||||
|
||||
// Hide options for non-library manga
|
||||
menu.findItem(R.id.action_edit_categories).isVisible = presenter.manga.favorite && presenter.getCategories().isNotEmpty()
|
||||
menu.findItem(R.id.action_edit_cover).isVisible = presenter.manga.favorite
|
||||
menu.findItem(R.id.action_migrate).isVisible = presenter.manga.favorite
|
||||
}
|
||||
|
||||
@ -446,10 +449,6 @@ class MangaController :
|
||||
R.id.download_custom, R.id.download_unread, R.id.download_all
|
||||
-> downloadChapters(item.itemId)
|
||||
|
||||
R.id.action_share_cover -> shareCover()
|
||||
R.id.action_save_cover -> saveCover()
|
||||
R.id.action_edit_cover -> changeCover()
|
||||
|
||||
R.id.action_edit_categories -> onCategoriesClick()
|
||||
R.id.action_migrate -> migrateManga()
|
||||
}
|
||||
@ -728,6 +727,21 @@ class MangaController :
|
||||
context.imageLoader.enqueue(req)
|
||||
}
|
||||
|
||||
fun showFullCoverDialog() {
|
||||
if (dialog != null) return
|
||||
val manga = manga ?: return
|
||||
dialog = MangaFullCoverDialog(this, manga)
|
||||
dialog?.addLifecycleListener(
|
||||
object : LifecycleListener() {
|
||||
override fun postDestroy(controller: Controller) {
|
||||
super.postDestroy(controller)
|
||||
dialog = null
|
||||
}
|
||||
}
|
||||
)
|
||||
dialog?.showDialog(router)
|
||||
}
|
||||
|
||||
fun shareCover() {
|
||||
try {
|
||||
val activity = activity!!
|
||||
@ -800,6 +814,7 @@ class MangaController :
|
||||
|
||||
fun onSetCoverSuccess() {
|
||||
mangaInfoAdapter?.notifyDataSetChanged()
|
||||
dialog?.setImage(manga)
|
||||
activity?.toast(R.string.cover_updated)
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,119 @@
|
||||
package eu.kanade.tachiyomi.ui.manga.info
|
||||
|
||||
import android.app.Dialog
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Bundle
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.WindowCompat
|
||||
import coil.imageLoader
|
||||
import coil.request.Disposable
|
||||
import coil.request.ImageRequest
|
||||
import com.davemorrissey.labs.subscaleview.ImageSource
|
||||
import dev.chrisbanes.insetter.applyInsetter
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.databinding.MangaFullCoverDialogBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.util.view.setNavigationBarTransparentCompat
|
||||
import eu.kanade.tachiyomi.widget.TachiyomiFullscreenDialog
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class MangaFullCoverDialog : DialogController {
|
||||
|
||||
private var manga: Manga? = null
|
||||
|
||||
private var binding: MangaFullCoverDialogBinding? = null
|
||||
|
||||
private var disposable: Disposable? = null
|
||||
|
||||
private val mangaController
|
||||
get() = targetController as MangaController
|
||||
|
||||
constructor(targetController: MangaController, manga: Manga) : super(bundleOf("mangaId" to manga.id)) {
|
||||
this.targetController = targetController
|
||||
this.manga = manga
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
constructor(bundle: Bundle) : super(bundle) {
|
||||
val db = Injekt.get<DatabaseHelper>()
|
||||
manga = db.getManga(bundle.getLong("mangaId")).executeAsBlocking()
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
binding = MangaFullCoverDialogBinding.inflate(activity!!.layoutInflater)
|
||||
|
||||
binding?.toolbar?.apply {
|
||||
setNavigationOnClickListener { dialog?.dismiss() }
|
||||
setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.action_share_cover -> mangaController.shareCover()
|
||||
R.id.action_save_cover -> mangaController.saveCover()
|
||||
R.id.action_edit_cover -> mangaController.changeCover()
|
||||
}
|
||||
true
|
||||
}
|
||||
menu?.findItem(R.id.action_edit_cover)?.isVisible = manga?.favorite ?: false
|
||||
}
|
||||
|
||||
binding?.fullCover?.setOnClickListener {
|
||||
dialog?.dismiss()
|
||||
}
|
||||
setImage(manga)
|
||||
|
||||
binding?.appbar?.applyInsetter {
|
||||
type(navigationBars = true, statusBars = true) {
|
||||
padding(left = true, top = true, right = true)
|
||||
}
|
||||
}
|
||||
|
||||
binding?.fullCover?.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
// Padding will make to image top align
|
||||
// This is likely an issue with SubsamplingScaleImageView
|
||||
margin(bottom = true)
|
||||
}
|
||||
}
|
||||
|
||||
return TachiyomiFullscreenDialog(activity!!, binding!!.root).apply {
|
||||
val typedValue = TypedValue()
|
||||
val theme = context.theme
|
||||
theme.resolveAttribute(android.R.attr.colorBackground, typedValue, true)
|
||||
window?.setBackgroundDrawable(ColorDrawable(ColorUtils.setAlphaComponent(typedValue.data, 230)))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttach(view: View) {
|
||||
super.onAttach(view)
|
||||
dialog?.window?.let { window ->
|
||||
window.setNavigationBarTransparentCompat(window.context)
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDetach(view: View) {
|
||||
super.onDetach(view)
|
||||
disposable?.dispose()
|
||||
disposable = null
|
||||
}
|
||||
|
||||
fun setImage(manga: Manga?) {
|
||||
val manga = manga ?: return
|
||||
val request = ImageRequest.Builder(applicationContext!!)
|
||||
.data(manga)
|
||||
.target {
|
||||
val bitmap = (it as BitmapDrawable).bitmap
|
||||
binding?.fullCover?.setImage(ImageSource.cachedBitmap(bitmap))
|
||||
}
|
||||
.build()
|
||||
|
||||
disposable = applicationContext?.imageLoader?.enqueue(request)
|
||||
}
|
||||
}
|
@ -3,11 +3,9 @@ package eu.kanade.tachiyomi.ui.manga.info
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.target.ImageViewTarget
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
@ -87,15 +85,10 @@ class MangaInfoHeaderAdapter(
|
||||
binding.mangaCover.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
topMargin += appBarHeight
|
||||
}
|
||||
binding.root.getConstraintSet(R.id.end)
|
||||
?.setMargin(R.id.manga_cover, ConstraintLayout.LayoutParams.TOP, appBarHeight)
|
||||
}
|
||||
|
||||
inner class HeaderViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
|
||||
fun bind() {
|
||||
val headerTransition = binding.root.getTransition(R.id.manga_info_header_transition)
|
||||
headerTransition.applySystemAnimatorScale(view.context)
|
||||
|
||||
val summaryTransition = binding.mangaSummarySection.getTransition(R.id.manga_summary_section_transition)
|
||||
summaryTransition.applySystemAnimatorScale(view.context)
|
||||
|
||||
@ -199,6 +192,12 @@ class MangaInfoHeaderAdapter(
|
||||
}
|
||||
.launchIn(controller.viewScope)
|
||||
|
||||
binding.mangaCover.clicks()
|
||||
.onEach {
|
||||
controller.showFullCoverDialog()
|
||||
}
|
||||
.launchIn(controller.viewScope)
|
||||
|
||||
binding.mangaCover.longClicks()
|
||||
.onEach {
|
||||
showCoverOptionsDialog()
|
||||
@ -286,17 +285,7 @@ class MangaInfoHeaderAdapter(
|
||||
|
||||
// Set cover if changed.
|
||||
binding.backdrop.loadAnyAutoPause(manga)
|
||||
binding.mangaCover.loadAnyAutoPause(manga) {
|
||||
listener(
|
||||
onSuccess = { request, _ ->
|
||||
(request.target as? ImageViewTarget)?.drawable?.let { drawable ->
|
||||
val ratio = drawable.minimumWidth / drawable.minimumHeight.toFloat()
|
||||
binding.root.getConstraintSet(R.id.end)
|
||||
?.setDimensionRatio(R.id.manga_cover, ratio.toString())
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
binding.mangaCover.loadAnyAutoPause(manga)
|
||||
|
||||
// Manga info section
|
||||
val hasInfoContent = !manga.description.isNullOrBlank() || !manga.genre.isNullOrBlank()
|
||||
|
@ -7,7 +7,6 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.appcompat.app.AppCompatDialog
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.WindowCompat
|
||||
@ -21,6 +20,7 @@ import eu.kanade.tachiyomi.databinding.TrackSearchDialogBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.util.view.setNavigationBarTransparentCompat
|
||||
import eu.kanade.tachiyomi.widget.TachiyomiFullscreenDialog
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -142,9 +142,7 @@ class TrackSearchDialog : DialogController {
|
||||
}
|
||||
}
|
||||
|
||||
return AppCompatDialog(activity!!, R.style.ThemeOverlay_Tachiyomi_Dialog_Fullscreen).apply {
|
||||
setContentView(binding!!.root)
|
||||
}
|
||||
return TachiyomiFullscreenDialog(activity!!, binding!!.root)
|
||||
}
|
||||
|
||||
override fun onAttach(view: View) {
|
||||
|
@ -0,0 +1,13 @@
|
||||
package eu.kanade.tachiyomi.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatDialog
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
||||
class TachiyomiFullscreenDialog(context: Context, view: View) : AppCompatDialog(context, R.style.ThemeOverlay_Tachiyomi_Dialog_Fullscreen) {
|
||||
|
||||
init {
|
||||
setContentView(view)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user