mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 10:46:53 -04:00
Fixed: WebView was not occupying full height when the BottomAppBar was hidden.
* Moved the scrolling logic of the WebView into the Compose UI, as custom scroll handling in the WebView was causing issues. * Removed ToolbarScrollingKiwixWebView since it's no longer needed—scrolling is now managed entirely within Compose. * Added animations for opening and closing the tab switcher view.
This commit is contained in:
parent
3ebb37d5cc
commit
db22e245b7
@ -21,7 +21,6 @@ package org.kiwix.kiwixmobile.nav.destination.reader
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.AttributeSet
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.View
|
||||
@ -48,8 +47,6 @@ import org.kiwix.kiwixmobile.core.extensions.snack
|
||||
import org.kiwix.kiwixmobile.core.extensions.toast
|
||||
import org.kiwix.kiwixmobile.core.extensions.update
|
||||
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
|
||||
import org.kiwix.kiwixmobile.core.main.CoreWebViewClient
|
||||
import org.kiwix.kiwixmobile.core.main.ToolbarScrollingKiwixWebView
|
||||
import org.kiwix.kiwixmobile.core.main.reader.CoreReaderFragment
|
||||
import org.kiwix.kiwixmobile.core.main.reader.RestoreOrigin
|
||||
import org.kiwix.kiwixmobile.core.main.reader.RestoreOrigin.FromExternalLaunch
|
||||
@ -57,6 +54,7 @@ import org.kiwix.kiwixmobile.core.main.reader.RestoreOrigin.FromSearchScreen
|
||||
import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryItem
|
||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
|
||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource.Companion.fromDatabaseValue
|
||||
import org.kiwix.kiwixmobile.core.utils.DimenUtils.getToolbarHeight
|
||||
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
||||
import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_FILE
|
||||
import org.kiwix.kiwixmobile.core.utils.TAG_KIWIX
|
||||
@ -299,19 +297,14 @@ class KiwixReaderFragment : CoreReaderFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IllegalArgumentException::class)
|
||||
override fun createWebView(attrs: AttributeSet?): ToolbarScrollingKiwixWebView? {
|
||||
return ToolbarScrollingKiwixWebView(
|
||||
requireContext(),
|
||||
this,
|
||||
attrs ?: throw IllegalArgumentException("AttributeSet must not be null"),
|
||||
requireNotNull(readerScreenState.value.fullScreenItem.second),
|
||||
CoreWebViewClient(this, requireNotNull(zimReaderContainer)),
|
||||
onToolbarOffsetChanged = { offsetY -> toolbarOffsetY.value = offsetY },
|
||||
onBottomAppBarOffsetChanged = { bottomOffsetY -> bottomAppBarOffsetY.value = bottomOffsetY },
|
||||
sharedPreferenceUtil = requireNotNull(sharedPreferenceUtil),
|
||||
parentNavigationBar = requireActivity().findViewById(R.id.bottom_nav_view)
|
||||
)
|
||||
override fun updateNavigationBarHeight(toolbarOffset: Float) {
|
||||
// if no activity exist simply return.
|
||||
if (activity == null) return
|
||||
activity?.findViewById<BottomNavigationView>(R.id.bottom_nav_view)?.let { view ->
|
||||
val toolbarHeightPx = activity?.getToolbarHeight() ?: 0f
|
||||
val offsetFactor = view.height / toolbarHeightPx.toFloat()
|
||||
view.translationY = -1 * toolbarOffset * offsetFactor
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFullscreenVideoToggled(isFullScreen: Boolean) {
|
||||
|
@ -13,7 +13,7 @@
|
||||
<ID>LongParameterList:MainMenu.kt$MainMenu.Factory$( menu: Menu, webViews: MutableList<KiwixWebView>, urlIsValid: Boolean, menuClickListener: MenuClickListener, disableReadAloud: Boolean, disableTabs: Boolean )</ID>
|
||||
<ID>LongParameterList:PageTestHelpers.kt$( bookmarkTitle: String = "bookmarkTitle", isSelected: Boolean = false, id: Long = 2, zimId: String = "zimId", zimName: String = "zimName", zimFilePath: String = "zimFilePath", bookmarkUrl: String = "bookmarkUrl", favicon: String = "favicon" )</ID>
|
||||
<ID>LongParameterList:Repository.kt$Repository$( private val libkiwixBookOnDisk: LibkiwixBookOnDisk, private val libkiwixBookmarks: LibkiwixBookmarks, private val historyRoomDao: HistoryRoomDao, private val webViewHistoryRoomDao: WebViewHistoryRoomDao, private val notesRoomDao: NotesRoomDao, private val languageDao: NewLanguagesDao, private val recentSearchRoomDao: RecentSearchRoomDao, private val zimReaderContainer: ZimReaderContainer )</ID>
|
||||
<ID>LongParameterList:ToolbarScrollingKiwixWebView.kt$ToolbarScrollingKiwixWebView$( context: Context, callback: WebViewCallback, attrs: AttributeSet, videoView: ViewGroup?, webViewClient: CoreWebViewClient, private val onToolbarOffsetChanged: ((Float) -> Unit)? = null, private val onBottomAppBarOffsetChanged: ((Float) -> Unit)? = null, sharedPreferenceUtil: SharedPreferenceUtil, private val parentNavigationBar: View? = null )</ID>
|
||||
<ID>LongParameterList:ToolbarScrollingKiwixWebView.kt$ToolbarScrollingKiwixWebView$( context: Context, callback: WebViewCallback, attrs: AttributeSet, videoView: ViewGroup?, webViewClient: CoreWebViewClient, sharedPreferenceUtil: SharedPreferenceUtil )</ID>
|
||||
<ID>MagicNumber:ArticleCount.kt$ArticleCount$3</ID>
|
||||
<ID>MagicNumber:CompatFindActionModeCallback.kt$CompatFindActionModeCallback$100</ID>
|
||||
<ID>MagicNumber:DownloadItem.kt$DownloadItem$1000L</ID>
|
||||
|
@ -1,136 +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.main
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.COMPOSE_BOTTOM_APP_BAR_DEFAULT_HEIGHT
|
||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.COMPOSE_TOOLBAR_DEFAULT_HEIGHT
|
||||
import org.kiwix.kiwixmobile.core.utils.DimenUtils.dpToPx
|
||||
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
@Suppress("UnusedPrivateProperty")
|
||||
class ToolbarScrollingKiwixWebView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
callback: WebViewCallback,
|
||||
attrs: AttributeSet,
|
||||
videoView: ViewGroup?,
|
||||
webViewClient: CoreWebViewClient,
|
||||
private val onToolbarOffsetChanged: ((Float) -> Unit)? = null,
|
||||
private val onBottomAppBarOffsetChanged: ((Float) -> Unit)? = null,
|
||||
sharedPreferenceUtil: SharedPreferenceUtil,
|
||||
private val parentNavigationBar: View? = null
|
||||
) : KiwixWebView(
|
||||
context,
|
||||
callback,
|
||||
attrs,
|
||||
videoView,
|
||||
webViewClient,
|
||||
sharedPreferenceUtil
|
||||
) {
|
||||
private val toolbarHeight = context.dpToPx(COMPOSE_TOOLBAR_DEFAULT_HEIGHT)
|
||||
private val bottomAppBarHeightPx = context.dpToPx(COMPOSE_BOTTOM_APP_BAR_DEFAULT_HEIGHT)
|
||||
|
||||
private var startY = 0f
|
||||
private var currentOffset = 0f
|
||||
|
||||
init {
|
||||
fixInitalScrollingIssue()
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the internal offset of the WebView based on scroll delta.
|
||||
*
|
||||
* Positive scrollDelta = user scrolling down (hide UI)
|
||||
* Negative scrollDelta = user scrolling up (show UI)
|
||||
*/
|
||||
|
||||
private fun moveToolbar(scrollDelta: Int): Boolean {
|
||||
val newOffset = when {
|
||||
scrollDelta > 0 -> max(-toolbarHeight.toFloat(), currentOffset - scrollDelta)
|
||||
else -> min(0f, currentOffset - scrollDelta)
|
||||
}
|
||||
|
||||
if (newOffset != currentOffset) {
|
||||
currentOffset = newOffset
|
||||
notifyOffsetChanged(newOffset)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies Compose UI about toolbar offset.
|
||||
*/
|
||||
private fun notifyOffsetChanged(offset: Float) {
|
||||
onToolbarOffsetChanged?.invoke(offset)
|
||||
|
||||
// Compute offset for bottomAppBar using height ratio
|
||||
val bottomOffset = offset * -1 * (bottomAppBarHeightPx.toFloat() / toolbarHeight)
|
||||
onBottomAppBarOffsetChanged?.invoke(bottomOffset)
|
||||
|
||||
// Optional: Animate parent navigation bar (if still using it)
|
||||
parentNavigationBar?.let { view ->
|
||||
val offsetFactor = view.height / toolbarHeight.toFloat()
|
||||
view.translationY = offset * -1 * offsetFactor
|
||||
}
|
||||
|
||||
// Adjust WebView position to prevent layout jump
|
||||
this.translationY = offset
|
||||
}
|
||||
|
||||
/**
|
||||
* The webview needs to be scrolled with 0 to not be slightly hidden on startup.
|
||||
* See https://github.com/kiwix/kiwix-android/issues/2304 for issue description.
|
||||
*/
|
||||
private fun fixInitalScrollingIssue() {
|
||||
moveToolbar(0)
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||
if (sharedPreferenceUtil.prefFullScreen) return super.onTouchEvent(event)
|
||||
|
||||
when (event.actionMasked) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
startY = event.rawY
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
if (event.pointerCount == 1) {
|
||||
val diffY = (event.rawY - startY).toInt()
|
||||
startY = event.rawY
|
||||
if (moveToolbar(-diffY)) {
|
||||
event.offsetLocation(0f, -diffY.toFloat())
|
||||
return super.onTouchEvent(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.onTouchEvent(event)
|
||||
}
|
||||
}
|
@ -148,7 +148,6 @@ import org.kiwix.kiwixmobile.core.main.TableDrawerAdapter
|
||||
import org.kiwix.kiwixmobile.core.main.TableDrawerAdapter.DocumentSection
|
||||
import org.kiwix.kiwixmobile.core.main.TableDrawerAdapter.TableClickListener
|
||||
import org.kiwix.kiwixmobile.core.main.TabsAdapter
|
||||
import org.kiwix.kiwixmobile.core.main.ToolbarScrollingKiwixWebView
|
||||
import org.kiwix.kiwixmobile.core.main.UNINITIALISER_ADDRESS
|
||||
import org.kiwix.kiwixmobile.core.main.WebViewCallback
|
||||
import org.kiwix.kiwixmobile.core.main.WebViewProvider
|
||||
@ -226,9 +225,6 @@ abstract class CoreReaderFragment :
|
||||
|
||||
var drawerLayout: DrawerLayout? = null
|
||||
protected var tableDrawerRightContainer: NavigationView? = null
|
||||
|
||||
var contentFrame: FrameLayout? = null
|
||||
|
||||
var tabSwitcherRoot: View? = null
|
||||
|
||||
var activityMainRoot: View? = null
|
||||
@ -318,8 +314,6 @@ abstract class CoreReaderFragment :
|
||||
private var isReadSelection = false
|
||||
private var isReadAloudServiceRunning = false
|
||||
private var libkiwixBook: Book? = null
|
||||
val toolbarOffsetY = mutableStateOf(0f)
|
||||
val bottomAppBarOffsetY = mutableStateOf(0f)
|
||||
|
||||
protected var readerMenuState: ReaderMenuState? = null
|
||||
private var composeView: ComposeView? = null
|
||||
@ -502,6 +496,9 @@ abstract class CoreReaderFragment :
|
||||
ReaderScreen(
|
||||
state = readerScreenState.value,
|
||||
actionMenuItems = readerMenuState?.menuItems.orEmpty(),
|
||||
onBottomScrollOffsetChanged = { offset ->
|
||||
updateNavigationBarHeight(offset)
|
||||
},
|
||||
navigationIcon = {
|
||||
NavigationIcon(
|
||||
iconItem = navigationIcon(),
|
||||
@ -509,9 +506,7 @@ abstract class CoreReaderFragment :
|
||||
onClick = { navigationIconClick() },
|
||||
iconTint = navigationIconTint()
|
||||
)
|
||||
},
|
||||
toolbarOffsetY = toolbarOffsetY,
|
||||
bottomAppBarOffsetY = bottomAppBarOffsetY
|
||||
}
|
||||
)
|
||||
DialogHost(alertDialogShower as AlertDialogShower)
|
||||
}
|
||||
@ -615,6 +610,17 @@ abstract class CoreReaderFragment :
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is for hiding the KiwixMainActivity bottomNavigationView.
|
||||
* In custom apps we do not have the bottomnavigationView so that's why this method is empty here.
|
||||
*
|
||||
* See the implementation in KiwixReaderFragment.
|
||||
* TODO refactore this when migrating the KiwixMainActivity in compose.
|
||||
*/
|
||||
open fun updateNavigationBarHeight(toolbarOffset: Float) {
|
||||
// Do nothing since in custom apps we do not have the bottomNavigationView.
|
||||
}
|
||||
|
||||
private fun getVideoView() = context?.let {
|
||||
FrameLayout(it).apply {
|
||||
layoutParams = ViewGroup.LayoutParams(
|
||||
@ -698,7 +704,6 @@ abstract class CoreReaderFragment :
|
||||
fragmentReaderBinding?.let { readerBinding ->
|
||||
with(readerBinding.root) {
|
||||
activityMainRoot = findViewById(R.id.activity_main_root)
|
||||
contentFrame = findViewById(R.id.activity_main_content_frame)
|
||||
toolbar = findViewById(R.id.toolbar)
|
||||
tabSwitcherRoot = findViewById(R.id.activity_main_tab_switcher)
|
||||
tabRecyclerView = findViewById(R.id.tab_switcher_recycler_view)
|
||||
@ -921,29 +926,6 @@ abstract class CoreReaderFragment :
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a top margin to the web views.
|
||||
*
|
||||
* @param topMargin The top margin to be applied to the web views.
|
||||
* Use 0 to remove the margin.
|
||||
*/
|
||||
protected open fun setTopMarginToWebViews(topMargin: Int) {
|
||||
for (webView in webViewList) {
|
||||
if (webView.parent == null) {
|
||||
// Ensure that the web view has a parent before modifying its layout parameters
|
||||
// This check is necessary to prevent adding the margin when the web view is not attached to a layout
|
||||
// Adding the margin without a parent can cause unintended layout issues or empty
|
||||
// space on top of the webView in the tabs adapter.
|
||||
val frameLayout = FrameLayout(requireActivity())
|
||||
// Add the web view to the frame layout
|
||||
frameLayout.addView(webView)
|
||||
}
|
||||
val layoutParams = webView.layoutParams as FrameLayout.LayoutParams?
|
||||
layoutParams?.topMargin = topMargin
|
||||
webView.requestLayout()
|
||||
}
|
||||
}
|
||||
|
||||
protected fun startAnimation(
|
||||
view: View?,
|
||||
@AnimRes anim: Int
|
||||
@ -969,9 +951,6 @@ abstract class CoreReaderFragment :
|
||||
showSearchPlaceHolderInToolbar(false)
|
||||
readerMenuState?.showWebViewOptions(urlIsValid())
|
||||
selectTab(currentWebViewIndex)
|
||||
// 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 custom apps.
|
||||
// setTopMarginToWebViews(0)
|
||||
}
|
||||
|
||||
open fun setUpDrawerToggle() {
|
||||
@ -1360,7 +1339,6 @@ abstract class CoreReaderFragment :
|
||||
activityMainRoot = null
|
||||
tabRecyclerView = null
|
||||
tabSwitcherRoot = null
|
||||
contentFrame = null
|
||||
compatCallback?.finish()
|
||||
compatCallback = null
|
||||
toolbar?.setOnTouchListener(null)
|
||||
@ -1422,15 +1400,13 @@ abstract class CoreReaderFragment :
|
||||
}
|
||||
|
||||
@Throws(IllegalArgumentException::class)
|
||||
protected open fun createWebView(attrs: AttributeSet?): ToolbarScrollingKiwixWebView? {
|
||||
return ToolbarScrollingKiwixWebView(
|
||||
protected open fun createWebView(attrs: AttributeSet?): KiwixWebView? {
|
||||
return KiwixWebView(
|
||||
requireContext(),
|
||||
this,
|
||||
attrs ?: throw IllegalArgumentException("AttributeSet must not be null"),
|
||||
requireNotNull(readerScreenState.value.fullScreenItem.second),
|
||||
CoreWebViewClient(this, requireNotNull(zimReaderContainer)),
|
||||
onToolbarOffsetChanged = { offsetY -> toolbarOffsetY.value = offsetY },
|
||||
onBottomAppBarOffsetChanged = { bottomOffsetY -> bottomAppBarOffsetY.value = bottomOffsetY },
|
||||
requireNotNull(sharedPreferenceUtil)
|
||||
)
|
||||
}
|
||||
@ -1505,7 +1481,6 @@ abstract class CoreReaderFragment :
|
||||
|
||||
private fun reopenBook() {
|
||||
hideNoBookOpenViews()
|
||||
contentFrame?.visibility = VISIBLE
|
||||
readerMenuState?.showBookSpecificMenuItems()
|
||||
}
|
||||
|
||||
@ -1517,7 +1492,6 @@ abstract class CoreReaderFragment :
|
||||
readerScreenTitle = context?.getString(R.string.reader).orEmpty()
|
||||
)
|
||||
}
|
||||
contentFrame?.visibility = GONE
|
||||
hideProgressBar()
|
||||
readerMenuState?.hideBookSpecificMenuItems()
|
||||
if (shouldCloseZimBook) {
|
||||
@ -1796,16 +1770,16 @@ abstract class CoreReaderFragment :
|
||||
setUpDrawerToggle()
|
||||
setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
|
||||
sharedPreferenceUtil?.putPrefFullScreen(false)
|
||||
updateBottomToolbarVisibility()
|
||||
val window = requireActivity().window
|
||||
window.decorView.closeFullScreenMode(window)
|
||||
getCurrentWebView()?.requestLayout()
|
||||
readerScreenState.update {
|
||||
copy(
|
||||
shouldShowBottomAppBar = true,
|
||||
shouldShowFullScreenMode = false
|
||||
)
|
||||
}
|
||||
updateBottomToolbarVisibility()
|
||||
val window = requireActivity().window
|
||||
window.decorView.closeFullScreenMode(window)
|
||||
getCurrentWebView()?.requestLayout()
|
||||
}
|
||||
|
||||
override fun openExternalUrl(intent: Intent) {
|
||||
|
@ -22,9 +22,14 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||
import android.widget.FrameLayout
|
||||
import androidx.compose.animation.core.animateDpAsState
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
@ -37,11 +42,9 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.systemBarsPadding
|
||||
@ -56,6 +59,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.BottomAppBar
|
||||
import androidx.compose.material3.BottomAppBarDefaults
|
||||
import androidx.compose.material3.BottomAppBarScrollBehavior
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
@ -97,9 +101,9 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.compose.ui.zIndex
|
||||
import kotlinx.coroutines.delay
|
||||
import org.kiwix.kiwixmobile.core.R
|
||||
import org.kiwix.kiwixmobile.core.downloader.downloadManager.HUNDERED
|
||||
@ -149,12 +153,15 @@ const val CONTENT_LOADING_PROGRESSBAR_TESTING_TAG = "contentLoadingProgressBarTe
|
||||
fun ReaderScreen(
|
||||
state: ReaderScreenState,
|
||||
actionMenuItems: List<ActionMenuItem>,
|
||||
toolbarOffsetY: MutableState<Float>,
|
||||
bottomAppBarOffsetY: MutableState<Float>,
|
||||
onBottomScrollOffsetChanged: (Float) -> Unit,
|
||||
navigationIcon: @Composable () -> Unit
|
||||
) {
|
||||
val bottomNavHeightInDp = with(LocalDensity.current) { state.bottomNavigationHeight.toDp() }
|
||||
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
||||
val bottomAppBarScrollBehavior = BottomAppBarDefaults.exitAlwaysScrollBehavior()
|
||||
LaunchedEffect(bottomAppBarScrollBehavior.state.heightOffset) {
|
||||
onBottomScrollOffsetChanged(scrollBehavior.state.heightOffset)
|
||||
}
|
||||
KiwixDialogTheme {
|
||||
Scaffold(
|
||||
snackbarHost = { KiwixSnackbarHost(snackbarHostState = state.snackBarHostState) },
|
||||
@ -162,7 +169,6 @@ fun ReaderScreen(
|
||||
ReaderTopBar(
|
||||
state,
|
||||
actionMenuItems,
|
||||
toolbarOffsetY,
|
||||
scrollBehavior,
|
||||
navigationIcon
|
||||
)
|
||||
@ -171,12 +177,13 @@ fun ReaderScreen(
|
||||
modifier = Modifier
|
||||
.systemBarsPadding()
|
||||
.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||
.nestedScroll(bottomAppBarScrollBehavior.nestedScrollConnection)
|
||||
.padding(bottom = bottomNavHeightInDp)
|
||||
) { paddingValues ->
|
||||
ReaderContentLayout(
|
||||
state,
|
||||
Modifier.padding(paddingValues),
|
||||
bottomAppBarOffsetY
|
||||
bottomAppBarScrollBehavior
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -188,69 +195,87 @@ fun ReaderScreen(
|
||||
private fun ReaderTopBar(
|
||||
state: ReaderScreenState,
|
||||
actionMenuItems: List<ActionMenuItem>,
|
||||
toolbarOffsetY: MutableState<Float>,
|
||||
scrollBehavior: TopAppBarScrollBehavior,
|
||||
navigationIcon: @Composable () -> Unit,
|
||||
) {
|
||||
if (!state.shouldShowFullScreenMode && !state.fullScreenItem.first) {
|
||||
val animatedOffsetY by animateDpAsState(
|
||||
targetValue = with(LocalDensity.current) { toolbarOffsetY.value.toDp() },
|
||||
label = "ToolbarScrollOffset"
|
||||
)
|
||||
KiwixAppBar(
|
||||
title = if (state.showTabSwitcher) "" else state.readerScreenTitle,
|
||||
navigationIcon = navigationIcon,
|
||||
actionMenuItems = actionMenuItems,
|
||||
topAppBarScrollBehavior = scrollBehavior,
|
||||
searchBar =
|
||||
searchPlaceHolderIfActive(state.searchPlaceHolderItemForCustomApps),
|
||||
modifier = Modifier.offset { IntOffset(x = ZERO, y = animatedOffsetY.roundToPx()) }
|
||||
searchPlaceHolderIfActive(state.searchPlaceHolderItemForCustomApps)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun ReaderContentLayout(
|
||||
state: ReaderScreenState,
|
||||
modifier: Modifier = Modifier,
|
||||
bottomAppBarOffsetY: MutableState<Float>
|
||||
bottomAppBarScrollBehavior: BottomAppBarScrollBehavior
|
||||
) {
|
||||
Box(modifier = modifier.fillMaxSize()) {
|
||||
when {
|
||||
state.showTabSwitcher -> TabSwitcherView(
|
||||
state.kiwixWebViewList,
|
||||
state.currentWebViewPosition,
|
||||
state.onTabClickListener,
|
||||
state.onCloseAllTabs,
|
||||
state.darkModeViewPainter
|
||||
)
|
||||
TabSwitcherAnimated(state)
|
||||
if (!state.showTabSwitcher) {
|
||||
when {
|
||||
state.isNoBookOpenInReader -> NoBookOpenView(state.onOpenLibraryButtonClicked)
|
||||
state.fullScreenItem.first -> ShowFullScreenView(state)
|
||||
|
||||
state.isNoBookOpenInReader -> NoBookOpenView(state.onOpenLibraryButtonClicked)
|
||||
state.fullScreenItem.first -> ShowFullScreenView(state)
|
||||
|
||||
else -> {
|
||||
ShowZIMFileContent(state, bottomAppBarOffsetY)
|
||||
ShowProgressBarIfZIMFilePageIsLoading(state)
|
||||
Column(Modifier.align(Alignment.BottomCenter)) {
|
||||
TtsControls(state)
|
||||
BottomAppBarOfReaderScreen(
|
||||
state.bookmarkButtonItem,
|
||||
state.previousPageButtonItem,
|
||||
state.onHomeButtonClick,
|
||||
state.nextPageButtonItem,
|
||||
state.tocButtonItem,
|
||||
state.shouldShowBottomAppBar,
|
||||
bottomAppBarOffsetY
|
||||
else -> {
|
||||
ShowZIMFileContent(state)
|
||||
ShowProgressBarIfZIMFilePageIsLoading(state)
|
||||
Column(Modifier.align(Alignment.BottomCenter)) {
|
||||
TtsControls(state)
|
||||
BottomAppBarOfReaderScreen(
|
||||
state.bookmarkButtonItem,
|
||||
state.previousPageButtonItem,
|
||||
state.onHomeButtonClick,
|
||||
state.nextPageButtonItem,
|
||||
state.tocButtonItem,
|
||||
state.shouldShowBottomAppBar,
|
||||
bottomAppBarScrollBehavior
|
||||
)
|
||||
}
|
||||
CloseFullScreenImageButton(
|
||||
state.shouldShowFullScreenMode,
|
||||
state.onExitFullscreenClick
|
||||
)
|
||||
}
|
||||
CloseFullScreenImageButton(
|
||||
state.shouldShowFullScreenMode,
|
||||
state.onExitFullscreenClick
|
||||
)
|
||||
}
|
||||
ShowDonationLayout(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShowDonationLayout(state)
|
||||
@Composable
|
||||
private fun TabSwitcherAnimated(state: ReaderScreenState) {
|
||||
val transitionSpec = remember {
|
||||
slideInVertically(
|
||||
initialOffsetY = { -it },
|
||||
animationSpec = tween(durationMillis = 300)
|
||||
) + fadeIn() togetherWith
|
||||
slideOutVertically(
|
||||
targetOffsetY = { -it },
|
||||
animationSpec = tween(durationMillis = 300)
|
||||
) + fadeOut()
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = state.showTabSwitcher,
|
||||
enter = transitionSpec.targetContentEnter,
|
||||
exit = transitionSpec.initialContentExit,
|
||||
modifier = Modifier.zIndex(1f),
|
||||
) {
|
||||
TabSwitcherView(
|
||||
state.kiwixWebViewList,
|
||||
state.currentWebViewPosition,
|
||||
state.onTabClickListener,
|
||||
state.onCloseAllTabs,
|
||||
state.darkModeViewPainter
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -325,15 +350,7 @@ private fun BoxScope.CloseFullScreenImageButton(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ShowZIMFileContent(
|
||||
state: ReaderScreenState,
|
||||
bottomAppBarOffsetY: MutableState<Float>
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
|
||||
val bottomNavHeightDp = with(density) { state.bottomNavigationHeight.toDp() }
|
||||
val bottomAppBarOffsetDp = with(density) { -bottomAppBarOffsetY.value.toDp() }
|
||||
val totalBottomPadding = (bottomNavHeightDp + bottomAppBarOffsetDp).coerceAtLeast(ZERO.dp)
|
||||
private fun ShowZIMFileContent(state: ReaderScreenState) {
|
||||
state.selectedWebView?.let { selectedWebView ->
|
||||
key(selectedWebView) {
|
||||
AndroidView(
|
||||
@ -346,10 +363,10 @@ private fun ShowZIMFileContent(
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight()
|
||||
.padding(bottom = totalBottomPadding)
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
)
|
||||
// TODO handle the unnecessary vertical scroll when webView page chnaged.
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -458,18 +475,13 @@ private fun BottomAppBarOfReaderScreen(
|
||||
nextPageButtonItem: Triple<() -> Unit, () -> Unit, Boolean>,
|
||||
tocButtonItem: Pair<Boolean, () -> Unit>,
|
||||
shouldShowBottomAppBar: Boolean,
|
||||
bottomAppBarOffsetY: MutableState<Float>
|
||||
bottomAppBarScrollBehavior: BottomAppBarScrollBehavior
|
||||
) {
|
||||
if (!shouldShowBottomAppBar) return
|
||||
val animatedOffsetY by animateDpAsState(
|
||||
targetValue = with(LocalDensity.current) { bottomAppBarOffsetY.value.toDp() },
|
||||
label = "BottomAppBarOffset"
|
||||
)
|
||||
BottomAppBar(
|
||||
containerColor = Black,
|
||||
contentColor = White,
|
||||
scrollBehavior = BottomAppBarDefaults.exitAlwaysScrollBehavior(),
|
||||
modifier = Modifier.offset { IntOffset(ZERO, animatedOffsetY.roundToPx()) }
|
||||
scrollBehavior = bottomAppBarScrollBehavior,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
|
Loading…
x
Reference in New Issue
Block a user