mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 10:46:53 -04:00
Fixed: Tabs were being automatically restored after closing them, navigating away from the reader screen, and then returning.
* Removed unused code from the reader screen. * Refactored fullscreen mode functionality to align with Compose UI. * Improved the `CloseAllTabs` button styling to match the app theme. * Refactored the "Back to Top" button functionality using Compose, and enhanced its UI. * Fixed: `Long-press` on bottom app bar buttons was not working due to `IconButton` consuming the touch event. * Removed the unused `AnimationUtils` file. * Fixed: Navigation history (forward and backward) was not being displayed.
This commit is contained in:
parent
b694ae3170
commit
234e9169f6
@ -29,15 +29,12 @@ import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import kotlinx.coroutines.launch
|
||||
import org.kiwix.kiwixmobile.R
|
||||
import org.kiwix.kiwixmobile.cachedComponent
|
||||
import org.kiwix.kiwixmobile.core.R.anim
|
||||
import org.kiwix.kiwixmobile.core.R.drawable
|
||||
import org.kiwix.kiwixmobile.core.R.string
|
||||
import org.kiwix.kiwixmobile.core.base.BaseActivity
|
||||
import org.kiwix.kiwixmobile.core.base.FragmentActivityExtensions.Super
|
||||
@ -47,7 +44,6 @@ import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.setupDrawerToggl
|
||||
import org.kiwix.kiwixmobile.core.extensions.coreMainActivity
|
||||
import org.kiwix.kiwixmobile.core.extensions.isFileExist
|
||||
import org.kiwix.kiwixmobile.core.extensions.setBottomMarginToFragmentContainerView
|
||||
import org.kiwix.kiwixmobile.core.extensions.setImageDrawableCompat
|
||||
import org.kiwix.kiwixmobile.core.extensions.snack
|
||||
import org.kiwix.kiwixmobile.core.extensions.toast
|
||||
import org.kiwix.kiwixmobile.core.extensions.update
|
||||
@ -184,32 +180,6 @@ class KiwixReaderFragment : CoreReaderFragment() {
|
||||
* @see closeAllTabs
|
||||
*/
|
||||
override fun hideTabSwitcher(shouldCloseZimBook: Boolean) {
|
||||
actionBar?.let { actionBar ->
|
||||
actionBar.setDisplayShowTitleEnabled(true)
|
||||
toolbar?.let { activity?.setupDrawerToggle(it, true) }
|
||||
|
||||
setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
|
||||
|
||||
closeAllTabsButton?.setImageDrawableCompat(drawable.ic_close_black_24dp)
|
||||
if (tabSwitcherRoot?.isVisible == true) {
|
||||
tabSwitcherRoot?.visibility = GONE
|
||||
startAnimation(tabSwitcherRoot, anim.slide_up)
|
||||
progressBar?.visibility = View.GONE
|
||||
progressBar?.progress = 0
|
||||
contentFrame?.visibility = View.VISIBLE
|
||||
}
|
||||
readerMenuState?.showWebViewOptions(true)
|
||||
if (webViewList.isEmpty()) {
|
||||
exitBook(shouldCloseZimBook)
|
||||
} else {
|
||||
// Reset the top margin of web views to 0 to remove any previously set margin
|
||||
// This ensures that the web views are displayed without any additional
|
||||
// top margin for kiwix main app.
|
||||
setTopMarginToWebViews(0)
|
||||
selectTab(currentWebViewIndex)
|
||||
}
|
||||
}
|
||||
actionBar?.setDisplayShowTitleEnabled(true)
|
||||
toolbar?.let { activity?.setupDrawerToggle(it, true) }
|
||||
setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
|
||||
if (webViewList.isEmpty()) {
|
||||
|
@ -52,10 +52,7 @@ import android.view.ViewGroup
|
||||
import android.view.animation.AnimationUtils
|
||||
import android.webkit.WebBackForwardList
|
||||
import android.webkit.WebView
|
||||
import android.widget.Button
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageButton
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
@ -79,16 +76,12 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.Group
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.edit
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.ContentLoadingProgressBar
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
@ -96,10 +89,8 @@ import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import com.google.android.material.bottomappbar.BottomAppBar
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@ -134,8 +125,6 @@ import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.observeNavigatio
|
||||
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.requestNotificationPermission
|
||||
import org.kiwix.kiwixmobile.core.extensions.ViewGroupExtensions.findFirstTextView
|
||||
import org.kiwix.kiwixmobile.core.extensions.closeFullScreenMode
|
||||
import org.kiwix.kiwixmobile.core.extensions.getToolbarNavigationIcon
|
||||
import org.kiwix.kiwixmobile.core.extensions.setToolTipWithContentDescription
|
||||
import org.kiwix.kiwixmobile.core.extensions.showFullScreenMode
|
||||
import org.kiwix.kiwixmobile.core.extensions.snack
|
||||
import org.kiwix.kiwixmobile.core.extensions.toast
|
||||
@ -185,7 +174,6 @@ import org.kiwix.kiwixmobile.core.search.viewmodel.effects.SearchItemToOpen
|
||||
import org.kiwix.kiwixmobile.core.ui.components.NavigationIcon
|
||||
import org.kiwix.kiwixmobile.core.ui.components.rememberBottomNavigationVisibility
|
||||
import org.kiwix.kiwixmobile.core.ui.models.IconItem
|
||||
import org.kiwix.kiwixmobile.core.utils.AnimationUtils.rotate
|
||||
import org.kiwix.kiwixmobile.core.utils.DimenUtils.getWindowWidth
|
||||
import org.kiwix.kiwixmobile.core.utils.DonationDialogHandler
|
||||
import org.kiwix.kiwixmobile.core.utils.DonationDialogHandler.ShowDonationDialogCallback
|
||||
@ -237,24 +225,16 @@ abstract class CoreReaderFragment :
|
||||
private var fragmentReaderBinding: FragmentReaderBinding? = null
|
||||
|
||||
var toolbar: Toolbar? = null
|
||||
var toolbarContainer: AppBarLayout? = null
|
||||
var progressBar: ContentLoadingProgressBar? = null
|
||||
|
||||
var drawerLayout: DrawerLayout? = null
|
||||
protected var tableDrawerRightContainer: NavigationView? = null
|
||||
|
||||
var contentFrame: FrameLayout? = null
|
||||
|
||||
var bottomToolbar: BottomAppBar? = null
|
||||
|
||||
var tabSwitcherRoot: View? = null
|
||||
|
||||
var closeAllTabsButton: FloatingActionButton? = null
|
||||
|
||||
var videoView: ViewGroup? = null
|
||||
|
||||
var noOpenBookButton: Button? = null
|
||||
|
||||
var activityMainRoot: View? = null
|
||||
|
||||
@JvmField
|
||||
@ -273,10 +253,6 @@ abstract class CoreReaderFragment :
|
||||
@Inject
|
||||
var darkModeConfig: DarkModeConfig? = null
|
||||
|
||||
@JvmField
|
||||
@Inject
|
||||
var menuFactory: MainMenu.Factory? = null
|
||||
|
||||
@JvmField
|
||||
@Inject
|
||||
var libkiwixBookmarks: LibkiwixBookmarks? = null
|
||||
@ -299,29 +275,7 @@ abstract class CoreReaderFragment :
|
||||
|
||||
var toolbarWithSearchPlaceholder: ConstraintLayout? = null
|
||||
|
||||
var backToTopButton: FloatingActionButton? = null
|
||||
|
||||
private var stopTTSButton: Button? = null
|
||||
|
||||
var pauseTTSButton: Button? = null
|
||||
|
||||
var ttsControls: Group? = null
|
||||
|
||||
private var exitFullscreenButton: ImageButton? = null
|
||||
|
||||
private var bottomToolbarBookmark: ImageView? = null
|
||||
|
||||
private var bottomToolbarArrowBack: ImageView? = null
|
||||
|
||||
private var bottomToolbarArrowForward: ImageView? = null
|
||||
|
||||
private var bottomToolbarHome: ImageView? = null
|
||||
|
||||
private var tabRecyclerView: RecyclerView? = null
|
||||
|
||||
private var noOpenBookText: TextView? = null
|
||||
private var bottomToolbarToc: ImageView? = null
|
||||
|
||||
private var isFirstTimeMainPageLoaded = true
|
||||
private var isFromManageExternalLaunch = false
|
||||
private val savingTabsMutex = Mutex()
|
||||
@ -384,7 +338,6 @@ abstract class CoreReaderFragment :
|
||||
fullScreenItem = false to null,
|
||||
showBackToTopButton = false,
|
||||
backToTopButtonClick = { backToTop() },
|
||||
showFullscreenButton = false,
|
||||
onExitFullscreenClick = { closeFullScreen() },
|
||||
showTtsControls = false,
|
||||
onPauseTtsClick = { pauseTts() },
|
||||
@ -420,7 +373,8 @@ abstract class CoreReaderFragment :
|
||||
override fun onCloseTab(position: Int) {
|
||||
closeTab(position)
|
||||
}
|
||||
}
|
||||
},
|
||||
shouldShowFullScreenMode = false
|
||||
)
|
||||
)
|
||||
private var readerLifeCycleScope: CoroutineScope? = null
|
||||
@ -699,29 +653,13 @@ abstract class CoreReaderFragment :
|
||||
private fun prepareViews() {
|
||||
fragmentReaderBinding?.let { readerBinding ->
|
||||
videoView = readerBinding.fullscreenVideoContainer
|
||||
noOpenBookButton = readerBinding.goToLibraryButtonNoOpenBook
|
||||
noOpenBookText = readerBinding.noOpenBookText
|
||||
with(readerBinding.root) {
|
||||
activityMainRoot = findViewById(R.id.activity_main_root)
|
||||
contentFrame = findViewById(R.id.activity_main_content_frame)
|
||||
toolbar = findViewById(R.id.toolbar)
|
||||
toolbarContainer = findViewById(R.id.fragment_main_app_bar)
|
||||
progressBar = findViewById(R.id.main_fragment_progress_view)
|
||||
bottomToolbar = findViewById(R.id.bottom_toolbar)
|
||||
tabSwitcherRoot = findViewById(R.id.activity_main_tab_switcher)
|
||||
closeAllTabsButton = findViewById(R.id.tab_switcher_close_all_tabs)
|
||||
toolbarWithSearchPlaceholder = findViewById(R.id.toolbarWithSearchPlaceholder)
|
||||
backToTopButton = findViewById(R.id.activity_main_back_to_top_fab)
|
||||
stopTTSButton = findViewById(R.id.activity_main_button_stop_tts)
|
||||
pauseTTSButton = findViewById(R.id.activity_main_button_pause_tts)
|
||||
ttsControls = findViewById(R.id.activity_main_tts_controls)
|
||||
exitFullscreenButton = findViewById(R.id.activity_main_fullscreen_button)
|
||||
bottomToolbarBookmark = findViewById(R.id.bottom_toolbar_bookmark)
|
||||
bottomToolbarArrowBack = findViewById(R.id.bottom_toolbar_arrow_back)
|
||||
bottomToolbarArrowForward = findViewById(R.id.bottom_toolbar_arrow_forward)
|
||||
bottomToolbarHome = findViewById(R.id.bottom_toolbar_home)
|
||||
tabRecyclerView = findViewById(R.id.tab_switcher_recycler_view)
|
||||
bottomToolbarToc = findViewById(R.id.bottom_toolbar_toc)
|
||||
donationLayout = findViewById(R.id.donation_layout)
|
||||
}
|
||||
}
|
||||
@ -731,53 +669,6 @@ abstract class CoreReaderFragment :
|
||||
toolbarWithSearchPlaceholder?.setOnClickListener {
|
||||
openSearch(searchString = "", isOpenedFromTabView = false, false)
|
||||
}
|
||||
backToTopButton?.setOnClickListener {
|
||||
backToTop()
|
||||
}
|
||||
stopTTSButton?.setOnClickListener {
|
||||
stopTts()
|
||||
}
|
||||
pauseTTSButton?.setOnClickListener {
|
||||
pauseTts()
|
||||
}
|
||||
exitFullscreenButton?.setOnClickListener {
|
||||
closeFullScreen()
|
||||
}
|
||||
bottomToolbarBookmark?.apply {
|
||||
setOnClickListener {
|
||||
toggleBookmark()
|
||||
}
|
||||
setOnLongClickListener {
|
||||
goToBookmarks()
|
||||
}
|
||||
}
|
||||
bottomToolbarArrowBack?.apply {
|
||||
setOnClickListener {
|
||||
goBack()
|
||||
}
|
||||
setOnLongClickListener {
|
||||
showBackwardHistory()
|
||||
true
|
||||
}
|
||||
}
|
||||
bottomToolbarArrowForward?.apply {
|
||||
setOnClickListener {
|
||||
goForward()
|
||||
}
|
||||
setOnLongClickListener {
|
||||
showForwardHistory()
|
||||
true
|
||||
}
|
||||
}
|
||||
bottomToolbarToc?.setOnClickListener {
|
||||
openToc()
|
||||
}
|
||||
closeAllTabsButton?.setOnClickListener {
|
||||
closeAllTabs()
|
||||
}
|
||||
bottomToolbarHome?.setOnClickListener {
|
||||
openMainPage()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initTabCallback() {
|
||||
@ -820,7 +711,7 @@ abstract class CoreReaderFragment :
|
||||
}
|
||||
|
||||
override fun onFinish() {
|
||||
backToTopButton?.hide()
|
||||
hideBackToTopButton()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -956,21 +847,6 @@ abstract class CoreReaderFragment :
|
||||
|
||||
private fun showTabSwitcher() {
|
||||
(requireActivity() as CoreMainActivity).disableDrawer()
|
||||
actionBar?.apply {
|
||||
setDisplayHomeAsUpEnabled(true)
|
||||
setHomeAsUpIndicator(
|
||||
ContextCompat.getDrawable(requireActivity(), R.drawable.ic_round_add_white_36dp)
|
||||
)
|
||||
// set the contentDescription to UpIndicator icon.
|
||||
toolbar?.getToolbarNavigationIcon()?.setToolTipWithContentDescription(
|
||||
getString(R.string.search_open_in_new_tab)
|
||||
)
|
||||
setDisplayShowTitleEnabled(false)
|
||||
}
|
||||
closeAllTabsButton?.setToolTipWithContentDescription(
|
||||
resources.getString(R.string.close_all_tabs)
|
||||
)
|
||||
setIsCloseAllTabButtonClickable(true)
|
||||
// Set a negative top margin to the web views to remove
|
||||
// the unwanted blank space caused by the toolbar.
|
||||
// setTopMarginToWebViews(-requireActivity().getToolbarHeight())
|
||||
@ -979,13 +855,10 @@ abstract class CoreReaderFragment :
|
||||
copy(
|
||||
shouldShowBottomAppBar = false,
|
||||
pageLoadingItem = false to ZERO,
|
||||
readerScreenTitle = ""
|
||||
readerScreenTitle = "",
|
||||
showBackToTopButton = false
|
||||
)
|
||||
}
|
||||
contentFrame?.visibility = GONE
|
||||
progressBar?.visibility = GONE
|
||||
backToTopButton?.hide()
|
||||
setTabSwitcherVisibility(VISIBLE)
|
||||
startAnimation(tabSwitcherRoot, R.anim.slide_down)
|
||||
tabsAdapter?.let { tabsAdapter ->
|
||||
tabRecyclerView?.let { recyclerView ->
|
||||
@ -1053,23 +926,8 @@ abstract class CoreReaderFragment :
|
||||
* as closing the ZIM book would require reloading the ZIM file, which can be a resource-intensive operation.
|
||||
*/
|
||||
protected open fun hideTabSwitcher(shouldCloseZimBook: Boolean = true) {
|
||||
actionBar?.apply {
|
||||
setDisplayShowTitleEnabled(true)
|
||||
}
|
||||
toolbar?.let(::setUpDrawerToggle)
|
||||
setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
|
||||
closeAllTabsButton?.setImageDrawable(
|
||||
ContextCompat.getDrawable(requireActivity(), R.drawable.ic_close_black_24dp)
|
||||
)
|
||||
tabSwitcherRoot?.let {
|
||||
if (it.isVisible) {
|
||||
setTabSwitcherVisibility(GONE)
|
||||
startAnimation(it, R.anim.slide_up)
|
||||
progressBar?.visibility = VISIBLE
|
||||
contentFrame?.visibility = VISIBLE
|
||||
}
|
||||
}
|
||||
progressBar?.hide()
|
||||
selectTab(currentWebViewIndex)
|
||||
readerScreenState.update {
|
||||
copy(
|
||||
@ -1477,32 +1335,16 @@ abstract class CoreReaderFragment :
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
private fun unBindViewsAndBinding() {
|
||||
activityMainRoot = null
|
||||
noOpenBookButton = null
|
||||
toolbarWithSearchPlaceholder = null
|
||||
backToTopButton = null
|
||||
stopTTSButton = null
|
||||
pauseTTSButton = null
|
||||
ttsControls = null
|
||||
exitFullscreenButton = null
|
||||
bottomToolbarBookmark = null
|
||||
bottomToolbarArrowBack = null
|
||||
bottomToolbarArrowForward = null
|
||||
bottomToolbarHome = null
|
||||
tabRecyclerView = null
|
||||
noOpenBookText = null
|
||||
bottomToolbarToc = null
|
||||
bottomToolbar = null
|
||||
tabSwitcherRoot = null
|
||||
videoView = null
|
||||
contentFrame = null
|
||||
toolbarContainer = null
|
||||
compatCallback?.finish()
|
||||
compatCallback = null
|
||||
toolbar?.setOnTouchListener(null)
|
||||
toolbar = null
|
||||
progressBar = null
|
||||
drawerLayout = null
|
||||
closeAllTabsButton = null
|
||||
tableDrawerRightContainer = null
|
||||
fragmentReaderBinding?.root?.removeAllViews()
|
||||
fragmentReaderBinding = null
|
||||
@ -1627,18 +1469,17 @@ abstract class CoreReaderFragment :
|
||||
if (index <= currentWebViewIndex && currentWebViewIndex > 0) {
|
||||
currentWebViewIndex--
|
||||
}
|
||||
tabsAdapter?.apply {
|
||||
notifyItemRemoved(index)
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
readerScreenState.value.snackBarHostState.snack(
|
||||
requireActivity().getString(R.string.tab_closed),
|
||||
actionLabel = requireActivity().getString(R.string.undo),
|
||||
actionClick = { restoreDeletedTab(index) },
|
||||
lifecycleScope = lifecycleScope,
|
||||
snackBarResult = { result ->
|
||||
if (result == SnackbarResult.Dismissed && webViewList.isEmpty() && isAdded) {
|
||||
closeZimBook()
|
||||
if (result == SnackbarResult.Dismissed && isAdded) {
|
||||
saveTabStates()
|
||||
if (webViewList.isEmpty()) {
|
||||
closeZimBook()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -1774,14 +1615,13 @@ abstract class CoreReaderFragment :
|
||||
if (readerScreenState.value.showTtsControls) {
|
||||
// currently TTS is running
|
||||
if (isBackToTopEnabled) {
|
||||
readerScreenState.update { copy(showBackToTopButton = true) }
|
||||
backToTopButton?.show()
|
||||
showBackToTopButton()
|
||||
}
|
||||
tts?.stop()
|
||||
} else {
|
||||
// TTS is not running.
|
||||
if (isBackToTopEnabled) {
|
||||
readerScreenState.update { copy(showBackToTopButton = false) }
|
||||
hideBackToTopButton()
|
||||
}
|
||||
readerScreenState.update {
|
||||
copy(pauseTtsButtonText = context?.getString(R.string.tts_pause).orEmpty())
|
||||
@ -1911,12 +1751,12 @@ abstract class CoreReaderFragment :
|
||||
@Suppress("MagicNumber")
|
||||
protected open fun openFullScreen() {
|
||||
(requireActivity() as CoreMainActivity).disableDrawer(false)
|
||||
toolbarContainer?.visibility = GONE
|
||||
readerScreenState.update {
|
||||
copy(shouldShowBottomAppBar = false)
|
||||
copy(
|
||||
shouldShowBottomAppBar = false,
|
||||
shouldShowFullScreenMode = true
|
||||
)
|
||||
}
|
||||
exitFullscreenButton?.visibility = VISIBLE
|
||||
exitFullscreenButton?.background?.alpha = 153
|
||||
val window = requireActivity().window
|
||||
window.decorView.showFullScreenMode(window)
|
||||
getCurrentWebView()?.apply {
|
||||
@ -1931,10 +1771,13 @@ abstract class CoreReaderFragment :
|
||||
toolbar?.let(::setUpDrawerToggle)
|
||||
setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
|
||||
sharedPreferenceUtil?.putPrefFullScreen(false)
|
||||
toolbarContainer?.visibility = VISIBLE
|
||||
readerScreenState.update {
|
||||
copy(
|
||||
shouldShowBottomAppBar = true,
|
||||
shouldShowFullScreenMode = false
|
||||
)
|
||||
}
|
||||
updateBottomToolbarVisibility()
|
||||
exitFullscreenButton?.visibility = GONE
|
||||
exitFullscreenButton?.background?.alpha = 255
|
||||
val window = requireActivity().window
|
||||
window.decorView.closeFullScreenMode(window)
|
||||
getCurrentWebView()?.requestLayout()
|
||||
@ -2132,17 +1975,12 @@ abstract class CoreReaderFragment :
|
||||
|
||||
private fun closeAllTabs() {
|
||||
onReadAloudStop()
|
||||
closeAllTabsButton?.apply {
|
||||
rotate()
|
||||
setIsCloseAllTabButtonClickable(false)
|
||||
}
|
||||
tempZimSourceForUndo = zimReaderContainer?.zimReaderSource
|
||||
tempWebViewListForUndo.apply {
|
||||
clear()
|
||||
addAll(webViewList)
|
||||
}
|
||||
webViewList.clear()
|
||||
tabsAdapter?.notifyDataSetChanged()
|
||||
openHomeScreen()
|
||||
readerScreenState.value.snackBarHostState.snack(
|
||||
context?.getString(R.string.tabs_closed).orEmpty(),
|
||||
@ -2150,17 +1988,16 @@ abstract class CoreReaderFragment :
|
||||
actionClick = { restoreDeletedTabs() },
|
||||
lifecycleScope = lifecycleScope,
|
||||
snackBarResult = { result ->
|
||||
if (result == SnackbarResult.Dismissed && webViewList.isEmpty() && isAdded) {
|
||||
closeZimBook()
|
||||
if (result == SnackbarResult.Dismissed && isAdded) {
|
||||
saveTabStates()
|
||||
if (webViewList.isEmpty()) {
|
||||
closeZimBook()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun setIsCloseAllTabButtonClickable(isClickable: Boolean) {
|
||||
closeAllTabsButton?.isClickable = isClickable
|
||||
}
|
||||
|
||||
private fun restoreDeletedTabs() {
|
||||
if (tempWebViewListForUndo.isNotEmpty()) {
|
||||
webViewList.addAll(tempWebViewListForUndo)
|
||||
@ -2652,12 +2489,20 @@ abstract class CoreReaderFragment :
|
||||
isBackToTopEnabled = sharedPreferenceUtil?.prefBackToTop == true
|
||||
isOpenNewTabInBackground = sharedPreferenceUtil?.prefNewTabBackground == true
|
||||
if (!isBackToTopEnabled) {
|
||||
backToTopButton?.hide()
|
||||
hideBackToTopButton()
|
||||
}
|
||||
openFullScreenIfEnabled()
|
||||
updateNightMode()
|
||||
}
|
||||
|
||||
private fun showBackToTopButton() {
|
||||
readerScreenState.update { copy(showBackToTopButton = true) }
|
||||
}
|
||||
|
||||
private fun hideBackToTopButton() {
|
||||
readerScreenState.update { copy(showBackToTopButton = false) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the current state of tabs and web view history to persistent storage.
|
||||
*
|
||||
@ -2869,28 +2714,18 @@ abstract class CoreReaderFragment :
|
||||
tabsAdapter?.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
@Suppress("NestedBlockDepth", "MagicNumber")
|
||||
@Suppress("MagicNumber")
|
||||
override fun webViewPageChanged(page: Int, maxPages: Int) {
|
||||
if (isBackToTopEnabled) {
|
||||
hideBackToTopTimer?.apply {
|
||||
cancel()
|
||||
start()
|
||||
}
|
||||
getCurrentWebView()?.scrollY?.let {
|
||||
if (it > 200) {
|
||||
if (
|
||||
(backToTopButton?.isGone == true || backToTopButton?.isInvisible == true) &&
|
||||
ttsControls?.visibility == GONE
|
||||
) {
|
||||
backToTopButton?.show()
|
||||
}
|
||||
} else {
|
||||
backToTopButton?.isVisible
|
||||
if (backToTopButton?.visibility == VISIBLE) {
|
||||
backToTopButton?.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isBackToTopEnabled) return
|
||||
hideBackToTopTimer?.apply {
|
||||
cancel()
|
||||
start()
|
||||
}
|
||||
val scrollY = getCurrentWebView()?.scrollY ?: return
|
||||
if (scrollY > 200 && !readerScreenState.value.showTtsControls) {
|
||||
showBackToTopButton()
|
||||
} else {
|
||||
hideBackToTopButton()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ import android.widget.FrameLayout
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@ -46,6 +47,7 @@ import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.BottomAppBar
|
||||
import androidx.compose.material3.BottomAppBarDefaults
|
||||
@ -54,14 +56,16 @@ import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.FloatingActionButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SmallFloatingActionButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.material3.minimumInteractiveComponentSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
@ -73,6 +77,7 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
@ -106,8 +111,10 @@ import org.kiwix.kiwixmobile.core.ui.models.IconItem
|
||||
import org.kiwix.kiwixmobile.core.ui.models.IconItem.Drawable
|
||||
import org.kiwix.kiwixmobile.core.ui.models.toPainter
|
||||
import org.kiwix.kiwixmobile.core.ui.theme.Black
|
||||
import org.kiwix.kiwixmobile.core.ui.theme.DenimBlue800
|
||||
import org.kiwix.kiwixmobile.core.ui.theme.KiwixDialogTheme
|
||||
import org.kiwix.kiwixmobile.core.ui.theme.White
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.BACK_TO_TOP_BUTTON_BOTTOM_MARGIN
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.CLOSE_ALL_TAB_BUTTON_BOTTOM_PADDING
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.CLOSE_TAB_ICON_ANIMATION_TIMEOUT
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.CLOSE_TAB_ICON_SIZE
|
||||
@ -115,8 +122,11 @@ import org.kiwix.kiwixmobile.core.utils.ComposeDimens.EIGHT_DP
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.FOUR_DP
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.ONE_DP
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.READER_BOTTOM_APP_BAR_BUTTON_ICON_SIZE
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.READER_BOTTOM_APP_BAR_DISABLE_BUTTON_ALPHA
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.READER_BOTTOM_APP_BAR_LAYOUT_HEIGHT
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.SEVEN_DP
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.SIXTEEN_DP
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.TEN_DP
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.TTS_BUTTONS_CONTROL_ALPHA
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.TWO_DP
|
||||
import org.kiwix.kiwixmobile.core.utils.StyleUtils.fromHtml
|
||||
@ -166,7 +176,7 @@ private fun ReaderTopBar(
|
||||
scrollBehavior: TopAppBarScrollBehavior,
|
||||
navigationIcon: @Composable () -> Unit,
|
||||
) {
|
||||
if (!state.fullScreenItem.first) {
|
||||
if (!state.shouldShowFullScreenMode) {
|
||||
KiwixAppBar(
|
||||
title = if (state.showTabSwitcher) "" else state.readerScreenTitle,
|
||||
navigationIcon = navigationIcon,
|
||||
@ -205,6 +215,10 @@ private fun ReaderContentLayout(state: ReaderScreenState, modifier: Modifier = M
|
||||
)
|
||||
}
|
||||
ShowFullScreenView(state)
|
||||
CloseFullScreenImageButton(
|
||||
state.shouldShowFullScreenMode,
|
||||
state.onExitFullscreenClick
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,6 +226,29 @@ private fun ReaderContentLayout(state: ReaderScreenState, modifier: Modifier = M
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BoxScope.CloseFullScreenImageButton(
|
||||
shouldShowFullScreenMode: Boolean,
|
||||
onExitFullScreen: () -> Unit
|
||||
) {
|
||||
if (shouldShowFullScreenMode) {
|
||||
IconButton(
|
||||
onClick = onExitFullScreen,
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.padding(SEVEN_DP)
|
||||
.minimumInteractiveComponentSize()
|
||||
.background(MaterialTheme.colorScheme.onSurface)
|
||||
) {
|
||||
Icon(
|
||||
painter = IconItem.Drawable(R.drawable.fullscreen_exit).toPainter(),
|
||||
contentDescription = stringResource(id = R.string.menu_exit_full_screen),
|
||||
tint = MaterialTheme.colorScheme.surface
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ShowZIMFileContent(state: ReaderScreenState) {
|
||||
state.selectedWebView?.let { selectedWebView ->
|
||||
@ -303,12 +340,12 @@ private fun TtsControls(state: ReaderScreenState) {
|
||||
@Composable
|
||||
private fun BackToTopFab(state: ReaderScreenState) {
|
||||
if (state.showBackToTopButton) {
|
||||
FloatingActionButton(
|
||||
SmallFloatingActionButton(
|
||||
onClick = state.backToTopButtonClick,
|
||||
modifier = Modifier,
|
||||
modifier = Modifier.padding(bottom = BACK_TO_TOP_BUTTON_BOTTOM_MARGIN),
|
||||
containerColor = MaterialTheme.colorScheme.primary,
|
||||
contentColor = MaterialTheme.colorScheme.onPrimary,
|
||||
shape = FloatingActionButtonDefaults.smallShape
|
||||
shape = CircleShape
|
||||
) {
|
||||
Icon(
|
||||
painter = Drawable(R.drawable.action_find_previous).toPainter(),
|
||||
@ -389,15 +426,26 @@ private fun BottomAppBarButtonIcon(
|
||||
shouldEnable: Boolean = true,
|
||||
contentDescription: String
|
||||
) {
|
||||
IconButton(
|
||||
onClick = onClick,
|
||||
modifier = Modifier.combinedClickable(onClick = onClick, onLongClick = onLongClick),
|
||||
enabled = shouldEnable
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(READER_BOTTOM_APP_BAR_BUTTON_ICON_SIZE + TEN_DP)
|
||||
.clip(CircleShape)
|
||||
.combinedClickable(
|
||||
onClick = onClick,
|
||||
onLongClick = onLongClick,
|
||||
enabled = shouldEnable
|
||||
),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Icon(
|
||||
buttonIcon.toPainter(),
|
||||
contentDescription,
|
||||
modifier = Modifier.size(READER_BOTTOM_APP_BAR_BUTTON_ICON_SIZE)
|
||||
modifier = Modifier.size(READER_BOTTOM_APP_BAR_BUTTON_ICON_SIZE),
|
||||
tint = if (shouldEnable) {
|
||||
LocalContentColor.current
|
||||
} else {
|
||||
LocalContentColor.current.copy(alpha = READER_BOTTOM_APP_BAR_DISABLE_BUTTON_ALPHA)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -504,6 +552,8 @@ private fun BoxScope.CloseAllTabButton(onCloseAllTabs: () -> Unit) {
|
||||
onCloseAllTabs()
|
||||
}
|
||||
),
|
||||
containerColor = DenimBlue800,
|
||||
contentColor = White
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(
|
||||
|
@ -56,13 +56,17 @@ data class ReaderScreenState(
|
||||
*/
|
||||
val shouldShowDonationPopup: Boolean,
|
||||
/**
|
||||
* Manages the showing of "Full screen view".
|
||||
* Manages the showing of "Full screen view" of webView's video.
|
||||
*
|
||||
* A [Pair] containing:
|
||||
* - [Boolean]: Whether to show/hide full screen mode.
|
||||
* - [ComposeView]: full screen view.
|
||||
*/
|
||||
val fullScreenItem: Pair<Boolean, ComposeView?>,
|
||||
/**
|
||||
* Manages the showing of "Full screen mode".
|
||||
*/
|
||||
val shouldShowFullScreenMode: Boolean,
|
||||
/**
|
||||
* Manages the showing of "BackToTop" fab button.
|
||||
*/
|
||||
@ -71,7 +75,6 @@ data class ReaderScreenState(
|
||||
* Handles the click of "BackToTop" fab button.
|
||||
*/
|
||||
val backToTopButtonClick: () -> Unit,
|
||||
val showFullscreenButton: Boolean = false,
|
||||
val onExitFullscreenClick: () -> Unit = {},
|
||||
val showTtsControls: Boolean = false,
|
||||
val onPauseTtsClick: () -> Unit = {},
|
||||
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Kiwix Android
|
||||
* Copyright (c) 2019 Kiwix <android.kiwix.org>
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package org.kiwix.kiwixmobile.core.utils
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.View
|
||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
import android.view.animation.LinearInterpolator
|
||||
import androidx.core.animation.addListener
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import org.kiwix.kiwixmobile.core.R
|
||||
import org.kiwix.kiwixmobile.core.extensions.setImageDrawableCompat
|
||||
|
||||
private const val HEIGHT_ANIM_DURATION = 100L
|
||||
private const val ROTATE_ANIM_DURATION = 200L
|
||||
private const val FULL_ROTATION = 360.0f
|
||||
|
||||
object AnimationUtils {
|
||||
@JvmStatic fun View.expand() {
|
||||
measure(MATCH_PARENT, WRAP_CONTENT)
|
||||
|
||||
// Older versions of android (pre API 21) cancel animations for views with a height of 0.
|
||||
layoutParams.height = 1
|
||||
visibility = View.VISIBLE
|
||||
|
||||
animateHeight(1, measuredHeight) {
|
||||
layoutParams.height = WRAP_CONTENT
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic fun View.collapse() {
|
||||
animateHeight(measuredHeight, 0) { visibility = View.GONE }
|
||||
}
|
||||
|
||||
@SuppressLint("Recycle")
|
||||
private fun View.animateHeight(start: Int, end: Int, onEndAction: () -> Unit) {
|
||||
ValueAnimator.ofInt(start, end).apply {
|
||||
addUpdateListener {
|
||||
layoutParams.height = it.animatedValue as Int
|
||||
requestLayout()
|
||||
}
|
||||
addListener(onEnd = { onEndAction.invoke() })
|
||||
duration = HEIGHT_ANIM_DURATION
|
||||
interpolator = LinearInterpolator()
|
||||
}.start()
|
||||
}
|
||||
|
||||
@JvmStatic fun FloatingActionButton.rotate() {
|
||||
animate().apply {
|
||||
withStartAction { setImageDrawableCompat(R.drawable.ic_close_black_24dp) }
|
||||
withEndAction { setImageDrawableCompat(R.drawable.ic_done_white_24dp) }
|
||||
rotationBy(FULL_ROTATION)
|
||||
duration = ROTATE_ANIM_DURATION
|
||||
}.start()
|
||||
}
|
||||
}
|
@ -48,6 +48,7 @@ object ComposeDimens {
|
||||
val TWELVE_DP = 12.dp
|
||||
val TEN_DP = 10.dp
|
||||
val EIGHT_DP = 8.dp
|
||||
val SEVEN_DP = 7.dp
|
||||
val SIX_DP = 6.dp
|
||||
val FIVE_DP = 5.dp
|
||||
val FOUR_DP = 4.dp
|
||||
@ -189,4 +190,6 @@ object ComposeDimens {
|
||||
const val TAB_SWITCHER_ICON_CORNER_RADIUS = 10
|
||||
val CLOSE_TAB_ICON_SIZE = 20.dp
|
||||
const val CLOSE_TAB_ICON_ANIMATION_TIMEOUT = 1200L
|
||||
val BACK_TO_TOP_BUTTON_BOTTOM_MARGIN = 80.dp
|
||||
const val READER_BOTTOM_APP_BAR_DISABLE_BUTTON_ALPHA = 0.38f
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user