增加一些蜜汁小动画

This commit is contained in:
HapeLee
2025-08-30 01:36:09 +08:00
parent 7d76cf3b12
commit 7e26a158e7
20 changed files with 186 additions and 67 deletions
@@ -2,6 +2,7 @@ package io.legato.kazusa.ui.book.info
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Color
import android.graphics.RenderEffect
import android.graphics.Shader
import android.net.Uri
@@ -15,6 +16,7 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import com.google.android.material.transition.platform.MaterialContainerTransform
import io.legato.kazusa.R
import io.legato.kazusa.base.VMBaseActivity
import io.legato.kazusa.constant.BookType
@@ -151,14 +153,23 @@ class BookInfoActivity :
@SuppressLint("PrivateResource")
override fun onCreate(savedInstanceState: Bundle?) {
window.sharedElementEnterTransition = MaterialContainerTransform().apply {
addTarget(binding.ivCover)
duration = 500
scrimColor = Color.TRANSPARENT
fadeMode = MaterialContainerTransform.FADE_MODE_THROUGH
}
window.sharedElementReturnTransition = MaterialContainerTransform().apply {
addTarget(binding.ivCover)
duration = 500
scrimColor = Color.TRANSPARENT
fadeMode = MaterialContainerTransform.FADE_MODE_THROUGH
}
window.sharedElementsUseOverlay = false
super.onCreate(savedInstanceState)
binding.ivCover.transitionName = intent.getStringExtra("transitionName")
setSupportActionBar(binding.topBar)
binding.llRead?.applyNavigationBarMargin()
// binding.refreshLayout?.setColorSchemeColors(accentColor)
// binding.llInfo.setBackgroundColor(backgroundColor)
// binding.flAction.setBackgroundColor(bottomBackground)
//binding.flAction.applyNavigationBarPadding()
binding.btnShelf.text = getString(R.string.remove_from_bookshelf)
binding.tvToc.text = getString(R.string.toc_s, getString(R.string.loading))
@@ -2,6 +2,7 @@ package io.legato.kazusa.ui.book.manga
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.view.KeyEvent
@@ -21,6 +22,7 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.integration.recyclerview.RecyclerViewPreloader
import com.bumptech.glide.request.target.Target.SIZE_ORIGINAL
import com.bumptech.glide.util.FixedPreloadSizeProvider
import com.google.android.material.transition.platform.MaterialContainerTransform
import io.legato.kazusa.BuildConfig
import io.legato.kazusa.R
import io.legato.kazusa.base.VMBaseActivity
@@ -158,9 +160,21 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
}
override fun onCreate(savedInstanceState: Bundle?) {
window.sharedElementEnterTransition = MaterialContainerTransform().apply {
addTarget(binding.root)
duration = 500
scrimColor = Color.TRANSPARENT
fadeMode = MaterialContainerTransform.FADE_MODE_THROUGH
}
window.sharedElementReturnTransition = MaterialContainerTransform().apply {
addTarget(binding.root)
duration = 500
scrimColor = Color.TRANSPARENT
fadeMode = MaterialContainerTransform.FADE_MODE_THROUGH
}
upLayoutInDisplayCutoutMode()
super.onCreate(savedInstanceState)
binding.root.transitionName = intent.getStringExtra("transitionName")
ReadManga.register(this)
upSystemUiVisibility(false)
initRecyclerView()
@@ -4,6 +4,7 @@ package io.legato.kazusa.ui.book.read
import android.annotation.SuppressLint
import android.content.Intent
import android.content.res.Configuration
import android.graphics.Color
import android.net.Uri
import android.os.Bundle
import android.os.Looper
@@ -22,6 +23,7 @@ import androidx.appcompat.widget.PopupMenu
import androidx.core.view.get
import androidx.core.view.size
import androidx.lifecycle.lifecycleScope
import com.google.android.material.transition.platform.MaterialContainerTransform
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
import io.legato.kazusa.BuildConfig
import io.legato.kazusa.R
@@ -259,7 +261,20 @@ class ReadBookActivity : BaseReadBookActivity(),
@SuppressLint("ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
window.sharedElementEnterTransition = MaterialContainerTransform().apply {
addTarget(binding.rootView)
duration = 500
scrimColor = Color.TRANSPARENT
fadeMode = MaterialContainerTransform.FADE_MODE_THROUGH
}
window.sharedElementReturnTransition = MaterialContainerTransform().apply {
addTarget(binding.rootView)
duration = 500
scrimColor = Color.TRANSPARENT
fadeMode = MaterialContainerTransform.FADE_MODE_THROUGH
}
super.onCreate(savedInstanceState)
binding.rootView.transitionName = intent.getStringExtra("transitionName")
//binding.cursorLeft.setColorFilter(accentColor)
//binding.cursorRight.setColorFilter(accentColor)
binding.cursorLeft.setOnTouchListener(this)
@@ -598,14 +598,18 @@ class ReadMenu @JvmOverloads constructor(
val result = mutableListOf<ToolButton>()
savedList.forEach { (id, enabled) ->
if (enabled) allButtons[id]?.let { result.add(it) }
}
getAllButtons().forEach { btn ->
if (savedList.none { it.first == btn.id }) {
result.add(btn)
if (savedList.isNotEmpty()) {
savedList.forEach { (id, enabled) ->
if (enabled) allButtons[id]?.let { result.add(it) }
}
getAllButtons().forEach { btn ->
if (savedList.none { it.first == btn.id }) {
result.add(btn)
}
}
} else {
result.addAll(getAllButtons().take(5))
}
@@ -56,7 +56,7 @@ class BookshelfConfigBottomSheet : BaseBottomSheetDialogFragment(R.layout.dialog
text = label
isCheckable = true
isClickable = true
id = View.generateViewId()
id = index
}
chipGroupSort.addView(chip)
if (index == AppConfig.bookshelfSort) {
@@ -113,8 +113,8 @@ class BookshelfConfigBottomSheet : BaseBottomSheetDialogFragment(R.layout.dialog
postEvent(EventBus.BOOKSHELF_REFRESH, "")
}
if (bookshelfSort != chipGroupSort.indexOfChild(chipGroupSort.findViewById(chipGroupSort.checkedChipId))) {
AppConfig.bookshelfSort = chipGroupSort.indexOfChild(chipGroupSort.findViewById(chipGroupSort.checkedChipId))
if (bookshelfSort != chipGroupSort.checkedChipId) {
AppConfig.bookshelfSort = chipGroupSort.checkedChipId
(requireParentFragment() as? BaseBookshelfFragment)?.upSort()
}
@@ -1,9 +1,13 @@
package io.legato.kazusa.ui.main.bookshelf.books
//import io.legado.app.lib.theme.accentColor
//import io.legado.app.lib.theme.primaryColor
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.ViewConfiguration
import androidx.core.app.ActivityOptionsCompat
import androidx.core.view.isGone
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
@@ -22,10 +26,13 @@ import io.legato.kazusa.data.appDb
import io.legato.kazusa.data.entities.Book
import io.legato.kazusa.data.entities.BookGroup
import io.legato.kazusa.databinding.FragmentBooksBinding
import io.legato.kazusa.help.book.isAudio
import io.legato.kazusa.help.book.isImage
import io.legato.kazusa.help.config.AppConfig
//import io.legado.app.lib.theme.accentColor
//import io.legado.app.lib.theme.primaryColor
import io.legato.kazusa.ui.book.audio.AudioPlayActivity
import io.legato.kazusa.ui.book.info.BookInfoActivity
import io.legato.kazusa.ui.book.manga.ReadMangaActivity
import io.legato.kazusa.ui.book.read.ReadBookActivity
import io.legato.kazusa.ui.main.MainViewModel
import io.legato.kazusa.ui.main.bookshelf.books.styleDefalut.BaseBooksAdapter
import io.legato.kazusa.ui.main.bookshelf.books.styleDefalut.BooksAdapterGrid
@@ -34,8 +41,6 @@ import io.legato.kazusa.utils.bookshelfLayout
import io.legato.kazusa.utils.cnCompare
import io.legato.kazusa.utils.flowWithLifecycleAndDatabaseChangeFirst
import io.legato.kazusa.utils.observeEvent
import io.legato.kazusa.utils.startActivity
import io.legato.kazusa.utils.startActivityForBook
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -150,11 +155,8 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
}
fun upBookSort() {
// binding.root.post {
// arguments?.putInt("bookSort", sort)
// bookSort = sort
upRecyclerData()
// }
bookSort = AppConfig.bookshelfSort
upRecyclerData()
}
fun setEnableRefresh(enable: Boolean) {
@@ -255,17 +257,49 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
binding.rvBookshelf.adapter = null
}
override fun open(book: Book) {
startActivityForBook(book)
override fun open(book: Book, sharedView: View) {
val transitionName = "book_${book.bookUrl}"
sharedView.transitionName = transitionName
val cls = when {
book.isAudio -> AudioPlayActivity::class.java
book.isImage && AppConfig.showMangaUi -> ReadMangaActivity::class.java
else -> ReadBookActivity::class.java
}
val intent = Intent(requireContext(), cls).apply {
putExtra("bookUrl", book.bookUrl)
putExtra("transitionName", transitionName)
}
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
requireActivity(),
sharedView,
transitionName
)
startActivity(intent, options.toBundle())
}
override fun openBookInfo(book: Book) {
startActivity<BookInfoActivity> {
override fun openBookInfo(book: Book, sharedView: View) {
val intent = Intent(requireContext(), BookInfoActivity::class.java).apply {
putExtra("name", book.name)
putExtra("author", book.author)
putExtra("transitionName", "book_${book.bookUrl}") // 给共享元素唯一标识
}
sharedView.transitionName = "book_${book.bookUrl}"
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
requireActivity(),
sharedView,
sharedView.transitionName
)
startActivity(intent, options.toBundle())
}
override fun isUpdate(bookUrl: String): Boolean {
return activityViewModel.isUpdate(bookUrl)
}
@@ -1,9 +1,11 @@
package io.legato.kazusa.ui.main.bookshelf.books
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.appcompat.widget.SearchView
import androidx.core.app.ActivityOptionsCompat
import androidx.core.view.isGone
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
@@ -19,9 +21,14 @@ import io.legato.kazusa.data.appDb
import io.legato.kazusa.data.entities.Book
import io.legato.kazusa.data.entities.BookGroup
import io.legato.kazusa.databinding.FragmentBookshelf2Binding
import io.legato.kazusa.help.book.isAudio
import io.legato.kazusa.help.book.isImage
import io.legato.kazusa.help.config.AppConfig
import io.legato.kazusa.ui.book.audio.AudioPlayActivity
import io.legato.kazusa.ui.book.group.GroupEditDialog
import io.legato.kazusa.ui.book.info.BookInfoActivity
import io.legato.kazusa.ui.book.manga.ReadMangaActivity
import io.legato.kazusa.ui.book.read.ReadBookActivity
import io.legato.kazusa.ui.book.search.SearchActivity
import io.legato.kazusa.ui.main.bookshelf.BaseBookshelfFragment
import io.legato.kazusa.ui.main.bookshelf.books.styleFold.BaseBooksAdapter
@@ -32,8 +39,6 @@ import io.legato.kazusa.utils.cnCompare
import io.legato.kazusa.utils.flowWithLifecycleAndDatabaseChangeFirst
import io.legato.kazusa.utils.observeEvent
import io.legato.kazusa.utils.showDialogFragment
import io.legato.kazusa.utils.startActivity
import io.legato.kazusa.utils.startActivityForBook
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -249,9 +254,31 @@ class BookshelfFragment2() : BaseBookshelfFragment(R.layout.fragment_bookshelf2)
}
}
override fun onItemClick(item: Any) {
override fun onItemClick(item: Any, sharedView: View) {
when (item) {
is Book -> startActivityForBook(item)
is Book -> {
val transitionName = "book_${item.bookUrl}"
sharedView.transitionName = transitionName
val cls = when {
item.isAudio -> AudioPlayActivity::class.java
item.isImage && AppConfig.showMangaUi -> ReadMangaActivity::class.java
else -> ReadBookActivity::class.java
}
val intent = Intent(requireContext(), cls).apply {
putExtra("bookUrl", item.bookUrl)
putExtra("transitionName", transitionName)
}
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
requireActivity(),
sharedView,
transitionName
)
startActivity(intent, options.toBundle())
}
is BookGroup -> {
groupId = item.groupId
@@ -260,11 +287,24 @@ class BookshelfFragment2() : BaseBookshelfFragment(R.layout.fragment_bookshelf2)
}
}
override fun onItemLongClick(item: Any) {
override fun onItemLongClick(item: Any, sharedView: View) {
when (item) {
is Book -> startActivity<BookInfoActivity> {
putExtra("name", item.name)
putExtra("author", item.author)
is Book -> {
val intent = Intent(requireContext(), BookInfoActivity::class.java).apply {
putExtra("name", item.name)
putExtra("author", item.author)
putExtra("transitionName", "book_${item.bookUrl}") // 给共享元素唯一标识
}
sharedView.transitionName = "book_${item.bookUrl}"
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
requireActivity(),
sharedView,
sharedView.transitionName
)
startActivity(intent, options.toBundle())
}
is BookGroup -> showDialogFragment(GroupEditDialog(item))
@@ -1,6 +1,7 @@
package io.legato.kazusa.ui.main.bookshelf.books.styleDefalut
import android.content.Context
import android.view.View
import androidx.core.os.bundleOf
import androidx.recyclerview.widget.DiffUtil
import androidx.viewbinding.ViewBinding
@@ -86,8 +87,8 @@ abstract class BaseBooksAdapter<VB : ViewBinding>(context: Context) :
}
interface CallBack {
fun open(book: Book)
fun openBookInfo(book: Book)
fun open(book: Book, sharedView: View)
fun openBookInfo(book: Book, sharedView: View)
fun isUpdate(bookUrl: String): Boolean
}
}
@@ -23,6 +23,7 @@ class BooksAdapterGrid(context: Context, private val callBack: CallBack) :
item: Book,
payloads: MutableList<Any>
) = binding.run {
binding.ivCover.transitionName = "book_${item.bookUrl}"
if (payloads.isEmpty()) {
tvName.text = item.name
ivCover.load(item.getDisplayCover(), item.name, item.author, false, item.origin)
@@ -62,15 +63,16 @@ class BooksAdapterGrid(context: Context, private val callBack: CallBack) :
}
override fun registerListener(holder: ItemViewHolder, binding: ItemBookshelfGridBinding) {
binding.cvContent.setOnClickListener {
getItem(holder.layoutPosition)?.let {
callBack.open(it)
callBack.open(it, binding.ivCover)
}
}
binding.cvContent.setOnLongClickListener {
getItem(holder.layoutPosition)?.let {
callBack.openBookInfo(it)
callBack.openBookInfo(it, binding.ivCover)
}
true
}
@@ -31,6 +31,7 @@ class BooksAdapterList(
item: Book,
payloads: MutableList<Any>
) = binding.run {
binding.ivCover.transitionName = "book_${item.bookUrl}"
if (payloads.isEmpty()) {
tvName.text = item.name
tvAuthor.text = item.author
@@ -97,13 +98,13 @@ class BooksAdapterList(
holder.itemView.apply {
binding.cvContent.setOnClickListener {
getItem(holder.layoutPosition)?.let {
callBack.open(it)
callBack.open(it, binding.ivCover)
}
}
binding.cvContent.onLongClick {
getItem(holder.layoutPosition)?.let {
callBack.openBookInfo(it)
callBack.openBookInfo(it, binding.ivCover)
}
}
}
@@ -2,6 +2,7 @@ package io.legato.kazusa.ui.main.bookshelf.books.styleFold
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import androidx.core.os.bundleOf
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil
@@ -138,8 +139,8 @@ abstract class BaseBooksAdapter<VH : RecyclerView.ViewHolder>(
interface CallBack {
fun onItemClick(item: Any)
fun onItemLongClick(item: Any)
fun onItemClick(item: Any, sharedView: View)
fun onItemLongClick(item: Any, sharedView: View)
fun isUpdate(bookUrl: String): Boolean
fun getItems(): List<Any>
}
@@ -92,10 +92,10 @@ class BooksAdapterGrid(context: Context, callBack: CallBack) :
fun registerListener(item: Any) {
binding.cvContent.setOnClickListener {
callBack.onItemClick(item)
callBack.onItemClick(item, binding.ivCover)
}
binding.cvContent.onLongClick {
callBack.onItemLongClick(item)
callBack.onItemLongClick(item, binding.ivCover)
}
}
@@ -149,10 +149,10 @@ class BooksAdapterGrid(context: Context, callBack: CallBack) :
fun registerListener(item: Any) {
binding.cvContent.setOnClickListener {
callBack.onItemClick(item)
callBack.onItemClick(item, binding.ivCover)
}
binding.cvContent.onLongClick {
callBack.onItemLongClick(item)
callBack.onItemLongClick(item, binding.ivCover)
}
}
@@ -113,10 +113,10 @@ class BooksAdapterList(context: Context, callBack: CallBack) :
fun registerListener(item: Any) {
binding.cvContent.setOnClickListener {
callBack.onItemClick(item)
callBack.onItemClick(item, binding.ivCover)
}
binding.cvContent.onLongClick {
callBack.onItemLongClick(item)
callBack.onItemLongClick(item, binding.ivCover)
}
}
@@ -166,10 +166,10 @@ class BooksAdapterList(context: Context, callBack: CallBack) :
fun registerListener(item: Any) {
binding.cvContent.setOnClickListener {
callBack.onItemClick(item)
callBack.onItemClick(item, binding.ivCover)
}
binding.cvContent.onLongClick {
callBack.onItemLongClick(item)
callBack.onItemLongClick(item, binding.ivCover)
}
}
@@ -65,12 +65,6 @@ class ExploreAdapter(context: Context, val callBack: CallBack) :
item.exploreKinds()
}.onSuccess { kindList ->
upKindList(flexbox, item.bookSourceUrl, kindList)
}.onFinally {
if (scrollTo >= 0) {
callBack.scrollTo(scrollTo)
scrollTo = -1
}
}
} else {
ivStatus.icon = ContextCompat.getDrawable(context, R.drawable.ic_arrow_right)
@@ -1,16 +1,15 @@
package io.legato.kazusa.ui.main.explore
//import io.legado.app.lib.theme.primaryColor
//import io.legado.app.lib.theme.primaryTextColor
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.SubMenu
import android.view.View
import android.view.inputmethod.EditorInfo
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.core.widget.doAfterTextChanged
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
@@ -29,8 +28,6 @@ import io.legato.kazusa.data.entities.BookSourcePart
import io.legato.kazusa.databinding.FragmentExploreBinding
import io.legato.kazusa.help.config.AppConfig
import io.legato.kazusa.lib.dialogs.alert
//import io.legado.app.lib.theme.primaryColor
//import io.legado.app.lib.theme.primaryTextColor
import io.legato.kazusa.ui.book.explore.ExploreShowActivity
import io.legato.kazusa.ui.book.search.SearchActivity
import io.legato.kazusa.ui.book.search.SearchScope
@@ -103,10 +100,8 @@ class ExploreFragment() : VMBaseFragment<ExploreViewModel>(R.layout.fragment_exp
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
val query = searchView.text.toString()
upExploreData(query)
searchBar.hint = if (query.isEmpty()) {
searchBar.hint = query.ifEmpty {
getString(R.string.screen_find)
} else {
query
}
searchView.hide()
return@setOnEditorActionListener true