This commit is contained in:
Horis
2024-09-01 10:45:43 +08:00
parent 30ec23390a
commit dde4af4517
8 changed files with 41 additions and 87 deletions
@@ -10,8 +10,6 @@ import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.widget.SeekBar import android.widget.SeekBar
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.VMBaseActivity import io.legado.app.base.VMBaseActivity
@@ -39,6 +37,7 @@ import io.legado.app.ui.book.toc.TocActivityResult
import io.legado.app.ui.login.SourceLoginActivity import io.legado.app.ui.login.SourceLoginActivity
import io.legado.app.ui.widget.seekbar.SeekBarChangeListener import io.legado.app.ui.widget.seekbar.SeekBarChangeListener
import io.legado.app.utils.StartActivityContract import io.legado.app.utils.StartActivityContract
import io.legado.app.utils.applyNavigationBarPadding
import io.legado.app.utils.dpToPx import io.legado.app.utils.dpToPx
import io.legado.app.utils.invisible import io.legado.app.utils.invisible
import io.legado.app.utils.observeEvent import io.legado.app.utils.observeEvent
@@ -51,7 +50,6 @@ import io.legado.app.utils.visible
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import splitties.views.bottomPadding
import splitties.views.onLongClick import splitties.views.onLongClick
import java.util.Locale import java.util.Locale
@@ -187,11 +185,7 @@ class AudioPlayActivity :
binding.ivTimer.setOnClickListener { binding.ivTimer.setOnClickListener {
timerSliderPopup.showAsDropDown(it, 0, (-100).dpToPx(), Gravity.TOP) timerSliderPopup.showAsDropDown(it, 0, (-100).dpToPx(), Gravity.TOP)
} }
ViewCompat.setOnApplyWindowInsetsListener(binding.llPlayMenu) { _, windowInsets -> binding.llPlayMenu.applyNavigationBarPadding()
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())
binding.llPlayMenu.bottomPadding = insets.bottom
windowInsets
}
} }
private fun upCover(path: String?) { private fun upCover(path: String?) {
@@ -49,8 +49,7 @@ class ExploreShowActivity : VMBaseActivity<ActivityExploreShowBinding, ExploreSh
loadMoreView.startLoad() loadMoreView.startLoad()
loadMoreView.setOnClickListener { loadMoreView.setOnClickListener {
if (!loadMoreView.isLoading) { if (!loadMoreView.isLoading) {
loadMoreView.hasMore() scrollToBottom(true)
scrollToBottom()
} }
} }
binding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { binding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
@@ -63,9 +62,9 @@ class ExploreShowActivity : VMBaseActivity<ActivityExploreShowBinding, ExploreSh
}) })
} }
private fun scrollToBottom() { private fun scrollToBottom(forceLoad: Boolean = false) {
if (loadMoreView.hasMore && !loadMoreView.isLoading) { if ((loadMoreView.hasMore && !loadMoreView.isLoading) || forceLoad) {
loadMoreView.startLoad() loadMoreView.hasMore()
viewModel.explore() viewModel.explore()
} }
} }
@@ -74,7 +73,7 @@ class ExploreShowActivity : VMBaseActivity<ActivityExploreShowBinding, ExploreSh
loadMoreView.stopLoad() loadMoreView.stopLoad()
if (books.isEmpty() && adapter.isEmpty()) { if (books.isEmpty() && adapter.isEmpty()) {
loadMoreView.noMore(getString(R.string.empty)) loadMoreView.noMore(getString(R.string.empty))
} else if (adapter.itemCount == books.size) { } else if (adapter.getActualItemCount() == books.size) {
loadMoreView.noMore() loadMoreView.noMore()
} else { } else {
adapter.setItems(books) adapter.setItems(books)
@@ -10,8 +10,6 @@ import android.widget.CheckBox
import android.widget.LinearLayout import android.widget.LinearLayout
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.VMBaseActivity import io.legado.app.base.VMBaseActivity
@@ -60,6 +58,7 @@ import io.legado.app.ui.widget.dialog.WaitDialog
import io.legado.app.utils.ColorUtils import io.legado.app.utils.ColorUtils
import io.legado.app.utils.GSON import io.legado.app.utils.GSON
import io.legado.app.utils.StartActivityContract import io.legado.app.utils.StartActivityContract
import io.legado.app.utils.applyNavigationBarPadding
import io.legado.app.utils.dpToPx import io.legado.app.utils.dpToPx
import io.legado.app.utils.gone import io.legado.app.utils.gone
import io.legado.app.utils.longToastOnUi import io.legado.app.utils.longToastOnUi
@@ -74,7 +73,6 @@ import io.legado.app.utils.visible
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import splitties.views.bottomPadding
class BookInfoActivity : class BookInfoActivity :
VMBaseActivity<ActivityBookInfoBinding, BookInfoViewModel>(toolBarTheme = Theme.Dark), VMBaseActivity<ActivityBookInfoBinding, BookInfoViewModel>(toolBarTheme = Theme.Dark),
@@ -157,6 +155,7 @@ class BookInfoActivity :
binding.arcView.setBgColor(backgroundColor) binding.arcView.setBgColor(backgroundColor)
binding.llInfo.setBackgroundColor(backgroundColor) binding.llInfo.setBackgroundColor(backgroundColor)
binding.flAction.setBackgroundColor(bottomBackground) binding.flAction.setBackgroundColor(bottomBackground)
binding.flAction.applyNavigationBarPadding()
binding.tvShelf.setTextColor(getPrimaryTextColor(ColorUtils.isColorLight(bottomBackground))) binding.tvShelf.setTextColor(getPrimaryTextColor(ColorUtils.isColorLight(bottomBackground)))
binding.tvToc.text = getString(R.string.toc_s, getString(R.string.loading)) binding.tvToc.text = getString(R.string.toc_s, getString(R.string.loading))
viewModel.bookData.observe(this) { showBook(it) } viewModel.bookData.observe(this) { showBook(it) }
@@ -164,11 +163,6 @@ class BookInfoActivity :
viewModel.waitDialogData.observe(this) { upWaitDialogStatus(it) } viewModel.waitDialogData.observe(this) { upWaitDialogStatus(it) }
viewModel.initData(intent) viewModel.initData(intent)
initViewEvent() initViewEvent()
ViewCompat.setOnApplyWindowInsetsListener(binding.flAction) { _, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())
binding.flAction.bottomPadding = insets.bottom
windowInsets
}
} }
override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
@@ -15,8 +15,6 @@ import android.view.animation.Animation
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.SeekBar import android.widget.SeekBar
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import io.legado.app.R import io.legado.app.R
@@ -41,6 +39,7 @@ import io.legado.app.ui.widget.seekbar.SeekBarChangeListener
import io.legado.app.utils.ColorUtils import io.legado.app.utils.ColorUtils
import io.legado.app.utils.ConstraintModify import io.legado.app.utils.ConstraintModify
import io.legado.app.utils.activity import io.legado.app.utils.activity
import io.legado.app.utils.applyNavigationBarPadding
import io.legado.app.utils.dpToPx import io.legado.app.utils.dpToPx
import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getPrefBoolean
import io.legado.app.utils.gone import io.legado.app.utils.gone
@@ -51,7 +50,6 @@ import io.legado.app.utils.openUrl
import io.legado.app.utils.putPrefBoolean import io.legado.app.utils.putPrefBoolean
import io.legado.app.utils.startActivity import io.legado.app.utils.startActivity
import io.legado.app.utils.visible import io.legado.app.utils.visible
import splitties.views.bottomPadding
import splitties.views.onClick import splitties.views.onClick
import splitties.views.onLongClick import splitties.views.onLongClick
@@ -235,11 +233,7 @@ class ReadMenu @JvmOverloads constructor(
/** /**
* 确保视图不被导航栏遮挡 * 确保视图不被导航栏遮挡
*/ */
ViewCompat.setOnApplyWindowInsetsListener(this@ReadMenu) { _, windowInsets -> applyNavigationBarPadding()
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())
root.bottomPadding = insets.bottom
windowInsets
}
} }
fun reset() { fun reset() {
@@ -5,8 +5,6 @@ import android.content.Context
import android.view.LayoutInflater import android.view.LayoutInflater
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.isInvisible import androidx.core.view.isInvisible
import io.legado.app.R import io.legado.app.R
@@ -23,11 +21,11 @@ import io.legado.app.ui.book.read.page.entities.TextPos
import io.legado.app.ui.book.read.page.provider.ChapterProvider import io.legado.app.ui.book.read.page.provider.ChapterProvider
import io.legado.app.ui.widget.BatteryView import io.legado.app.ui.widget.BatteryView
import io.legado.app.utils.activity import io.legado.app.utils.activity
import io.legado.app.utils.applyStatusBarPadding
import io.legado.app.utils.dpToPx import io.legado.app.utils.dpToPx
import io.legado.app.utils.gone import io.legado.app.utils.gone
import io.legado.app.utils.setTextIfNotEqual import io.legado.app.utils.setTextIfNotEqual
import splitties.views.backgroundColor import splitties.views.backgroundColor
import splitties.views.topPadding
import java.util.Date import java.util.Date
/** /**
@@ -62,11 +60,7 @@ class PageView(context: Context) : FrameLayout(context) {
init { init {
if (!isInEditMode) { if (!isInEditMode) {
upStyle() upStyle()
ViewCompat.setOnApplyWindowInsetsListener(this) { _, windowInsets -> binding.vwStatusBar.applyStatusBarPadding()
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.statusBars())
binding.vwStatusBar.topPadding = insets.top
windowInsets
}
} }
} }
@@ -12,6 +12,7 @@ import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.BaseFragment import io.legado.app.base.BaseFragment
import io.legado.app.constant.AppLog import io.legado.app.constant.AppLog
@@ -72,7 +73,6 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
} }
} }
private var booksFlowJob: Job? = null private var booksFlowJob: Job? = null
private var savedInstanceState: Bundle? = null
var position = 0 var position = 0
private set private set
var groupId = -1L var groupId = -1L
@@ -83,7 +83,6 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
private var enableRefresh = true private var enableRefresh = true
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
this.savedInstanceState = savedInstanceState
arguments?.let { arguments?.let {
position = it.getInt("position", 0) position = it.getInt("position", 0)
groupId = it.getLong("groupId", -1) groupId = it.getLong("groupId", -1)
@@ -113,11 +112,12 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
} else { } else {
binding.rvBookshelf.setRecycledViewPool(activityViewModel.booksGridRecycledViewPool) binding.rvBookshelf.setRecycledViewPool(activityViewModel.booksGridRecycledViewPool)
} }
booksAdapter.stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY
binding.rvBookshelf.adapter = booksAdapter binding.rvBookshelf.adapter = booksAdapter
booksAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { booksAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
val layoutManager = binding.rvBookshelf.layoutManager val layoutManager = binding.rvBookshelf.layoutManager
if (positionStart == 0 && layoutManager is LinearLayoutManager) { if (positionStart == 0 && itemCount == 1 && layoutManager is LinearLayoutManager) {
val scrollTo = layoutManager.findFirstVisibleItemPosition() - itemCount val scrollTo = layoutManager.findFirstVisibleItemPosition() - itemCount
binding.rvBookshelf.scrollToPosition(max(0, scrollTo)) binding.rvBookshelf.scrollToPosition(max(0, scrollTo))
} }
@@ -125,7 +125,7 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) { override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {
val layoutManager = binding.rvBookshelf.layoutManager val layoutManager = binding.rvBookshelf.layoutManager
if (toPosition == 0 && layoutManager is LinearLayoutManager) { if (toPosition == 0 && itemCount == 1 && layoutManager is LinearLayoutManager) {
val scrollTo = layoutManager.findFirstVisibleItemPosition() - itemCount val scrollTo = layoutManager.findFirstVisibleItemPosition() - itemCount
binding.rvBookshelf.scrollToPosition(max(0, scrollTo)) binding.rvBookshelf.scrollToPosition(max(0, scrollTo))
} }
@@ -191,25 +191,11 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
binding.tvEmptyMsg.isGone = list.isNotEmpty() binding.tvEmptyMsg.isGone = list.isNotEmpty()
binding.refreshLayout.isEnabled = enableRefresh && list.isNotEmpty() binding.refreshLayout.isEnabled = enableRefresh && list.isNotEmpty()
booksAdapter.setItems(list) booksAdapter.setItems(list)
recoverPositionState()
delay(100) delay(100)
} }
} }
} }
private fun recoverPositionState() {
// 恢复书架位置状态
if (savedInstanceState?.getBoolean("needRecoverState") == true) {
val layoutManager = binding.rvBookshelf.layoutManager
if (layoutManager is LinearLayoutManager) {
val leavePosition = savedInstanceState!!.getInt("leavePosition")
val leaveOffset = savedInstanceState!!.getInt("leaveOffset")
layoutManager.scrollToPositionWithOffset(leavePosition, leaveOffset)
}
savedInstanceState!!.putBoolean("needRecoverState", false)
}
}
private fun startLastUpdateTimeJob() { private fun startLastUpdateTimeJob() {
upLastUpdateTimeJob?.cancel() upLastUpdateTimeJob?.cancel()
if (!AppConfig.showLastUpdateTime) { if (!AppConfig.showLastUpdateTime) {
@@ -241,28 +227,6 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
return booksAdapter.itemCount return booksAdapter.itemCount
} }
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
// 保存书架位置状态
val layoutManager = binding.rvBookshelf.layoutManager
if (layoutManager is LinearLayoutManager) {
val itemPosition = layoutManager.findFirstVisibleItemPosition()
val currentView = layoutManager.findViewByPosition(itemPosition)
val viewOffset = currentView?.top
if (viewOffset != null) {
outState.putInt("leavePosition", itemPosition)
outState.putInt("leaveOffset", viewOffset)
outState.putBoolean("needRecoverState", true)
} else if (savedInstanceState != null) {
val leavePosition = savedInstanceState!!.getInt("leavePosition")
val leaveOffset = savedInstanceState!!.getInt("leaveOffset")
outState.putInt("leavePosition", leavePosition)
outState.putInt("leaveOffset", leaveOffset)
outState.putBoolean("needRecoverState", true)
}
}
}
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
/** /**
@@ -9,8 +9,6 @@ import android.widget.FrameLayout
import androidx.annotation.MenuRes import androidx.annotation.MenuRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import io.legado.app.R import io.legado.app.R
import io.legado.app.databinding.ViewSelectActionBarBinding import io.legado.app.databinding.ViewSelectActionBarBinding
import io.legado.app.lib.theme.TintHelper import io.legado.app.lib.theme.TintHelper
@@ -20,8 +18,8 @@ import io.legado.app.lib.theme.elevation
import io.legado.app.lib.theme.getPrimaryTextColor import io.legado.app.lib.theme.getPrimaryTextColor
import io.legado.app.lib.theme.getSecondaryDisabledTextColor import io.legado.app.lib.theme.getSecondaryDisabledTextColor
import io.legado.app.utils.ColorUtils import io.legado.app.utils.ColorUtils
import io.legado.app.utils.applyNavigationBarPadding
import io.legado.app.utils.visible import io.legado.app.utils.visible
import splitties.views.bottomPadding
@Suppress("unused") @Suppress("unused")
@@ -54,12 +52,7 @@ class SelectActionBar @JvmOverloads constructor(
binding.btnRevertSelection.setOnClickListener { callBack?.revertSelection() } binding.btnRevertSelection.setOnClickListener { callBack?.revertSelection() }
binding.btnSelectActionMain.setOnClickListener { callBack?.onClickSelectBarMainAction() } binding.btnSelectActionMain.setOnClickListener { callBack?.onClickSelectBarMainAction() }
binding.ivMenuMore.setOnClickListener { selMenu?.show() } binding.ivMenuMore.setOnClickListener { selMenu?.show() }
val initialBottomPadding = binding.root.paddingBottom applyNavigationBarPadding()
ViewCompat.setOnApplyWindowInsetsListener(this) { _, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())
binding.root.bottomPadding = initialBottomPadding + insets.bottom
windowInsets
}
} }
} }
@@ -28,6 +28,8 @@ import androidx.appcompat.view.menu.MenuPopupHelper
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.core.graphics.record import androidx.core.graphics.record
import androidx.core.graphics.withTranslation import androidx.core.graphics.withTranslation
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.get import androidx.core.view.get
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager.widget.ViewPager import androidx.viewpager.widget.ViewPager
@@ -36,6 +38,8 @@ import io.legado.app.lib.theme.TintHelper
import io.legado.app.utils.canvasrecorder.CanvasRecorder import io.legado.app.utils.canvasrecorder.CanvasRecorder
import io.legado.app.utils.canvasrecorder.record import io.legado.app.utils.canvasrecorder.record
import splitties.systemservices.inputMethodManager import splitties.systemservices.inputMethodManager
import splitties.views.bottomPadding
import splitties.views.topPadding
import java.lang.reflect.Field import java.lang.reflect.Field
@@ -255,3 +259,21 @@ fun View.shouldHideSoftInput(event: MotionEvent): Boolean {
} }
return false return false
} }
fun View.applyStatusBarPadding(withInitialPadding: Boolean = false) {
val initialPadding = if (withInitialPadding) topPadding else 0
ViewCompat.setOnApplyWindowInsetsListener(this) { _, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.statusBars())
topPadding = initialPadding + insets.top
windowInsets
}
}
fun View.applyNavigationBarPadding(withInitialPadding: Boolean = false) {
val initialPadding = if (withInitialPadding) bottomPadding else 0
ViewCompat.setOnApplyWindowInsetsListener(this) { _, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())
bottomPadding = initialPadding + insets.bottom
windowInsets
}
}