diff --git a/app/src/main/java/org/kiwix/kiwixmobile/language/LanguageScreen.kt b/app/src/main/java/org/kiwix/kiwixmobile/language/LanguageScreen.kt index 53ed73476..4ee833537 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/language/LanguageScreen.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/language/LanguageScreen.kt @@ -36,6 +36,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.extensions.CollectSideEffectWithActivity @@ -70,7 +71,7 @@ fun LanguageScreen( } Scaffold(topBar = { KiwixAppBar( - titleId = R.string.select_languages, + title = stringResource(R.string.select_languages), navigationIcon = navigationIcon, actionMenuItems = actionMenuItemList, searchBar = if (isSearchActive) { diff --git a/app/src/main/java/org/kiwix/kiwixmobile/localFileTransfer/LocalFileTransferScreen.kt b/app/src/main/java/org/kiwix/kiwixmobile/localFileTransfer/LocalFileTransferScreen.kt index c678d57a7..bd160497e 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/localFileTransfer/LocalFileTransferScreen.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/localFileTransfer/LocalFileTransferScreen.kt @@ -113,7 +113,7 @@ fun LocalFileTransferScreen( Scaffold( topBar = { KiwixAppBar( - titleId = toolbarTitle, + title = stringResource(toolbarTitle), actionMenuItems = actionMenuItems.map { it.copy( modifier = diff --git a/app/src/main/java/org/kiwix/kiwixmobile/main/KiwixMainActivity.kt b/app/src/main/java/org/kiwix/kiwixmobile/main/KiwixMainActivity.kt index 81b6bf987..f052e8c3e 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/main/KiwixMainActivity.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/main/KiwixMainActivity.kt @@ -233,7 +233,7 @@ class KiwixMainActivity : CoreMainActivity() { * * TODO Remove this once we migrate to compose. */ - fun toggleBottomNavigation(isVisible: Boolean) { + override fun toggleBottomNavigation(isVisible: Boolean) { activityKiwixMainBinding.bottomNavView.animate() ?.translationY( if (isVisible) { diff --git a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/local/LocalLibraryScreen.kt b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/local/LocalLibraryScreen.kt index 4768d6877..07f2e58f7 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/local/LocalLibraryScreen.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/local/LocalLibraryScreen.kt @@ -38,32 +38,24 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp import org.kiwix.kiwixmobile.R.string import org.kiwix.kiwixmobile.core.R -import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO import org.kiwix.kiwixmobile.core.main.reader.CONTENT_LOADING_PROGRESSBAR_TESTING_TAG +import org.kiwix.kiwixmobile.core.main.reader.rememberScrollBehavior import org.kiwix.kiwixmobile.core.ui.components.ContentLoadingProgressBar import org.kiwix.kiwixmobile.core.ui.components.KiwixAppBar import org.kiwix.kiwixmobile.core.ui.components.KiwixButton import org.kiwix.kiwixmobile.core.ui.components.KiwixSnackbarHost import org.kiwix.kiwixmobile.core.ui.components.ProgressBarStyle -import org.kiwix.kiwixmobile.core.ui.components.ScrollDirection import org.kiwix.kiwixmobile.core.ui.components.SwipeRefreshLayout -import org.kiwix.kiwixmobile.core.ui.components.rememberLazyListScrollListener import org.kiwix.kiwixmobile.core.ui.theme.Black import org.kiwix.kiwixmobile.core.ui.theme.KiwixTheme import org.kiwix.kiwixmobile.core.ui.theme.White @@ -102,7 +94,12 @@ fun LocalLibraryScreen( Scaffold( snackbarHost = { KiwixSnackbarHost(snackbarHostState = state.snackBarHostState) }, topBar = { - KiwixAppBar(R.string.library, navigationIcon, state.actionMenuItems, scrollBehavior) + KiwixAppBar( + stringResource(R.string.library), + navigationIcon, + state.actionMenuItems, + scrollBehavior + ) }, floatingActionButton = { SelectFileButton(fabButtonClick) }, modifier = Modifier @@ -141,33 +138,6 @@ fun LocalLibraryScreen( } } -@Composable -fun rememberScrollBehavior( - bottomNavigationHeight: Int, - listState: LazyListState, -): Pair, LazyListState> { - val bottomNavHeightInDp = with(LocalDensity.current) { bottomNavigationHeight.toDp() } - val bottomNavHeight = remember { mutableStateOf(bottomNavHeightInDp) } - val lazyListState = rememberLazyListScrollListener( - lazyListState = listState, - onScrollChanged = { direction -> - when (direction) { - ScrollDirection.SCROLL_UP -> { - bottomNavHeight.value = bottomNavHeightInDp - } - - ScrollDirection.SCROLL_DOWN -> { - bottomNavHeight.value = ZERO.dp - } - - ScrollDirection.IDLE -> {} - } - } - ) - - return bottomNavHeight to lazyListState -} - @Composable private fun BookItemList( state: FileSelectListState, diff --git a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/online/OnlineLibraryScreen.kt b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/online/OnlineLibraryScreen.kt index 2ffd3c68a..bc214225c 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/online/OnlineLibraryScreen.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/online/OnlineLibraryScreen.kt @@ -53,6 +53,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import org.kiwix.kiwixmobile.core.R.string import org.kiwix.kiwixmobile.core.extensions.hideKeyboardOnLazyColumnScroll +import org.kiwix.kiwixmobile.core.main.reader.rememberScrollBehavior import org.kiwix.kiwixmobile.core.ui.components.ContentLoadingProgressBar import org.kiwix.kiwixmobile.core.ui.components.KiwixAppBar import org.kiwix.kiwixmobile.core.ui.components.KiwixSearchView @@ -72,7 +73,6 @@ import org.kiwix.kiwixmobile.core.utils.ComposeDimens.FOUR_DP import org.kiwix.kiwixmobile.core.utils.ComposeDimens.SIXTEEN_DP import org.kiwix.kiwixmobile.core.utils.ComposeDimens.SIX_DP import org.kiwix.kiwixmobile.core.utils.ComposeDimens.THREE_DP -import org.kiwix.kiwixmobile.nav.destination.library.local.rememberScrollBehavior import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryListItem import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryListItem.DividerItem @@ -100,7 +100,7 @@ fun OnlineLibraryScreen( snackbarHost = { KiwixSnackbarHost(snackbarHostState = state.snackBarHostState) }, topBar = { KiwixAppBar( - string.download, + stringResource(string.download), navigationIcon, actionMenuItems, scrollBehavior, 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 0fe52e5dc..089ffe209 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 @@ -27,11 +27,11 @@ import android.view.MenuInflater import android.view.View import android.view.View.GONE import android.view.View.VISIBLE -import android.view.ViewGroup 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 @@ -51,12 +51,12 @@ 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.reader.CoreReaderFragment 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 import org.kiwix.kiwixmobile.core.main.reader.RestoreOrigin.FromSearchScreen -import org.kiwix.kiwixmobile.core.main.ToolbarScrollingKiwixWebView 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 @@ -253,6 +253,9 @@ class KiwixReaderFragment : CoreReaderFragment() { exitBook() } + override fun getBottomNavigationView(): BottomNavigationView? = + requireActivity().findViewById(R.id.bottom_nav_view) + /** * Restores the view state based on the provided webViewHistoryItemList data and restore origin. * @@ -291,7 +294,10 @@ class KiwixReaderFragment : CoreReaderFragment() { } restoreTabs(webViewHistoryItemList, currentTab, onComplete) } else { - getCurrentWebView()?.snack(string.zim_not_opened) + readerScreenState.value.snackBarHostState.snack( + requireActivity().getString(string.zim_not_opened), + lifecycleScope = lifecycleScope + ) exitBook() // hide the options for zim file to avoid unexpected UI behavior } } @@ -305,16 +311,17 @@ class KiwixReaderFragment : CoreReaderFragment() { @Throws(IllegalArgumentException::class) override fun createWebView(attrs: AttributeSet?): ToolbarScrollingKiwixWebView? { - requireNotNull(activityMainRoot) + // requireNotNull(activityMainRoot) return ToolbarScrollingKiwixWebView( requireContext(), this, attrs ?: throw IllegalArgumentException("AttributeSet must not be null"), - activityMainRoot as ViewGroup, - requireNotNull(videoView), + null, + // requireNotNull(videoView), + null, CoreWebViewClient(this, requireNotNull(zimReaderContainer)), - requireNotNull(toolbarContainer), - requireNotNull(bottomToolbar), + // requireNotNull(toolbarContainer), + // requireNotNull(bottomToolbar), sharedPreferenceUtil = requireNotNull(sharedPreferenceUtil), parentNavigationBar = requireActivity().findViewById(R.id.bottom_nav_view) ) diff --git a/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostScreen.kt b/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostScreen.kt index 13cddcf0f..e5c382bb5 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostScreen.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/webserver/ZimHostScreen.kt @@ -87,7 +87,7 @@ fun ZimHostScreen( ) { KiwixTheme { Scaffold(topBar = { - KiwixAppBar(R.string.menu_wifi_hotspot, navigationIcon) + KiwixAppBar(stringResource(R.string.menu_wifi_hotspot), navigationIcon) }) { contentPadding -> Column(modifier = Modifier.fillMaxSize().padding(contentPadding)) { Row( diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/SnackbarHostStateExtension.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/SnackbarHostStateExtension.kt index 2cc75c3c7..1aea36f41 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/SnackbarHostStateExtension.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/SnackbarHostStateExtension.kt @@ -30,7 +30,8 @@ fun SnackbarHostState.snack( actionClick: (() -> Unit)? = null, // Default duration is 4 seconds. snackbarDuration: SnackbarDuration = SnackbarDuration.Short, - lifecycleScope: CoroutineScope + lifecycleScope: CoroutineScope, + snackBarResult: (SnackbarResult) -> Unit = {} ) { lifecycleScope.launch { val result = showSnackbar( @@ -41,5 +42,6 @@ fun SnackbarHostState.snack( if (result == SnackbarResult.ActionPerformed) { actionClick?.invoke() } + snackBarResult.invoke(result) } } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/help/HelpScreen.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/help/HelpScreen.kt index 0b06bde81..e470e6659 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/help/HelpScreen.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/help/HelpScreen.kt @@ -73,7 +73,7 @@ fun HelpScreen( KiwixTheme { Scaffold( topBar = { - KiwixAppBar(R.string.menu_help, navigationIcon) + KiwixAppBar(stringResource(R.string.menu_help), navigationIcon) } ) { innerPadding -> Column(modifier = Modifier.padding(innerPadding)) { diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/AddNoteDialogScreen.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/AddNoteDialogScreen.kt index 5772c6711..12ab84867 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/AddNoteDialogScreen.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/AddNoteDialogScreen.kt @@ -72,7 +72,7 @@ fun AddNoteDialogScreen( KiwixDialogTheme { Scaffold( snackbarHost = { KiwixSnackbarHost(snackbarHostState = snackBarHostState) }, - topBar = { KiwixAppBar(R.string.note, navigationIcon, actionMenuItems) } + topBar = { KiwixAppBar(stringResource(R.string.note), navigationIcon, actionMenuItems) } ) { paddingValues -> Column( modifier = Modifier diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreMainActivity.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreMainActivity.kt index cc100dc1c..e4071e546 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreMainActivity.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreMainActivity.kt @@ -495,4 +495,14 @@ abstract class CoreMainActivity : BaseActivity(), WebViewProvider { abstract val readerFragmentResId: Int abstract fun createApplicationShortcuts() abstract fun setDialogHostToActivity(alertDialogShower: AlertDialogShower) + + /** + * This is for showing and hiding the bottomNavigationView when user scroll the screen. + * We are making this abstract so that it can be easily used from the reader screen. + * Since we do not have the bottomNavigationView in custom apps. So doing this way both apps will + * provide there own implementation. + * + * TODO we will remove this once we will migrate mainActivity to the compose. + */ + abstract fun toggleBottomNavigation(isVisible: Boolean) } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/KiwixWebView.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/KiwixWebView.kt index 4e5f56531..e2eadce87 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/KiwixWebView.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/KiwixWebView.kt @@ -60,7 +60,7 @@ open class KiwixWebView @SuppressLint("SetJavaScriptEnabled") constructor( private val callback: WebViewCallback, attrs: AttributeSet, private var nonVideoView: ViewGroup?, - videoView: ViewGroup, + videoView: ViewGroup?, private val webViewClient: CoreWebViewClient, val sharedPreferenceUtil: SharedPreferenceUtil ) : VideoEnabledWebView(context, attrs) { 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 index 2e24a9da5..c67f97a0e 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/ToolbarScrollingKiwixWebView.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/ToolbarScrollingKiwixWebView.kt @@ -25,19 +25,16 @@ import android.view.View import android.view.ViewGroup import org.kiwix.kiwixmobile.core.utils.DimenUtils.getToolbarHeight 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, - nonVideoView: ViewGroup, - videoView: ViewGroup, + nonVideoView: ViewGroup?, + videoView: ViewGroup?, webViewClient: CoreWebViewClient, - private val toolbarView: View, - private val bottomBarView: View, sharedPreferenceUtil: SharedPreferenceUtil, private val parentNavigationBar: View? = null ) : KiwixWebView( @@ -65,58 +62,60 @@ class ToolbarScrollingKiwixWebView @JvmOverloads constructor( moveToolbar(0) } + @Suppress("FunctionOnlyReturningConstant", "UnusedParameter") private fun moveToolbar(scrollDelta: Int): Boolean { - val originalTranslation = toolbarView.translationY - val newTranslation = - if (scrollDelta > 0) { - // scroll down - max(-toolbarHeight.toFloat(), originalTranslation - scrollDelta) - } else { - // scroll up - min(0f, originalTranslation - scrollDelta) - } - - toolbarView.translationY = newTranslation - bottomBarView.translationY = - newTranslation * -1 * (bottomBarView.height / toolbarHeight.toFloat()) - parentNavigationBar?.let { - it.translationY = newTranslation * -1 * (it.height / toolbarHeight.toFloat()) - } - this.translationY = newTranslation + toolbarHeight - return toolbarHeight + newTranslation != 0f && newTranslation != 0f + // val originalTranslation = toolbarView.translationY + // val newTranslation = + // if (scrollDelta > 0) { + // // scroll down + // max(-toolbarHeight.toFloat(), originalTranslation - scrollDelta) + // } else { + // // scroll up + // min(0f, originalTranslation - scrollDelta) + // } + // + // toolbarView.translationY = newTranslation + // bottomBarView.translationY = + // newTranslation * -1 * (bottomBarView.height / toolbarHeight.toFloat()) + // parentNavigationBar?.let { + // it.translationY = newTranslation * -1 * (it.height / toolbarHeight.toFloat()) + // } + // this.translationY = newTranslation + toolbarHeight + // return toolbarHeight + newTranslation != 0f && newTranslation != 0f + return false } @SuppressLint("ClickableViewAccessibility") override fun onTouchEvent(event: MotionEvent): Boolean { - val transY = toolbarView.translationY.toInt() - when (event.actionMasked) { - MotionEvent.ACTION_DOWN -> startY = event.rawY - MotionEvent.ACTION_MOVE -> { - // If we are in fullscreen don't scroll bar - if (sharedPreferenceUtil.prefFullScreen) { - return super.onTouchEvent(event) - } - // Filter out zooms since we don't want to affect the toolbar when zooming - 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) - } - } - } - // If the toolbar is half-visible, - // either open or close it entirely depending on how far it is visible - MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> - if (transY != 0 && transY > -toolbarHeight) { - if (transY > -toolbarHeight / 2) { - ensureToolbarDisplayed() - } else { - ensureToolbarHidden() - } - } - } + // val transY = toolbarView.translationY.toInt() + // when (event.actionMasked) { + // MotionEvent.ACTION_DOWN -> startY = event.rawY + // MotionEvent.ACTION_MOVE -> { + // // If we are in fullscreen don't scroll bar + // if (sharedPreferenceUtil.prefFullScreen) { + // return super.onTouchEvent(event) + // } + // // Filter out zooms since we don't want to affect the toolbar when zooming + // 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) + // } + // } + // } + // // If the toolbar is half-visible, + // // either open or close it entirely depending on how far it is visible + // MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> + // if (transY != 0 && transY > -toolbarHeight) { + // if (transY > -toolbarHeight / 2) { + // ensureToolbarDisplayed() + // } else { + // ensureToolbarHidden() + // } + // } + // } 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 ab8255bbf..d06897d1d 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 @@ -44,8 +44,6 @@ import android.view.Gravity.BOTTOM import android.view.Gravity.CENTER_HORIZONTAL import android.view.LayoutInflater import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem import android.view.MotionEvent import android.view.View import android.view.View.GONE @@ -67,27 +65,28 @@ import androidx.annotation.AnimRes import androidx.appcompat.app.ActionBar import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Menu +import androidx.compose.material3.SnackbarDuration import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.SnackbarResult +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.platform.ComposeView import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.Group -import androidx.coordinatorlayout.widget.CoordinatorLayout 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.MenuHost -import androidx.core.view.MenuProvider 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.Lifecycle import androidx.lifecycle.Observer import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.ItemTouchHelper @@ -96,9 +95,9 @@ 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 com.google.android.material.snackbar.Snackbar import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -151,7 +150,6 @@ import org.kiwix.kiwixmobile.core.main.KiwixTextToSpeech.OnInitSucceedListener import org.kiwix.kiwixmobile.core.main.KiwixTextToSpeech.OnSpeakingListener import org.kiwix.kiwixmobile.core.main.KiwixWebView import org.kiwix.kiwixmobile.core.main.MainMenu -import org.kiwix.kiwixmobile.core.main.MainMenu.MenuClickListener import org.kiwix.kiwixmobile.core.main.MainRepositoryActions import org.kiwix.kiwixmobile.core.main.OnSwipeTouchListener import org.kiwix.kiwixmobile.core.main.ServiceWorkerUninitialiser @@ -181,6 +179,7 @@ import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer import org.kiwix.kiwixmobile.core.reader.ZimReaderSource 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.getToolbarHeight @@ -224,13 +223,13 @@ const val SEARCH_ITEM_TITLE_KEY = "searchItemTitle" abstract class CoreReaderFragment : BaseFragment(), WebViewCallback, - MenuClickListener, + ReaderMenuState.MenuClickListener, FragmentActivityExtensions, WebViewProvider, ReadAloudCallbacks, NavigationHistoryClickListener, ShowDonationDialogCallback { - protected val webViewList: MutableList = ArrayList() + protected val webViewList = mutableStateListOf() private val webUrlsFlow = MutableStateFlow("") private var fragmentReaderBinding: FragmentReaderBinding? = null @@ -317,8 +316,6 @@ abstract class CoreReaderFragment : private var tabRecyclerView: RecyclerView? = null - private var snackBarRoot: CoordinatorLayout? = null - private var noOpenBookText: TextView? = null private var bottomToolbarToc: ImageView? = null @@ -395,11 +392,15 @@ abstract class CoreReaderFragment : { goToBookmarks() }, IconItem.Drawable(R.drawable.ic_bookmark_border_24dp) ), - previousPageButtonItem = { goBack() } to { showBackwardHistory() }, + previousPageButtonItem = Triple({ goBack() }, { showBackwardHistory() }, false), onHomeButtonClick = { openMainPage() }, - nextPageButtonItem = { goForward() } to { showForwardHistory() }, + nextPageButtonItem = Triple({ goForward() }, { showForwardHistory() }, false), onTocClick = { openToc() }, - onCloseAllTabs = { closeAllTabs() } + onCloseAllTabs = { closeAllTabs() }, + bottomNavigationHeight = ZERO, + shouldShowBottomAppBar = true, + selectedWebView = null, + readerScreenTitle = "" ) ) private var readerLifeCycleScope: CoroutineScope? = null @@ -498,6 +499,19 @@ abstract class CoreReaderFragment : super.onViewCreated(view, savedInstanceState) composeView?.apply { setContent { + val lazyListState = rememberLazyListState() + val isBottomNavVisible = rememberBottomNavigationVisibility(lazyListState) + LaunchedEffect(isBottomNavVisible) { + (requireActivity() as CoreMainActivity).toggleBottomNavigation(isBottomNavVisible) + } + LaunchedEffect(Unit) { + readerScreenState.update { + copy( + bottomNavigationHeight = getBottomNavigationHeight(), + readerScreenTitle = context.getString(R.string.reader) + ) + } + } ReaderScreen( state = readerScreenState.value, actionMenuItems = emptyList(), @@ -507,13 +521,13 @@ abstract class CoreReaderFragment : contentDescription = string.open_drawer, onClick = { navigationIconClick() } ) - } + }, + listState = lazyListState ) DialogHost(alertDialogShower as AlertDialogShower) } } addAlertDialogToDialogHost() - setupMenu() donationDialogHandler?.setDonationDialogCallBack(this) val activity = requireActivity() as AppCompatActivity? activity?.let { @@ -613,6 +627,8 @@ abstract class CoreReaderFragment : handleClicks() } + private fun getBottomNavigationHeight(): Int = getBottomNavigationView()?.measuredHeight ?: ZERO + private fun navigationIconClick() { // Manually handle the navigation open/close. // Since currently we are using the view based navigation drawer in other screens. @@ -657,7 +673,6 @@ abstract class CoreReaderFragment : bottomToolbarArrowForward = findViewById(R.id.bottom_toolbar_arrow_forward) bottomToolbarHome = findViewById(R.id.bottom_toolbar_home) tabRecyclerView = findViewById(R.id.tab_switcher_recycler_view) - snackBarRoot = findViewById(R.id.snackbar_root) bottomToolbarToc = findViewById(R.id.bottom_toolbar_toc) donationLayout = findViewById(R.id.donation_layout) } @@ -912,7 +927,9 @@ abstract class CoreReaderFragment : // the unwanted blank space caused by the toolbar. setTopMarginToWebViews(-requireActivity().getToolbarHeight()) setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) - bottomToolbar?.visibility = GONE + readerScreenState.update { + copy(shouldShowBottomAppBar = false) + } contentFrame?.visibility = GONE progressBar?.visibility = GONE backToTopButton?.hide() @@ -1123,19 +1140,12 @@ abstract class CoreReaderFragment : @Suppress("MagicNumber") private fun updateBottomToolbarArrowsAlpha() { - bottomToolbarArrowForward?.let { - if (getCurrentWebView()?.canGoForward() == true) { - bottomToolbarArrowForward?.alpha = 1f - } else { - bottomToolbarArrowForward?.alpha = 0.6f - } - } - bottomToolbarArrowBack?.let { - if (getCurrentWebView()?.canGoBack() == true) { - bottomToolbarArrowBack?.alpha = 1f - } else { - bottomToolbarArrowBack?.alpha = 0.6f - } + val currentWebView = getCurrentWebView() + readerScreenState.update { + copy( + previousPageButtonItem = previousPageButtonItem.copy(third = currentWebView?.canGoBack() == true), + nextPageButtonItem = nextPageButtonItem.copy(third = currentWebView?.canGoForward() == true) + ) } } @@ -1224,7 +1234,9 @@ abstract class CoreReaderFragment : */ open fun updateTitle() { if (isAdded) { - actionBar?.title = getValidTitle(zimReaderContainer?.zimFileTitle) + readerScreenState.update { + copy(readerScreenTitle = getValidTitle(zimReaderContainer?.zimFileTitle)) + } } } @@ -1350,7 +1362,6 @@ abstract class CoreReaderFragment : super.onDestroyView() findInPageTitle = null searchItemToOpen = null - restoreTabsSnackbarCallback = null try { coreReaderLifeCycleScope?.cancel() readerLifeCycleScope?.cancel() @@ -1412,7 +1423,6 @@ abstract class CoreReaderFragment : bottomToolbarArrowForward = null bottomToolbarHome = null tabRecyclerView = null - snackBarRoot = null noOpenBookText = null bottomToolbarToc = null bottomToolbar = null @@ -1484,16 +1494,17 @@ abstract class CoreReaderFragment : @Throws(IllegalArgumentException::class) protected open fun createWebView(attrs: AttributeSet?): ToolbarScrollingKiwixWebView? { - requireNotNull(activityMainRoot) + // requireNotNull(activityMainRoot) return ToolbarScrollingKiwixWebView( requireActivity(), this, attrs ?: throw IllegalArgumentException("AttributeSet must not be null"), - activityMainRoot as ViewGroup, - requireNotNull(videoView), + null, + // requireNotNull(readerScreenState.value.fullScreenItem.second), + null, CoreWebViewClient(this, requireNotNull(zimReaderContainer)), - requireNotNull(toolbarContainer), - requireNotNull(bottomToolbar), + // requireNotNull(toolbarContainer), + // requireNotNull(bottomToolbar), requireNotNull(sharedPreferenceUtil) ) } @@ -1550,14 +1561,18 @@ abstract class CoreReaderFragment : notifyItemRemoved(index) notifyDataSetChanged() } - snackBarRoot?.let { - it.bringToFront() - Snackbar.make(it, R.string.tab_closed, Snackbar.LENGTH_LONG) - .setAction(R.string.undo) { undoButton -> - undoButton.isEnabled = false - restoreDeletedTab(index) - }.addCallback(restoreTabsSnackbarCallback).show() - } + readerScreenState.value.snackBarHostState.snack( + requireActivity().getString(R.string.tab_closed), + actionLabel = requireActivity().getString(R.string.undo), + snackbarDuration = SnackbarDuration.Long, + actionClick = { restoreDeletedTab(index) }, + lifecycleScope = lifecycleScope, + snackBarResult = { result -> + if (result != SnackbarResult.Dismissed && webViewList.isEmpty() && isAdded) { + closeZimBook() + } + } + ) openHomeScreen() } @@ -1569,8 +1584,12 @@ abstract class CoreReaderFragment : protected fun exitBook(shouldCloseZimBook: Boolean = true) { showNoBookOpenViews() - bottomToolbar?.visibility = GONE - actionBar?.title = getString(R.string.reader) + readerScreenState.update { + copy( + shouldShowBottomAppBar = false, + readerScreenTitle = requireActivity().getString(R.string.reader) + ) + } contentFrame?.visibility = GONE hideProgressBar() mainMenu?.hideBookSpecificMenuItems() @@ -1586,17 +1605,14 @@ abstract class CoreReaderFragment : } protected fun showProgressBarWithProgress(progress: Int) { - progressBar?.apply { - visibility = VISIBLE - show() - this.progress = progress + readerScreenState.update { + copy(pageLoadingItem = true to progress) } } protected fun hideProgressBar() { - progressBar?.apply { - visibility = GONE - hide() + readerScreenState.update { + copy(pageLoadingItem = false to ZERO) } } @@ -1617,9 +1633,10 @@ abstract class CoreReaderFragment : } webViewList.add(index, it) tabsAdapter?.notifyDataSetChanged() - snackBarRoot?.let { root -> - Snackbar.make(root, R.string.tab_restored, Snackbar.LENGTH_SHORT).show() - } + readerScreenState.value.snackBarHostState.snack( + requireActivity().getString(R.string.tab_restored), + lifecycleScope = lifecycleScope + ) setUpWithTextToSpeech(it) updateBottomToolbarVisibility() safelyAddWebView(it) @@ -1628,22 +1645,21 @@ abstract class CoreReaderFragment : private fun safelyAddWebView(webView: KiwixWebView) { webView.parent?.let { (it as ViewGroup).removeView(webView) } - contentFrame?.addView(webView) + readerScreenState.update { + copy(selectedWebView = webView) + } } protected fun selectTab(position: Int) { currentWebViewIndex = position - contentFrame?.let { - it.removeAllViews() - val webView = safelyGetWebView(position) ?: return@selectTab - safelyAddWebView(webView) - tabsAdapter?.selected = currentWebViewIndex - updateBottomToolbarVisibility() - loadPrefs() - updateUrlFlow() - updateTableOfContents() - updateTitle() - } + val webView = safelyGetWebView(position) ?: return + safelyAddWebView(webView) + tabsAdapter?.selected = currentWebViewIndex + updateBottomToolbarVisibility() + loadPrefs() + updateUrlFlow() + updateTableOfContents() + updateTitle() } private fun safelyGetWebView(position: Int): KiwixWebView? = @@ -1667,22 +1683,6 @@ abstract class CoreReaderFragment : } } - private fun setupMenu() { - (requireActivity() as MenuHost).addMenuProvider( - object : MenuProvider { - override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { - menu.clear() - mainMenu = createMainMenu(menu) - } - - override fun onMenuItemSelected(menuItem: MenuItem): Boolean = - mainMenu?.onOptionsItemSelected(menuItem) == true - }, - viewLifecycleOwner, - Lifecycle.State.RESUMED - ) - } - override fun onFullscreenMenuClicked() { if (isInFullScreenMode()) { closeFullScreen() @@ -1846,7 +1846,9 @@ abstract class CoreReaderFragment : protected open fun openFullScreen() { (requireActivity() as CoreMainActivity).disableDrawer(false) toolbarContainer?.visibility = GONE - bottomToolbar?.visibility = GONE + readerScreenState.update { + copy(shouldShowBottomAppBar = false) + } exitFullscreenButton?.visibility = VISIBLE exitFullscreenButton?.background?.alpha = 153 val window = requireActivity().window @@ -2038,16 +2040,19 @@ abstract class CoreReaderFragment : zimReaderSource?.let { openZimFile(it) } } } else { - snackBarRoot?.let { snackBarRoot -> - Snackbar.make(snackBarRoot, R.string.request_storage, Snackbar.LENGTH_LONG) - .setAction(R.string.menu_settings) { - val intent = Intent() - intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS - val uri = Uri.fromParts("package", requireActivity().packageName, null) - intent.data = uri - startActivity(intent) - }.show() - } + readerScreenState.value.snackBarHostState.snack( + requireActivity().getString(R.string.request_storage), + actionLabel = requireActivity().getString(R.string.menu_settings), + snackbarDuration = SnackbarDuration.Long, + actionClick = { + val intent = Intent() + intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS + val uri = Uri.fromParts("package", requireActivity().packageName, null) + intent.data = uri + startActivity(intent) + }, + lifecycleScope = lifecycleScope + ) } } @@ -2073,27 +2078,18 @@ abstract class CoreReaderFragment : webViewList.clear() tabsAdapter?.notifyDataSetChanged() openHomeScreen() - snackBarRoot?.let { root -> - root.bringToFront() - Snackbar.make(root, R.string.tabs_closed, Snackbar.LENGTH_LONG).apply { - setAction(R.string.undo) { - it.isEnabled = false // to prevent multiple clicks on this button - setIsCloseAllTabButtonClickable(true) - restoreDeletedTabs() + readerScreenState.value.snackBarHostState.snack( + requireActivity().getString(R.string.tabs_closed), + actionLabel = requireActivity().getString(R.string.undo), + snackbarDuration = SnackbarDuration.Long, + actionClick = { restoreDeletedTabs() }, + lifecycleScope = lifecycleScope, + snackBarResult = { result -> + if (result != SnackbarResult.Dismissed && webViewList.isEmpty() && isAdded) { + closeZimBook() } - }.addCallback(restoreTabsSnackbarCallback).show() - } - } - - private var restoreTabsSnackbarCallback: Snackbar.Callback? = object : Snackbar.Callback() { - override fun onDismissed(transientBottomBar: Snackbar?, event: Int) { - super.onDismissed(transientBottomBar, event) - // If the undo button is not clicked and no tabs are left, exit the book and - // clean up resources. - if (event != DISMISS_EVENT_ACTION && webViewList.isEmpty() && isAdded) { - closeZimBook() } - } + ) } private fun setIsCloseAllTabButtonClickable(isClickable: Boolean) { @@ -2104,9 +2100,10 @@ abstract class CoreReaderFragment : if (tempWebViewListForUndo.isNotEmpty()) { webViewList.addAll(tempWebViewListForUndo) tabsAdapter?.notifyDataSetChanged() - snackBarRoot?.let { root -> - Snackbar.make(root, R.string.tabs_restored, Snackbar.LENGTH_SHORT).show() - } + readerScreenState.value.snackBarHostState.snack( + requireActivity().getString(R.string.tabs_restored), + lifecycleScope = lifecycleScope + ) reopenBook() showTabSwitcher() setUpWithTextToSpeech(tempWebViewListForUndo[tempWebViewListForUndo.lastIndex]) @@ -2117,13 +2114,11 @@ abstract class CoreReaderFragment : // opens home screen when user closes all tabs protected fun showNoBookOpenViews() { - noOpenBookButton?.visibility = VISIBLE - noOpenBookText?.visibility = VISIBLE + readerScreenState.update { copy(isNoBookOpenInReader = true) } } private fun hideNoBookOpenViews() { - noOpenBookButton?.visibility = GONE - noOpenBookText?.visibility = GONE + readerScreenState.update { copy(isNoBookOpenInReader = false) } } @Suppress("MagicNumber") @@ -2145,19 +2140,20 @@ abstract class CoreReaderFragment : val libKiwixBook = getLibkiwixBook(zimFileReader) if (isBookmarked) { repositoryActions?.deleteBookmark(libKiwixBook.id, articleUrl) - snackBarRoot?.snack(R.string.bookmark_removed) + readerScreenState.value.snackBarHostState.snack( + requireActivity().getString(R.string.bookmark_removed), + lifecycleScope = lifecycleScope + ) } else { getCurrentWebView()?.title?.let { repositoryActions?.saveBookmark( LibkiwixBookmarkItem(it, articleUrl, zimFileReader, libKiwixBook) ) - snackBarRoot?.snack( - stringId = R.string.bookmark_added, - actionStringId = R.string.open, - actionClick = { - goToBookmarks() - Unit - } + readerScreenState.value.snackBarHostState.snack( + requireActivity().getString(R.string.bookmark_added), + lifecycleScope = lifecycleScope, + actionLabel = requireActivity().getString(R.string.open), + actionClick = { goToBookmarks() } ) } } @@ -2174,7 +2170,7 @@ abstract class CoreReaderFragment : } /** - * Returns the libkiwix book evertime when user saves or remove the bookmark. + * Returns the libkiwix book everytime when user saves or remove the bookmark. * the object will be created once to avoid creating it multiple times. */ private fun getLibkiwixBook(zimFileReader: ZimFileReader): Book { @@ -2289,14 +2285,10 @@ abstract class CoreReaderFragment : protected fun isInFullScreenMode(): Boolean = sharedPreferenceUtil?.prefFullScreen == true private fun updateBottomToolbarVisibility() { - bottomToolbar?.let { - if (urlIsValid() && - tabSwitcherRoot?.visibility != VISIBLE && !isInFullScreenMode() - ) { - it.visibility = VISIBLE - } else { - it.visibility = GONE - } + // TODO refactroe this code once we integrate the tabSwitcher + // tabSwitcherRoot?.visibility != VISIBLE && !isInFullScreenMode() + readerScreenState.update { + copy(shouldShowBottomAppBar = !isInFullScreenMode()) } } @@ -2566,17 +2558,13 @@ abstract class CoreReaderFragment : * WARNING: If modifying this method, ensure thorough testing with custom apps * to verify proper functionality. */ - protected open fun createMainMenu(menu: Menu?): MainMenu? = - menu?.let { - menuFactory?.create( - it, - webViewList, - urlIsValid(), - menuClickListener = this, - disableReadAloud = false, - disableTabs = false - ) - } + protected open fun createMainMenu(menu: Menu?): ReaderMenuState? = + ReaderMenuState( + this, + disableReadAloud = false, + disableTabs = false, + disableSearch = false + ) protected fun urlIsValid(): Boolean = getCurrentWebView()?.url != null @@ -2588,7 +2576,7 @@ abstract class CoreReaderFragment : painter?.update( getCurrentWebView(), ::shouldActivateNightMode, - videoView + readerScreenState.value.fullScreenItem.second ) } @@ -2878,11 +2866,14 @@ abstract class CoreReaderFragment : { if (isOpenNewTabInBackground) { newTabInBackground(url) - snackBarRoot?.snack( - stringId = R.string.new_tab_snack_bar, - actionStringId = R.string.open, + readerScreenState.value.snackBarHostState.snack( + message = requireActivity().getString(R.string.new_tab_snack_bar), + lifecycleScope = lifecycleScope, + actionLabel = requireActivity().getString(R.string.open), actionClick = { - if (webViewList.size > 1) selectTab(webViewList.size - 1) + if (webViewList.size > 1) { + selectTab(webViewList.size - 1) + } } ) } else { @@ -3104,6 +3095,8 @@ abstract class CoreReaderFragment : * when handling invalid JSON scenarios. */ abstract fun restoreViewStateOnInvalidWebViewHistory() + + abstract fun getBottomNavigationView(): BottomNavigationView? } enum class RestoreOrigin { diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/ReaderMenuState.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/ReaderMenuState.kt new file mode 100644 index 000000000..abdf44096 --- /dev/null +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/ReaderMenuState.kt @@ -0,0 +1,156 @@ +/* + * Kiwix Android + * Copyright (c) 2025 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.reader + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.runtime.Stable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import org.kiwix.kiwixmobile.core.R +import org.kiwix.kiwixmobile.core.page.SEARCH_ICON_TESTING_TAG +import org.kiwix.kiwixmobile.core.ui.models.ActionMenuItem +import org.kiwix.kiwixmobile.core.ui.models.IconItem + +const val READ_ALOUD_MENU_ITEM_TESTING_TAG = "readAloudMenuItemTestingTag" +const val TAKE_NOTE_MENU_ITEM_TESTING_TAG = "takeNoteMenuItemTestingTag" +const val FULL_SCREEN_MENU_ITEM_TESTING_TAG = "fullScreenMenuItemTestingTag" +const val RANDOM_ARTICLE_MENU_ITEM_TESTING_TAG = "randomArticleMenuItemTestingTag" +const val TAB_MENU_ITEM_TESTING_TAG = "tabMenuItemTestingTag" + +@Stable +class ReaderMenuState( + private val menuClickListener: MenuClickListener, + private val disableReadAloud: Boolean = false, + private val disableTabs: Boolean = false, + private val disableSearch: Boolean = false +) { + interface MenuClickListener { + fun onTabMenuClicked() + fun onHomeMenuClicked() + fun onAddNoteMenuClicked() + fun onRandomArticleMenuClicked() + fun onReadAloudMenuClicked() + fun onFullscreenMenuClicked() + fun onSearchMenuClickedMenuClicked() + } + + var isInTabSwitcher by mutableStateOf(false) + private set + + var isReadingAloud by mutableStateOf(false) + private set + + var webViewCount by mutableStateOf(0) + var urlIsValid by mutableStateOf(false) + var zimFileReaderAvailable by mutableStateOf(false) + + fun onTabsChanged(count: Int) { + webViewCount = count + } + + fun onUrlValidityChanged(valid: Boolean) { + urlIsValid = valid + } + + fun onZimFileReaderAvailable(available: Boolean) { + zimFileReaderAvailable = available + } + + fun onTextToSpeechStarted() { + isReadingAloud = true + } + + fun onTextToSpeechStopped() { + isReadingAloud = false + } + + fun exitTabSwitcher() { + isInTabSwitcher = false + } + + @Suppress("LongMethod", "MagicNumber") + fun getActionMenuItems(): List { + if (isInTabSwitcher) { + return emptyList() + } + + val list = mutableListOf() + + if (!disableSearch && urlIsValid) { + list += ActionMenuItem( + icon = IconItem.Drawable(R.drawable.action_search), + contentDescription = R.string.search_label, + onClick = { menuClickListener.onSearchMenuClickedMenuClicked() }, + isInOverflow = false, + testingTag = SEARCH_ICON_TESTING_TAG + ) + } + + if (!disableTabs) { + val tabLabel = if (webViewCount > 99) ":D" else "$webViewCount" + list += ActionMenuItem( + icon = IconItem.Vector(Icons.Default.Add), + contentDescription = R.string.switch_tabs, + onClick = { + isInTabSwitcher = true + menuClickListener.onTabMenuClicked() + }, + isInOverflow = false, + iconButtonText = tabLabel, + testingTag = TAB_MENU_ITEM_TESTING_TAG + ) + } + + if (urlIsValid) { + list += listOf( + ActionMenuItem( + icon = IconItem.Drawable(R.drawable.ic_add_note), + contentDescription = R.string.take_notes, + onClick = { menuClickListener.onAddNoteMenuClicked() }, + testingTag = TAKE_NOTE_MENU_ITEM_TESTING_TAG + ), + ActionMenuItem( + contentDescription = R.string.menu_random_article, + onClick = { menuClickListener.onRandomArticleMenuClicked() }, + testingTag = RANDOM_ARTICLE_MENU_ITEM_TESTING_TAG + ), + ActionMenuItem( + contentDescription = R.string.menu_full_screen, + onClick = { menuClickListener.onFullscreenMenuClicked() }, + testingTag = FULL_SCREEN_MENU_ITEM_TESTING_TAG + ) + ) + + if (!disableReadAloud) { + list += ActionMenuItem( + contentDescription = if (isReadingAloud) R.string.menu_read_aloud_stop else R.string.menu_read_aloud, + onClick = { + isReadingAloud = !isReadingAloud + menuClickListener.onReadAloudMenuClicked() + }, + testingTag = READ_ALOUD_MENU_ITEM_TESTING_TAG + ) + } + } + + return list + } +} 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 7bc997981..5d43ef8c1 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 @@ -36,13 +36,16 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.BottomAppBar +import androidx.compose.material3.BottomAppBarDefaults import androidx.compose.material3.Button import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults @@ -54,23 +57,31 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.key +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource 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.dp import androidx.compose.ui.viewinterop.AndroidView import org.kiwix.kiwixmobile.core.R +import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO import org.kiwix.kiwixmobile.core.main.DarkModeViewPainter import org.kiwix.kiwixmobile.core.main.KiwixWebView import org.kiwix.kiwixmobile.core.ui.components.ContentLoadingProgressBar @@ -78,6 +89,8 @@ import org.kiwix.kiwixmobile.core.ui.components.KiwixAppBar import org.kiwix.kiwixmobile.core.ui.components.KiwixButton import org.kiwix.kiwixmobile.core.ui.components.KiwixSnackbarHost import org.kiwix.kiwixmobile.core.ui.components.ProgressBarStyle +import org.kiwix.kiwixmobile.core.ui.components.ScrollDirection +import org.kiwix.kiwixmobile.core.ui.components.rememberLazyListScrollListener import org.kiwix.kiwixmobile.core.ui.models.ActionMenuItem import org.kiwix.kiwixmobile.core.ui.models.IconItem import org.kiwix.kiwixmobile.core.ui.models.IconItem.Drawable @@ -103,14 +116,29 @@ const val CONTENT_LOADING_PROGRESSBAR_TESTING_TAG = "contentLoadingProgressBarTe @Composable fun ReaderScreen( state: ReaderScreenState, + listState: LazyListState, actionMenuItems: List, navigationIcon: @Composable () -> Unit ) { + val (bottomNavHeight, lazyListState) = + rememberScrollBehavior(state.bottomNavigationHeight, listState) + val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() KiwixDialogTheme { Scaffold( snackbarHost = { KiwixSnackbarHost(snackbarHostState = state.snackBarHostState) }, - topBar = { KiwixAppBar(R.string.note, navigationIcon, actionMenuItems) }, - floatingActionButton = { BackToTopFab(state) } + topBar = { + KiwixAppBar( + state.readerScreenTitle, + navigationIcon, + actionMenuItems, + scrollBehavior + ) + }, + floatingActionButton = { BackToTopFab(state) }, + modifier = Modifier + .systemBarsPadding() + .nestedScroll(scrollBehavior.nestedScrollConnection) + .padding(bottom = bottomNavHeight.value) ) { paddingValues -> Box( modifier = Modifier @@ -120,15 +148,16 @@ fun ReaderScreen( if (state.isNoBookOpenInReader) { NoBookOpenView(state.onOpenLibraryButtonClicked) } else { + ShowZIMFileContent(state) ShowProgressBarIfZIMFilePageIsLoading(state) - ShowZIMFileContent(state.kiwixWebViewList) TtsControls(state) BottomAppBarOfReaderScreen( state.bookmarkButtonItem, state.previousPageButtonItem, state.onHomeButtonClick, state.nextPageButtonItem, - state.onTocClick + state.onTocClick, + state.shouldShowBottomAppBar ) ShowFullScreenView(state) } @@ -139,9 +168,14 @@ fun ReaderScreen( } @Composable -private fun ShowZIMFileContent(kiwixWebViewList: List) { - if (kiwixWebViewList.isNotEmpty()) { - AndroidView({ kiwixWebViewList[0] }, modifier = Modifier.fillMaxSize()) +private fun ShowZIMFileContent(state: ReaderScreenState) { + state.selectedWebView?.let { selectedWebView -> + key(selectedWebView) { + AndroidView( + factory = { selectedWebView }, + modifier = Modifier.fillMaxSize() + ) + } } } @@ -158,7 +192,7 @@ private fun BoxScope.ShowProgressBarIfZIMFilePageIsLoading(state: ReaderScreenSt ContentLoadingProgressBar( modifier = Modifier .testTag(CONTENT_LOADING_PROGRESSBAR_TESTING_TAG) - .align(Alignment.CenterEnd), + .align(Alignment.TopCenter), progressBarStyle = ProgressBarStyle.HORIZONTAL, progress = state.pageLoadingItem.second ) @@ -240,17 +274,22 @@ private fun BackToTopFab(state: ReaderScreenState) { } } +@OptIn(ExperimentalMaterial3Api::class) @Composable -private fun BottomAppBarOfReaderScreen( +private fun BoxScope.BottomAppBarOfReaderScreen( bookmarkButtonItem: Triple<() -> Unit, () -> Unit, Drawable>, - previousPageButtonItem: Pair<() -> Unit, () -> Unit>, + previousPageButtonItem: Triple<() -> Unit, () -> Unit, Boolean>, onHomeButtonClick: () -> Unit, - nextPageButtonItem: Pair<() -> Unit, () -> Unit>, - onTocClick: () -> Unit + nextPageButtonItem: Triple<() -> Unit, () -> Unit, Boolean>, + onTocClick: () -> Unit, + shouldShowBottomAppBar: Boolean ) { + if (!shouldShowBottomAppBar) return BottomAppBar( containerColor = Black, - contentColor = White + contentColor = White, + modifier = Modifier.align(Alignment.BottomCenter), + scrollBehavior = BottomAppBarDefaults.exitAlwaysScrollBehavior() ) { Row( modifier = Modifier @@ -271,6 +310,7 @@ private fun BottomAppBarOfReaderScreen( onClick = previousPageButtonItem.first, onLongClick = previousPageButtonItem.second, buttonIcon = Drawable(R.drawable.ic_keyboard_arrow_left_24dp), + shouldEnable = previousPageButtonItem.third, contentDescription = stringResource(R.string.go_to_previous_page) ) // Home Icon(to open the home page of ZIM file) @@ -284,6 +324,7 @@ private fun BottomAppBarOfReaderScreen( onClick = nextPageButtonItem.first, onLongClick = nextPageButtonItem.second, buttonIcon = Drawable(R.drawable.ic_keyboard_arrow_right_24dp), + shouldEnable = nextPageButtonItem.third, contentDescription = stringResource(R.string.go_to_next_page) ) // Toggle Icon(to open the table of content in right side bar) @@ -301,11 +342,13 @@ private fun BottomAppBarButtonIcon( onClick: () -> Unit, onLongClick: (() -> Unit)? = null, buttonIcon: IconItem, + shouldEnable: Boolean = true, contentDescription: String ) { IconButton( onClick = onClick, - modifier = Modifier.combinedClickable(onClick = onClick, onLongClick = onLongClick) + modifier = Modifier.combinedClickable(onClick = onClick, onLongClick = onLongClick), + enabled = shouldEnable ) { Icon( buttonIcon.toPainter(), @@ -454,3 +497,30 @@ fun TabItemView( } } } + +@Composable +fun rememberScrollBehavior( + bottomNavigationHeight: Int, + listState: LazyListState, +): Pair, LazyListState> { + val bottomNavHeightInDp = with(LocalDensity.current) { bottomNavigationHeight.toDp() } + val bottomNavHeight = remember { mutableStateOf(bottomNavHeightInDp) } + val lazyListState = rememberLazyListScrollListener( + lazyListState = listState, + onScrollChanged = { direction -> + when (direction) { + ScrollDirection.SCROLL_UP -> { + bottomNavHeight.value = bottomNavHeightInDp + } + + ScrollDirection.SCROLL_DOWN -> { + bottomNavHeight.value = ZERO.dp + } + + ScrollDirection.IDLE -> {} + } + } + ) + + return bottomNavHeight to lazyListState +} diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/ReaderScreenState.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/ReaderScreenState.kt index 2da1a70db..0bb43d980 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/ReaderScreenState.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/ReaderScreenState.kt @@ -83,6 +83,10 @@ data class ReaderScreenState( * To show in the tabs view. */ val kiwixWebViewList: List, + /** + * Manages the showing of current selected webView. + */ + val selectedWebView: KiwixWebView?, /** * Handles the (UI, and clicks) for bookmark button in reader bottom toolbar. * @@ -95,11 +99,12 @@ data class ReaderScreenState( /** * Handles the clicks of previous page button in reader bottom toolbar. * - * A [Pair] containing: + * A [Triple] containing: * - [Unit]: Handles the normal click of button(For going to previous page). * - [Unit]: Handles the long click of button(For showing the previous pages history). + * - [Boolean]: Handles the button should enable or not. */ - val previousPageButtonItem: Pair<() -> Unit, () -> Unit>, + val previousPageButtonItem: Triple<() -> Unit, () -> Unit, Boolean>, /** * Handles the click to open home page of ZIM file button click in reader bottom toolbar. */ @@ -110,11 +115,21 @@ data class ReaderScreenState( * A [Pair] containing: * - [Unit]: Handles the normal click of button(For going to next page). * - [Unit]: Handles the long click of button(For showing the next pages history). + * - [Boolean]: Handles the button should enable or not. */ - val nextPageButtonItem: Pair<() -> Unit, () -> Unit>, + val nextPageButtonItem: Triple<() -> Unit, () -> Unit, Boolean>, /** * Handles the click to open right sidebar button click in reader bottom toolbar. */ val onTocClick: () -> Unit, - val onCloseAllTabs: () -> Unit + val onCloseAllTabs: () -> Unit, + /** + * Stores the height of the bottom navigation bar in pixels. + */ + val bottomNavigationHeight: Int, + /** + * Manages the showing of Reader's [BottomAppBarOfReaderScreen]. + */ + val shouldShowBottomAppBar: Boolean, + val readerScreenTitle: String ) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/PageScreen.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/PageScreen.kt index e1a6df217..5fdadd598 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/PageScreen.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/page/PageScreen.kt @@ -88,7 +88,7 @@ fun PageScreen( topBar = { Column { KiwixAppBar( - titleId = state.screenTitle, + title = stringResource(state.screenTitle), navigationIcon = navigationIcon, actionMenuItems = actionMenuItems, searchBar = searchBarIfActive(state) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/NavigationHistoryDialogScreen.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/NavigationHistoryDialogScreen.kt index 0bf84774a..159437055 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/NavigationHistoryDialogScreen.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/NavigationHistoryDialogScreen.kt @@ -70,7 +70,7 @@ fun NavigationHistoryDialogScreen( ) { KiwixDialogTheme { Scaffold( - topBar = { KiwixAppBar(titleId, navigationIcon, actionMenuItems) } + topBar = { KiwixAppBar(stringResource(titleId), navigationIcon, actionMenuItems) } ) { paddingValues -> Box( modifier = Modifier diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/search/SearchFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/search/SearchFragment.kt index 0c8fa9eec..5a132700a 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/search/SearchFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/search/SearchFragment.kt @@ -260,7 +260,7 @@ class SearchFragment : BaseFragment() { searchViewModel.actions.trySend(ClickedSearchInText).isSuccess }, testingTag = FIND_IN_PAGE_TESTING_TAG, - iconButtonText = R.string.menu_search_in_text, + iconButtonText = requireActivity().getString(R.string.menu_search_in_text), isEnabled = findInPageMenuItem.value.first ) } else { diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/search/SearchScreen.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/search/SearchScreen.kt index 658442fb7..a46c0436d 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/search/SearchScreen.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/search/SearchScreen.kt @@ -87,7 +87,7 @@ fun SearchScreen( Scaffold( topBar = { KiwixAppBar( - titleId = R.string.empty_string, + title = stringResource(R.string.empty_string), navigationIcon = searchScreenState.navigationIcon, actionMenuItems = actionMenuItemList, searchBar = { diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/settings/SettingsScreen.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/settings/SettingsScreen.kt index 8ce0ea93d..f316ec930 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/settings/SettingsScreen.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/settings/SettingsScreen.kt @@ -117,7 +117,7 @@ fun SettingsScreen( Scaffold( topBar = { KiwixAppBar( - titleId = R.string.menu_settings, + title = stringResource(R.string.menu_settings), navigationIcon = navigationIcon ) } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/ui/components/KiwixAppBar.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/ui/components/KiwixAppBar.kt index c66b843a8..59eead867 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/ui/components/KiwixAppBar.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/ui/components/KiwixAppBar.kt @@ -18,7 +18,6 @@ package org.kiwix.kiwixmobile.core.ui.components -import androidx.annotation.StringRes import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row @@ -29,6 +28,10 @@ import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -67,7 +70,7 @@ const val TOOLBAR_TITLE_TESTING_TAG = "toolbarTitle" @OptIn(ExperimentalMaterial3Api::class) @Composable fun KiwixAppBar( - @StringRes titleId: Int, + title: String, navigationIcon: @Composable () -> Unit, actionMenuItems: List = emptyList(), topAppBarScrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(), @@ -76,7 +79,7 @@ fun KiwixAppBar( ) { KiwixTheme { TopAppBar( - title = { AppBarTitleSection(titleId, searchBar) }, + title = { AppBarTitleSection(title, searchBar) }, navigationIcon = navigationIcon, actions = { ActionMenu(actionMenuItems) }, scrollBehavior = topAppBarScrollBehavior, @@ -95,7 +98,7 @@ fun KiwixAppBar( @Suppress("ComposableLambdaParameterNaming") @Composable private fun AppBarTitleSection( - @StringRes titleId: Int, + title: String, searchBar: (@Composable () -> Unit)? = null ) { Box( @@ -107,14 +110,14 @@ private fun AppBarTitleSection( searchBar?.let { it() } ?: run { - AppBarTitle(titleId) + AppBarTitle(title) } } } @Composable private fun AppBarTitle( - @StringRes titleId: Int + title: String ) { val appBarTitleColor = if (isSystemInDarkTheme()) { MineShaftGray350 @@ -122,7 +125,7 @@ private fun AppBarTitle( White } Text( - text = stringResource(titleId), + text = title, color = appBarTitleColor, style = MaterialTheme.typography.titleMedium, overflow = TextOverflow.Ellipsis, @@ -132,10 +135,14 @@ private fun AppBarTitle( ) } +@Suppress("LongMethod") @Composable private fun ActionMenu(actionMenuItems: List) { + var overflowExpanded by remember { mutableStateOf(false) } + Row { - actionMenuItems.forEach { menuItem -> + val (mainActions, overflowActions) = actionMenuItems.partition { !it.isInOverflow } + mainActions.forEach { menuItem -> val modifier = menuItem.modifier.testTag(menuItem.testingTag) // If icon is not null show the icon. menuItem.icon?.let { @@ -158,7 +165,7 @@ private fun ActionMenu(actionMenuItems: List) { modifier = modifier ) { Text( - text = stringResource(id = menuItem.iconButtonText).uppercase(), + text = menuItem.iconButtonText.uppercase(), color = if (menuItem.isEnabled) Color.White else Color.Gray, maxLines = 1, overflow = TextOverflow.Ellipsis, @@ -166,6 +173,32 @@ private fun ActionMenu(actionMenuItems: List) { } } } + if (overflowActions.isNotEmpty()) { + IconButton(onClick = { overflowExpanded = true }) { + Icon( + imageVector = Icons.Default.MoreVert, + contentDescription = null, + tint = White + ) + } + } + DropdownMenu( + expanded = overflowExpanded, + onDismissRequest = { overflowExpanded = false } + ) { + overflowActions.forEach { menuItem -> + DropdownMenuItem( + text = { + Text(text = menuItem.iconButtonText) + }, + onClick = { + overflowExpanded = false + menuItem.onClick() + }, + enabled = menuItem.isEnabled + ) + } + } } } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/ui/models/ActionMenuItem.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/ui/models/ActionMenuItem.kt index b367aa273..ae5b7ea0f 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/ui/models/ActionMenuItem.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/ui/models/ActionMenuItem.kt @@ -21,7 +21,6 @@ package org.kiwix.kiwixmobile.core.ui.models import androidx.annotation.StringRes import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.ui.theme.White data class ActionMenuItem( @@ -30,7 +29,8 @@ data class ActionMenuItem( val onClick: () -> Unit, val iconTint: Color = White, val isEnabled: Boolean = true, - @StringRes val iconButtonText: Int = R.string.empty_string, + val iconButtonText: String = "", val testingTag: String, - val modifier: Modifier = Modifier + val modifier: Modifier = Modifier, + val isInOverflow: Boolean = false ) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/utils/ComposeDimens.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/utils/ComposeDimens.kt index 40a6632a2..8529c2a14 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/utils/ComposeDimens.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/utils/ComposeDimens.kt @@ -181,7 +181,7 @@ object ComposeDimens { val CATEGORY_TITLE_TEXT_SIZE = 14.sp // Reader screen dimes - val READER_BOTTOM_APP_BAR_LAYOUT_HEIGHT = 48.dp + val READER_BOTTOM_APP_BAR_LAYOUT_HEIGHT = 40.dp val READER_BOTTOM_APP_BAR_BUTTON_ICON_SIZE = 30.dp const val TTS_BUTTONS_CONTROL_ALPHA = 0.6f val CLOSE_ALL_TAB_BUTTON_BOTTOM_PADDING = 24.dp diff --git a/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomMainActivity.kt b/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomMainActivity.kt index a570000d3..06ab70a52 100644 --- a/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomMainActivity.kt +++ b/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomMainActivity.kt @@ -215,6 +215,10 @@ class CustomMainActivity : CoreMainActivity() { activityCustomMainBinding.root.addView(getDialogHostComposeView(alertDialogShower), 0) } + override fun toggleBottomNavigation(isVisible: Boolean) { + // Do nothing as we do not have the bottomNavigationView in custom apps. + } + // Outdated shortcut id(new_tab) // Remove if the application has the outdated shortcut. private fun removeOutdatedIdShortcuts() { diff --git a/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomReaderFragment.kt b/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomReaderFragment.kt index 1a5eecbe2..c79ce3c82 100644 --- a/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomReaderFragment.kt +++ b/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomReaderFragment.kt @@ -31,6 +31,7 @@ import androidx.appcompat.widget.Toolbar import androidx.core.net.toUri import androidx.drawerlayout.widget.DrawerLayout import androidx.navigation.fragment.findNavController +import com.google.android.material.bottomnavigation.BottomNavigationView import kotlinx.coroutines.launch import org.kiwix.kiwixmobile.core.R.dimen import org.kiwix.kiwixmobile.core.base.BaseActivity @@ -38,7 +39,7 @@ import org.kiwix.kiwixmobile.core.extensions.browserIntent import org.kiwix.kiwixmobile.core.extensions.getResizedDrawable import org.kiwix.kiwixmobile.core.extensions.isFileExist import org.kiwix.kiwixmobile.core.main.reader.CoreReaderFragment -import org.kiwix.kiwixmobile.core.main.MainMenu +import org.kiwix.kiwixmobile.core.main.reader.ReaderMenuState import org.kiwix.kiwixmobile.core.main.reader.RestoreOrigin import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryItem import org.kiwix.kiwixmobile.core.reader.ZimReaderSource @@ -157,6 +158,9 @@ class CustomReaderFragment : CoreReaderFragment() { openHomeScreen() } + // Since custom apps do not have the bottomNavigationView, so returning null. + override fun getBottomNavigationView(): BottomNavigationView? = null + /** * Restores the view state when the webViewHistory data is valid. * This method restores the tabs with webView pages history. @@ -304,19 +308,13 @@ class CustomReaderFragment : CoreReaderFragment() { * provided configuration. It takes into account whether read aloud and tabs are enabled or disabled * and creates the menu accordingly. */ - override fun createMainMenu(menu: Menu?): MainMenu? { - return menu?.let { - menuFactory?.create( - it, - webViewList, - urlIsValid(), - this, - BuildConfig.DISABLE_READ_ALOUD, - BuildConfig.DISABLE_TABS, - BuildConfig.DISABLE_TITLE - ) - } - } + override fun createMainMenu(menu: Menu?): ReaderMenuState? = + ReaderMenuState( + this, + disableReadAloud = BuildConfig.DISABLE_READ_ALOUD, + disableTabs = BuildConfig.DISABLE_TABS, + disableSearch = BuildConfig.DISABLE_TITLE + ) /** * Overrides the method to control the functionality of showing the "Open In New Tab" dialog.