diff --git a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/reader/KiwixReaderFragment.kt b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/reader/KiwixReaderFragment.kt index 4fc78a366..8b65c91fe 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/reader/KiwixReaderFragment.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/reader/KiwixReaderFragment.kt @@ -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(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) { diff --git a/core/detekt_baseline.xml b/core/detekt_baseline.xml index 242b89aab..d2e3edb2c 100644 --- a/core/detekt_baseline.xml +++ b/core/detekt_baseline.xml @@ -13,7 +13,7 @@ LongParameterList:MainMenu.kt$MainMenu.Factory$( menu: Menu, webViews: MutableList<KiwixWebView>, urlIsValid: Boolean, menuClickListener: MenuClickListener, disableReadAloud: Boolean, disableTabs: Boolean ) 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" ) 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 ) - 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 ) + LongParameterList:ToolbarScrollingKiwixWebView.kt$ToolbarScrollingKiwixWebView$( context: Context, callback: WebViewCallback, attrs: AttributeSet, videoView: ViewGroup?, webViewClient: CoreWebViewClient, sharedPreferenceUtil: SharedPreferenceUtil ) MagicNumber:ArticleCount.kt$ArticleCount$3 MagicNumber:CompatFindActionModeCallback.kt$CompatFindActionModeCallback$100 MagicNumber:DownloadItem.kt$DownloadItem$1000L diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/ToolbarScrollingKiwixWebView.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/ToolbarScrollingKiwixWebView.kt deleted file mode 100644 index 9241b146e..000000000 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/ToolbarScrollingKiwixWebView.kt +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Kiwix Android - * Copyright (c) 2019 Kiwix - * 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 . - * - */ -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) - } -} diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/CoreReaderFragment.kt index 5357476d4..8de176eb1 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/CoreReaderFragment.kt @@ -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) { diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/ReaderScreen.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/ReaderScreen.kt index 916cb0bef..9a9f01f8b 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/ReaderScreen.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/ReaderScreen.kt @@ -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, - toolbarOffsetY: MutableState, - bottomAppBarOffsetY: MutableState, + 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, - toolbarOffsetY: MutableState, 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 + 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 -) { - 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 Unit>, shouldShowBottomAppBar: Boolean, - bottomAppBarOffsetY: MutableState + 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