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 62a3e6b79..c691e7efb 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/main/KiwixMainActivity.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/main/KiwixMainActivity.kt @@ -23,7 +23,6 @@ import android.content.res.Configuration import android.os.Bundle import android.os.Handler import android.os.Looper -import android.view.MenuItem import androidx.activity.compose.setContent import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.view.ActionMode @@ -50,7 +49,6 @@ import org.kiwix.kiwixmobile.BuildConfig import org.kiwix.kiwixmobile.R import org.kiwix.kiwixmobile.core.CoreApp import org.kiwix.kiwixmobile.core.R.drawable -import org.kiwix.kiwixmobile.core.R.id import org.kiwix.kiwixmobile.core.R.mipmap import org.kiwix.kiwixmobile.core.R.string import org.kiwix.kiwixmobile.core.base.FragmentActivityExtensions @@ -63,7 +61,6 @@ import org.kiwix.kiwixmobile.core.main.CoreMainActivity import org.kiwix.kiwixmobile.core.main.DrawerMenuItem import org.kiwix.kiwixmobile.core.main.NEW_TAB_SHORTCUT_ID import org.kiwix.kiwixmobile.core.utils.LanguageUtils.Companion.handleLocaleChange -import org.kiwix.kiwixmobile.core.utils.dialog.AlertDialogShower import org.kiwix.kiwixmobile.core.utils.dialog.DialogHost import org.kiwix.kiwixmobile.kiwixActivityComponent import org.kiwix.kiwixmobile.ui.KiwixDestination @@ -72,25 +69,12 @@ import javax.inject.Inject const val ACTION_GET_CONTENT = "GET_CONTENT" const val OPENING_ZIM_FILE_DELAY = 300L const val GET_CONTENT_SHORTCUT_ID = "get_content_shortcut" -const val KIWIX_BOTTOM_BAR_ANIMATION_DURATION = 250L class KiwixMainActivity : CoreMainActivity() { private var actionMode: ActionMode? = null override val cachedComponent by lazy { kiwixActivityComponent } override val searchFragmentRoute: String = KiwixDestination.Search.route - // override val drawerContainerLayout: DrawerLayout by lazy { - // // activityKiwixMainBinding.navigationContainer - // } - - // override val drawerNavView: NavigationView by lazy { - // activityKiwixMainBinding.drawerNavView - // } - - // override val readerTableOfContentsDrawer: NavigationView by lazy { - // activityKiwixMainBinding.readerDrawerNavView - // } - @Inject lateinit var libkiwixBookOnDisk: LibkiwixBookOnDisk override val mainActivity: AppCompatActivity by lazy { this } @@ -288,14 +272,6 @@ class KiwixMainActivity : CoreMainActivity() { navigate(KiwixDestination.Reader.createRoute(zimFileUri = path)) } - override fun onNavigationItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - id.menu_host_books -> openZimHostFragment() - else -> return super.onNavigationItemSelected(item) - } - return true - } - override val zimHostDrawerMenuItem: DrawerMenuItem? = DrawerMenuItem( title = CoreApp.instance.getString(string.menu_wifi_hotspot), iconRes = drawable.ic_mobile_screen_share_24px, @@ -323,7 +299,7 @@ class KiwixMainActivity : CoreMainActivity() { override val aboutAppDrawerMenuItem: DrawerMenuItem? = null private fun openZimHostFragment() { - disableDrawer() + disableLeftDrawer() handleDrawerOnNavigation() navigate(KiwixDestination.ZimHost.route) } @@ -336,10 +312,6 @@ class KiwixMainActivity : CoreMainActivity() { ShortcutManagerCompat.addDynamicShortcuts(this, dynamicShortcutList()) } - override fun setDialogHostToActivity(alertDialogShower: AlertDialogShower) { - // activityKiwixMainBinding.root.addView(getDialogHostComposeView(alertDialogShower), 0) - } - override fun openSearch(searchString: String, isOpenedFromTabView: Boolean, isVoice: Boolean) { navigate( KiwixDestination.Search.createRoute( diff --git a/app/src/main/java/org/kiwix/kiwixmobile/main/KiwixMainActivityScreen.kt b/app/src/main/java/org/kiwix/kiwixmobile/main/KiwixMainActivityScreen.kt index 7dd4ddeeb..e396285e1 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/main/KiwixMainActivityScreen.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/main/KiwixMainActivityScreen.kt @@ -22,6 +22,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.material3.BottomAppBar import androidx.compose.material3.BottomAppBarScrollBehavior import androidx.compose.material3.DrawerState @@ -51,6 +52,7 @@ import org.kiwix.kiwixmobile.core.ui.theme.White import org.kiwix.kiwixmobile.ui.KiwixDestination import org.kiwix.kiwixmobile.ui.KiwixNavGraph +@Suppress("LongParameterList") @OptIn(ExperimentalMaterial3Api::class) @Composable fun KiwixMainActivityScreen( @@ -83,28 +85,28 @@ fun KiwixMainActivityScreen( // on the hamburger button. (currentRoute != KiwixDestination.Reader.route || leftDrawerState.isOpen) ) { - Box { - Scaffold( - bottomBar = { - if (shouldShowBottomBar) { - BottomNavigationBar( - navController = navController, - bottomAppBarScrollBehaviour = bottomAppBarScrollBehaviour, - navBackStackEntry = navBackStackEntry, - leftDrawerState = leftDrawerState, - uiCoroutineScope = uiCoroutineScope - ) - } - }, - modifier = Modifier.fillMaxSize() - ) { paddingValues -> - Box(modifier = Modifier.padding(paddingValues)) { - KiwixNavGraph( + Scaffold( + bottomBar = { + if (shouldShowBottomBar) { + BottomNavigationBar( navController = navController, - startDestination = startDestination, - modifier = Modifier.fillMaxSize() + bottomAppBarScrollBehaviour = bottomAppBarScrollBehaviour, + navBackStackEntry = navBackStackEntry, + leftDrawerState = leftDrawerState, + uiCoroutineScope = uiCoroutineScope ) } + }, + modifier = Modifier + .fillMaxSize() + .systemBarsPadding() + ) { paddingValues -> + Box(modifier = Modifier.padding(paddingValues)) { + KiwixNavGraph( + navController = navController, + startDestination = startDestination, + modifier = Modifier.fillMaxSize() + ) } } } diff --git a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/local/LocalLibraryFragment.kt b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/local/LocalLibraryFragment.kt index 5158941d6..c15409827 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/local/LocalLibraryFragment.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/local/LocalLibraryFragment.kt @@ -113,7 +113,6 @@ import java.util.Locale import javax.inject.Inject private const val WAS_IN_ACTION_MODE = "WAS_IN_ACTION_MODE" -private const val MATERIAL_BOTTOM_VIEW_ENTER_ANIMATION_DURATION = 225L const val LOCAL_FILE_TRANSFER_MENU_BUTTON_TESTING_TAG = "localFileTransferMenuButtonTestingTag" @Suppress("LargeClass") 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 46b379e87..d84a3534e 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 @@ -26,10 +26,8 @@ import android.view.MenuInflater import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.core.net.toUri -import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.lifecycleScope import androidx.navigation.NavOptions -import com.google.android.material.bottomnavigation.BottomNavigationView import kotlinx.coroutines.launch import org.kiwix.kiwixmobile.cachedComponent import org.kiwix.kiwixmobile.core.R.string @@ -37,7 +35,6 @@ import org.kiwix.kiwixmobile.core.base.BaseActivity import org.kiwix.kiwixmobile.core.base.FragmentActivityExtensions.Super import org.kiwix.kiwixmobile.core.base.FragmentActivityExtensions.Super.ShouldCall import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO -import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.setupDrawerToggle import org.kiwix.kiwixmobile.core.extensions.isFileExist import org.kiwix.kiwixmobile.core.extensions.snack import org.kiwix.kiwixmobile.core.extensions.toast @@ -79,7 +76,7 @@ class KiwixReaderFragment : CoreReaderFragment() { }) } activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) - activity.setupDrawerToggle(true) + activity.enableLeftDrawer() openPageInBookFromNavigationArguments() } @@ -147,11 +144,6 @@ class KiwixReaderFragment : CoreReaderFragment() { openZimFile(zimReaderSource) } - override fun loadDrawerViews() { - // drawerLayout = requireActivity().findViewById(R.id.navigation_container) - // tableDrawerRightContainer = requireActivity().findViewById(R.id.reader_drawer_nav_view) - } - override fun openHomeScreen() { Handler(Looper.getMainLooper()).postDelayed({ if (webViewList.isEmpty()) { @@ -174,9 +166,8 @@ class KiwixReaderFragment : CoreReaderFragment() { * @see closeAllTabs */ override fun hideTabSwitcher(shouldCloseZimBook: Boolean) { - activity?.setupDrawerToggle(true) + enableLeftDrawer() (requireActivity() as CoreMainActivity).showBottomAppBar() - setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED) if (webViewList.isEmpty()) { readerMenuState?.hideTabSwitcher() exitBook(shouldCloseZimBook) diff --git a/app/src/main/java/org/kiwix/kiwixmobile/ui/KiwixNavGraph.kt b/app/src/main/java/org/kiwix/kiwixmobile/ui/KiwixNavGraph.kt index f033c495e..50744e07e 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/ui/KiwixNavGraph.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/ui/KiwixNavGraph.kt @@ -74,6 +74,7 @@ import org.kiwix.kiwixmobile.nav.destination.reader.KiwixReaderFragment import org.kiwix.kiwixmobile.settings.KiwixSettingsFragment import org.kiwix.kiwixmobile.webserver.ZimHostFragment +@Suppress("LongMethod") @Composable fun KiwixNavGraph( navController: NavHostController, diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/ActivityExtensions.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/ActivityExtensions.kt index 165d5dd02..9f54a6fdc 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/ActivityExtensions.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/ActivityExtensions.kt @@ -95,9 +95,6 @@ object ActivityExtensions { val Activity.cachedComponent: CoreActivityComponent get() = coreMainActivity.cachedComponent - fun Activity.setupDrawerToggle(shouldEnableRightDrawer: Boolean = false) = - coreMainActivity.setupDrawerToggle(shouldEnableRightDrawer) - fun Activity.navigate(route: String, navOptions: NavOptions? = null) { coreMainActivity.navigate(route, navOptions) } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/ViewExtensions.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/ViewExtensions.kt index e0d8dfec3..9f7cbb983 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/ViewExtensions.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/ViewExtensions.kt @@ -21,16 +21,13 @@ package org.kiwix.kiwixmobile.core.extensions import android.annotation.SuppressLint import android.os.Build import android.view.View -import android.view.ViewGroup import android.view.Window import android.view.WindowManager import androidx.annotation.ColorInt import androidx.appcompat.widget.TooltipCompat -import androidx.core.view.ViewCompat import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsControllerCompat -import androidx.core.view.updateLayoutParams import com.google.android.material.snackbar.BaseTransientBottomBar import com.google.android.material.snackbar.Snackbar @@ -130,31 +127,3 @@ fun View.closeFullScreenMode(window: Window) { clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) } } - -/** - * Applies edge-to-edge insets to the current view by adjusting its margins - * to account for system bars and display cutouts (e.g., status bar, navigation bar, and notches). - * - * This method ensures that the view avoids overlapping with system UI components by dynamically - * setting margins based on the insets provided by the system. - * - * Usage: Call this method on any view to apply edge-to-edge handling. - */ -fun View?.applyEdgeToEdgeInsets() { - this?.let { - ViewCompat.setOnApplyWindowInsetsListener(it) { view, windowInsets -> - val systemBarsInsets = - windowInsets.getInsets( - WindowInsetsCompat.Type.displayCutout() or - WindowInsetsCompat.Type.systemBars() - ) - view.updateLayoutParams { - topMargin = systemBarsInsets.top - leftMargin = systemBarsInsets.left - bottomMargin = systemBarsInsets.bottom - rightMargin = systemBarsInsets.right - } - WindowInsetsCompat.CONSUMED - } - } -} 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 b7a2f802f..9fc319715 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 @@ -127,17 +127,13 @@ abstract class CoreMainActivity : BaseActivity(), WebViewProvider { /** * Manages the enabling/disabling the left drawer */ - protected val enableLeftDrawer = mutableStateOf(true) + val enableLeftDrawer = mutableStateOf(true) /** * For managing the the showing/hiding the bottomAppBar when scrolling. */ @OptIn(ExperimentalMaterial3Api::class) var bottomAppBarScrollBehaviour: BottomAppBarScrollBehavior? = null - - // abstract val drawerContainerLayout: DrawerLayout - // abstract val drawerNavView: NavigationView - // abstract val readerTableOfContentsDrawer: NavigationView abstract val bookmarksFragmentRoute: String abstract val settingsFragmentRoute: String abstract val historyFragmentRoute: String @@ -145,8 +141,6 @@ abstract class CoreMainActivity : BaseActivity(), WebViewProvider { abstract val helpFragmentRoute: String abstract val cachedComponent: CoreActivityComponent abstract val topLevelDestinationsRoute: Set - - // abstract val navHostContainer: FragmentContainerView abstract val mainActivity: AppCompatActivity abstract val appName: String @@ -200,15 +194,11 @@ abstract class CoreMainActivity : BaseActivity(), WebViewProvider { override fun onStart() { super.onStart() - setDialogHostToActivity(alertDialogShower) externalLinkOpener.setAlertDialogShower(alertDialogShower) rateDialogHandler.setAlertDialogShower(alertDialogShower) downloadMonitor.startMonitoringDownload() stopDownloadServiceIfRunning() rateDialogHandler.checkForRateDialog(getIconResId()) - // navController.addOnDestinationChangedListener { _, destination, _ -> - // configureActivityBasedOn(destination) - // } } /** @@ -302,59 +292,12 @@ abstract class CoreMainActivity : BaseActivity(), WebViewProvider { override fun onSupportNavigateUp(): Boolean = navController.navigateUp() || super.onSupportNavigateUp() - open fun setupDrawerToggle(shouldEnableRightDrawer: Boolean = false) { + fun enableLeftDrawer() { enableLeftDrawer.value = true - // Set the initial contentDescription to the hamburger icon. - // This method is called from various locations after modifying the navigationIcon. - // For example, we previously changed this icon/contentDescription to the "+" button - // when opening the tabSwitcher. After closing the tabSwitcher, we reset the - // contentDescription to the default hamburger icon. - // Todo we will refactore this when migrating the CoreMainActivity. - // toolbar.getToolbarNavigationIcon()?.setToolTipWithContentDescription( - // getString(R.string.open_drawer) - // ) - // drawerToggle = - // ActionBarDrawerToggle( - // this, - // drawerContainerLayout, - // R.string.open_drawer, - // R.string.close_drawer - // ) - // drawerToggle?.let { - // drawerContainerLayout.addDrawerListener(it) - // it.syncState() - // } - // drawerContainerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED) - // if (shouldEnableRightDrawer) { - // // Enable the right drawer - // drawerContainerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, GravityCompat.END) - // } } - open fun disableDrawer(disableRightDrawer: Boolean = true) { + open fun disableLeftDrawer() { enableLeftDrawer.value = false - // drawerToggle?.isDrawerIndicatorEnabled = false - // drawerContainerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) - // if (disableRightDrawer) { - // // Disable the right drawer - // drawerContainerLayout.setDrawerLockMode( - // DrawerLayout.LOCK_MODE_LOCKED_CLOSED, - // GravityCompat.END - // ) - // } - } - - open fun onNavigationItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - R.id.menu_support_kiwix -> openSupportKiwixExternalLink() - R.id.menu_settings -> openSettings() - R.id.menu_help -> openHelpFragment() - R.id.menu_notes -> openNotes() - R.id.menu_history -> openHistory() - R.id.menu_bookmarks_list -> openBookmarks() - else -> return false - } - return true } protected fun openHelpFragment() { @@ -492,7 +435,7 @@ abstract class CoreMainActivity : BaseActivity(), WebViewProvider { protected fun handleDrawerOnNavigation() { closeNavigationDrawer() - disableDrawer() + disableLeftDrawer() } private fun setMainActivityToCoreApp() { @@ -592,7 +535,6 @@ abstract class CoreMainActivity : BaseActivity(), WebViewProvider { protected abstract fun getIconResId(): Int abstract val readerFragmentRoute: String abstract fun createApplicationShortcuts() - abstract fun setDialogHostToActivity(alertDialogShower: AlertDialogShower) abstract fun hideBottomAppBar() abstract fun showBottomAppBar() } 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 85b4fae43..e682cb337 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 @@ -68,8 +68,6 @@ 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.drawerlayout.widget.DrawerLayout import androidx.lifecycle.Observer import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.RecyclerView @@ -193,8 +191,6 @@ abstract class CoreReaderFragment : protected val webViewList = mutableStateListOf() private val webUrlsFlow = MutableStateFlow("") - var drawerLayout: DrawerLayout? = null - @JvmField @Inject var sharedPreferenceUtil: SharedPreferenceUtil? = null @@ -490,7 +486,6 @@ abstract class CoreReaderFragment : } handleLocaleCheck() initHideBackToTopTimer() - loadDrawerViews() addFileReader() activity?.let { compatCallback = CompatFindActionModeCallback(it) @@ -561,16 +556,28 @@ abstract class CoreReaderFragment : string.open_drawer } - private fun navigationIconClick() { + /** + * Handles clicks on the navigation icon. + * - If the tab switcher is active, triggers the home menu action. + * - Otherwise, toggles the navigation drawer: opens it if closed, closes it if open. + * + * Subclasses like CustomReaderFragment can override this method to provide custom behavior, + * such as disabling the hamburger icon click when the sidebar is configured to be hidden. + * + * WARNING: If modifying this method, ensure thorough testing with custom apps + * to verify proper functionality. + */ + open fun navigationIconClick() { if (readerMenuState?.isInTabSwitcher == true) { onHomeMenuClicked() + return + } + + val activity = activity as CoreMainActivity + if (activity.navigationDrawerIsOpen()) { + activity.closeNavigationDrawer() } else { - val activity = activity as CoreMainActivity - if (activity.navigationDrawerIsOpen()) { - activity.closeNavigationDrawer() - } else { - activity.openNavigationDrawer() - } + activity.openNavigationDrawer() } } @@ -616,13 +623,6 @@ abstract class CoreReaderFragment : } } - /** - * Abstract method to be implemented by subclasses for loading drawer-related views. - * Subclasses like CustomReaderFragment and KiwixReaderFragment should override this method - * to set up specific views for both the left and right drawers, such as custom containers - * or navigation views. - */ - protected abstract fun loadDrawerViews() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -672,10 +672,9 @@ abstract class CoreReaderFragment : private fun showTabSwitcher() { (requireActivity() as CoreMainActivity).apply { - disableDrawer() + disableLeftDrawer() hideBottomAppBar() } - setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) readerScreenState.update { copy( shouldShowBottomAppBar = false, @@ -716,9 +715,8 @@ abstract class CoreReaderFragment : * as closing the ZIM book would require reloading the ZIM file, which can be a resource-intensive operation. */ protected open fun hideTabSwitcher(shouldCloseZimBook: Boolean = true) { - setUpDrawerToggle() + enableLeftDrawer() (requireActivity() as CoreMainActivity).showBottomAppBar() - setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED) readerScreenState.update { copy( shouldShowBottomAppBar = true, @@ -730,20 +728,15 @@ abstract class CoreReaderFragment : selectTab(currentWebViewIndex) } - open fun setUpDrawerToggle() { - (requireActivity() as CoreMainActivity).setupDrawerToggle(true) - } - /** - * Sets the lock mode for the drawer, controlling whether the drawer can be opened or closed. - * Subclasses like CustomReaderFragment override this method to provide custom - * behavior, such as disabling the sidebar when configured not to show it. + * Enables the activity's left drawer, allowing it to be opened by clicking the hamburger icon. + * Subclasses like CustomReaderFragment can override this method to customize the behavior, + * for example, to disable the sidebar when it shouldn't be shown. * - * WARNING: If modifying this method, ensure thorough testing with custom apps - * to verify proper functionality. + * WARNING: If you modify this method, thoroughly test it in custom apps to ensure it works correctly. */ - protected open fun setDrawerLockMode(lockMode: Int) { - drawerLayout?.setDrawerLockMode(lockMode) + open fun enableLeftDrawer() { + (requireActivity() as CoreMainActivity).enableLeftDrawer() } private fun goBack() { @@ -873,8 +866,8 @@ abstract class CoreReaderFragment : return FragmentActivityExtensions.Super.ShouldNotCall } - drawerLayout?.isDrawerOpen(GravityCompat.END) == true -> { - drawerLayout?.closeDrawers() + shouldTableOfContentDrawer.value -> { + shouldTableOfContentDrawer.update { false } return FragmentActivityExtensions.Super.ShouldNotCall } @@ -1108,7 +1101,6 @@ abstract class CoreReaderFragment : private fun unBindViewsAndBinding() { compatCallback?.finish() compatCallback = null - drawerLayout = null } private fun updateTableOfContents() { @@ -1484,13 +1476,12 @@ abstract class CoreReaderFragment : shouldShowBottomAppBar = false ) } - (requireActivity() as CoreMainActivity).disableDrawer(false) + (requireActivity() as CoreMainActivity).disableLeftDrawer() } else { readerScreenState.update { copy(fullScreenItem = fullScreenItem.copy(first = false)) } if (!isInFullScreenMode()) { readerScreenState.update { copy(shouldShowBottomAppBar = true) } - setUpDrawerToggle() - setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED) + enableLeftDrawer() } } } @@ -1498,7 +1489,7 @@ abstract class CoreReaderFragment : @Suppress("MagicNumber") protected open fun openFullScreen() { (requireActivity() as CoreMainActivity).apply { - disableDrawer(false) + disableLeftDrawer() hideBottomAppBar() } readerScreenState.update { @@ -1518,9 +1509,8 @@ abstract class CoreReaderFragment : @Suppress("MagicNumber") open fun closeFullScreen() { - setUpDrawerToggle() + enableLeftDrawer() (requireActivity() as CoreMainActivity).showBottomAppBar() - setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED) sharedPreferenceUtil?.putPrefFullScreen(false) updateBottomToolbarVisibility() val window = requireActivity().window @@ -1982,7 +1972,9 @@ abstract class CoreReaderFragment : @Suppress("MagicNumber") private fun contentsDrawerHint() { - drawerLayout?.postDelayed({ drawerLayout?.openDrawer(GravityCompat.END) }, 500) + Handler(Looper.getMainLooper()).postDelayed({ + shouldTableOfContentDrawer.update { true } + }, 500) alertDialogShower?.show(KiwixDialog.ContentsDrawerHint) } 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 7a31888d1..af6e483df 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 @@ -169,7 +169,7 @@ const val CLOSE_ALL_TABS_BUTTON_TESTING_TAG = "closeAllTabsButtonTestingTag" const val TAB_TITLE_TESTING_TAG = "tabTitleTestingTag" @OptIn(ExperimentalMaterial3Api::class) -@Suppress("ComposableLambdaParameterNaming") +@Suppress("ComposableLambdaParameterNaming", "LongMethod") @Composable fun ReaderScreen( state: ReaderScreenState, @@ -305,6 +305,7 @@ private fun ReaderContentLayout( } } +@Suppress("LongMethod", "UnsafeCallOnNullableType") @Composable fun TableDrawerSheet( title: String, @@ -372,7 +373,7 @@ fun TableDrawerSheet( "document.getElementById('$targetId')?.scrollIntoView();", null ) - delay(100) + delay(HUNDERED.toLong()) webViewScrollState.value = ScrollState(selectedWebView?.scrollY ?: ZERO) scrollToSectionIndex = null showTableOfContentDrawer.update { false } 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 319d4a34c..18bba6130 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 @@ -20,178 +20,64 @@ package org.kiwix.kiwixmobile.custom.main import android.content.Intent import android.os.Bundle -import android.view.MenuItem +import androidx.activity.compose.setContent import androidx.appcompat.app.AppCompatActivity +import androidx.compose.material3.DrawerValue +import androidx.compose.material3.rememberDrawerState +import androidx.compose.runtime.rememberCoroutineScope import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutManagerCompat import androidx.core.graphics.drawable.IconCompat import androidx.core.net.toUri -import androidx.drawerlayout.widget.DrawerLayout -import androidx.navigation.NavController -import androidx.navigation.fragment.NavHostFragment -import com.google.android.material.navigation.NavigationView +import androidx.navigation.compose.rememberNavController import org.kiwix.kiwixmobile.core.CoreApp import org.kiwix.kiwixmobile.core.R.drawable import org.kiwix.kiwixmobile.core.R.string -import org.kiwix.kiwixmobile.core.extensions.applyEdgeToEdgeInsets import org.kiwix.kiwixmobile.core.extensions.browserIntent -import org.kiwix.kiwixmobile.core.extensions.getDialogHostComposeView import org.kiwix.kiwixmobile.core.main.ACTION_NEW_TAB import org.kiwix.kiwixmobile.core.main.CoreMainActivity import org.kiwix.kiwixmobile.core.main.DrawerMenuItem import org.kiwix.kiwixmobile.core.main.NEW_TAB_SHORTCUT_ID -import org.kiwix.kiwixmobile.core.utils.dialog.AlertDialogShower +import org.kiwix.kiwixmobile.core.utils.dialog.DialogHost import org.kiwix.kiwixmobile.custom.BuildConfig import org.kiwix.kiwixmobile.custom.R import org.kiwix.kiwixmobile.custom.customActivityComponent -import org.kiwix.kiwixmobile.custom.databinding.ActivityCustomMainBinding class CustomMainActivity : CoreMainActivity() { - override val navController: NavController by lazy { - ( - supportFragmentManager.findFragmentById( - R.id.custom_nav_controller - ) as NavHostFragment - ) - .navController - } - override val drawerContainerLayout: DrawerLayout by lazy { - activityCustomMainBinding.customDrawerContainer - } - override val drawerNavView: NavigationView by lazy { activityCustomMainBinding.drawerNavView } - override val readerTableOfContentsDrawer: NavigationView by lazy { - activityCustomMainBinding.activityMainNavView - } - - override val navHostContainer by lazy { - activityCustomMainBinding.customNavController - } - override val mainActivity: AppCompatActivity by lazy { this } override val appName: String by lazy { getString(R.string.app_name) } - override val searchFragmentResId: Int = R.id.searchFragment - override val bookmarksFragmentResId: Int = R.id.bookmarksFragment - override val settingsFragmentResId: Int = R.id.customSettingsFragment - override val readerFragmentResId: Int = R.id.customReaderFragment - override val historyFragmentResId: Int = R.id.historyFragment - override val notesFragmentResId: Int = R.id.notesFragment - override val helpFragmentResId: Int = R.id.helpFragment + override val searchFragmentRoute: String = CustomDestination.Search.route + override val bookmarksFragmentRoute: String = CustomDestination.Bookmarks.route + override val settingsFragmentRoute: String = CustomDestination.Settings.route + override val readerFragmentRoute: String = CustomDestination.Reader.route + override val historyFragmentRoute: String = CustomDestination.History.route + override val notesFragmentRoute: String = CustomDestination.Notes.route + override val helpFragmentRoute: String = CustomDestination.Help.route override val cachedComponent by lazy { customActivityComponent } - override val topLevelDestinations = - setOf(R.id.customReaderFragment) - - lateinit var activityCustomMainBinding: ActivityCustomMainBinding + override val topLevelDestinationsRoute = setOf(CustomDestination.Reader.route) override fun onCreate(savedInstanceState: Bundle?) { customActivityComponent.inject(this) super.onCreate(savedInstanceState) - activityCustomMainBinding = ActivityCustomMainBinding.inflate(layoutInflater) - setContentView(activityCustomMainBinding.root) - activityCustomMainBinding.root.applyEdgeToEdgeInsets() + setContent { + navController = rememberNavController() + leftDrawerState = rememberDrawerState(DrawerValue.Closed) + uiCoroutineScope = rememberCoroutineScope() + CustomMainActivityScreen( + navController = navController, + leftDrawerContent = leftDrawerMenu, + topLevelDestinationsRoute = topLevelDestinationsRoute, + leftDrawerState = leftDrawerState, + enableLeftDrawer = enableLeftDrawer.value + ) + DialogHost(alertDialogShower) + } if (savedInstanceState != null) { return } } - override fun onStart() { - super.onStart() - navController.addOnDestinationChangedListener { _, destination, _ -> - if (destination.id !in topLevelDestinations) { - handleDrawerOnNavigation() - } - } - } - - override fun setupDrawerToggle(shouldEnableRightDrawer: Boolean) { - super.setupDrawerToggle(shouldEnableRightDrawer) - activityCustomMainBinding.drawerNavView.apply { - /** - * Hide the 'ZimHostFragment' option from the navigation menu - * because we are now using fd (FileDescriptor) - * to read the zim file from the asset folder. Currently, - * 'KiwixServer' is unable to host zim files via fd. - * This feature is temporarily removed for custom apps. - * We will re-enable it for custom apps once the issue is resolved. - * For more info see https://github.com/kiwix/kiwix-android/pull/3516, - * https://github.com/kiwix/kiwix-android/issues/4026 - */ - menu.findItem(org.kiwix.kiwixmobile.core.R.id.menu_host_books)?.isVisible = false - /** - * Hide the `HelpFragment` from custom apps. - * We have not removed the relevant code for `HelpFragment` from custom apps. - * If, in the future, we need to display this for all/some custom apps, - * we can either remove the line below or configure it according to the requirements. - * For more information, see https://github.com/kiwix/kiwix-android/issues/3584 - */ - menu.findItem(org.kiwix.kiwixmobile.core.R.id.menu_help)?.isVisible = false - - /** - * If custom app is configured to show the "About app_name app" in navigation - * then show it navigation. "app_name" will be replaced with custom app name. - */ - if (BuildConfig.ABOUT_APP_URL.isNotEmpty()) { - menu.findItem(org.kiwix.kiwixmobile.core.R.id.menu_about_app)?.apply { - title = getString( - org.kiwix.kiwixmobile.core.R.string.menu_about_app, - getString(R.string.app_name) - ) - isVisible = true - } - } - - /** - * If custom app is configured to show the "Support app_name" in navigation - * then show it navigation. "app_name" will be replaced with custom app name. - */ - if (BuildConfig.SUPPORT_URL.isNotEmpty()) { - menu.findItem(org.kiwix.kiwixmobile.core.R.id.menu_support_kiwix)?.apply { - title = - getString( - org.kiwix.kiwixmobile.core.R.string.menu_support_kiwix_for_custom_apps, - getString(R.string.app_name) - ) - isVisible = true - } - } else { - /** - * If custom app is not configured to show the "Support app_name" in navigation - * then hide it from navigation. - */ - menu.findItem(org.kiwix.kiwixmobile.core.R.id.menu_support_kiwix)?.isVisible = false - } - setNavigationItemSelectedListener { item -> - closeNavigationDrawer() - onNavigationItemSelected(item) - } - } - } - - /** - * Overrides the method to configure the click behavior of the "About the app" - * and "Support URL" features. When the "About the app" and "Support URL" - * are enabled in a custom app, this function handles those clicks. - */ - override fun onNavigationItemSelected(item: MenuItem): Boolean { - return when (item.itemId) { - org.kiwix.kiwixmobile.core.R.id.menu_about_app -> { - if (BuildConfig.ABOUT_APP_URL.isNotEmpty()) { - externalLinkOpener.openExternalUrl(BuildConfig.ABOUT_APP_URL.toUri().browserIntent()) - } - true - } - - org.kiwix.kiwixmobile.core.R.id.menu_support_kiwix -> { - if (BuildConfig.SUPPORT_URL.isNotEmpty()) { - externalLinkOpener.openExternalUrl(BuildConfig.SUPPORT_URL.toUri().browserIntent(), false) - } - true - } - - else -> super.onNavigationItemSelected(item) - } - } - override fun getIconResId() = R.mipmap.ic_launcher /** @@ -256,7 +142,10 @@ class CustomMainActivity : CoreMainActivity() { true, onClick = { closeNavigationDrawer() - externalLinkOpener.openExternalUrl(BuildConfig.ABOUT_APP_URL.toUri().browserIntent(), false) + externalLinkOpener.openExternalUrl( + BuildConfig.ABOUT_APP_URL.toUri().browserIntent(), + false + ) } ) } else { @@ -281,12 +170,14 @@ class CustomMainActivity : CoreMainActivity() { ShortcutManagerCompat.addDynamicShortcuts(this, listOf(newTabShortcut)) } - override fun setDialogHostToActivity(alertDialogShower: AlertDialogShower) { - activityCustomMainBinding.root.addView(getDialogHostComposeView(alertDialogShower), 0) - } - override fun openSearch(searchString: String, isOpenedFromTabView: Boolean, isVoice: Boolean) { - // TODO implement when refactoring the custom app UI. + navigate( + CustomDestination.Search.createRoute( + searchString = searchString, + isOpenedFromTabView = isOpenedFromTabView, + isVoice = isVoice + ) + ) } override fun hideBottomAppBar() { diff --git a/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomMainActivityScreen.kt b/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomMainActivityScreen.kt new file mode 100644 index 000000000..2d625bb45 --- /dev/null +++ b/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomMainActivityScreen.kt @@ -0,0 +1,78 @@ +/* + * 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.custom.main + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.material3.DrawerState +import androidx.compose.material3.ModalNavigationDrawer +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.navigation.NavHostController +import androidx.navigation.compose.currentBackStackEntryAsState +import org.kiwix.kiwixmobile.core.main.DrawerMenuGroup +import org.kiwix.kiwixmobile.core.main.LeftDrawerMenu +import org.kiwix.kiwixmobile.core.ui.theme.KiwixTheme + +@Composable +fun CustomMainActivityScreen( + navController: NavHostController, + leftDrawerContent: List, + topLevelDestinationsRoute: Set, + leftDrawerState: DrawerState, + enableLeftDrawer: Boolean, +) { + val navBackStackEntry by navController.currentBackStackEntryAsState() + val currentRoute = navBackStackEntry?.destination?.route + KiwixTheme { + ModalNavigationDrawer( + drawerState = leftDrawerState, + drawerContent = { + Column(modifier = Modifier.fillMaxSize()) { + LeftDrawerMenu(leftDrawerContent) + } + }, + gesturesEnabled = enableLeftDrawer && + currentRoute in topLevelDestinationsRoute && + // Fixing the webView scrolling is lagging when navigation gesture is enabled, + // since navigation consumes the swipes event makes webView lagging. + // However, on reader screen navigation drawer can be opened by clicking + // on the hamburger button. + (currentRoute != CustomDestination.Reader.route || leftDrawerState.isOpen) + ) { + Scaffold( + modifier = Modifier + .fillMaxSize() + .systemBarsPadding() + ) { paddingValues -> + Box(modifier = Modifier.padding(paddingValues)) { + CustomNavGraph( + navController = navController, + modifier = Modifier.fillMaxSize() + ) + } + } + } + } +} diff --git a/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomNavGraph.kt b/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomNavGraph.kt new file mode 100644 index 000000000..09dbc48d5 --- /dev/null +++ b/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomNavGraph.kt @@ -0,0 +1,248 @@ +/* + * 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.custom.main + +import android.net.Uri +import android.os.Bundle +import android.view.View +import androidx.appcompat.app.AppCompatActivity +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.viewinterop.AndroidView +import androidx.core.view.doOnAttach +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentContainerView +import androidx.fragment.app.commit +import androidx.navigation.NavHostController +import androidx.navigation.NavType +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.navArgument +import org.kiwix.kiwixmobile.core.main.BOOKMARK_FRAGMENT +import org.kiwix.kiwixmobile.core.main.DOWNLOAD_FRAGMENT +import org.kiwix.kiwixmobile.core.main.FIND_IN_PAGE_SEARCH_STRING +import org.kiwix.kiwixmobile.core.main.HELP_FRAGMENT +import org.kiwix.kiwixmobile.core.main.HISTORY_FRAGMENT +import org.kiwix.kiwixmobile.core.main.NOTES_FRAGMENT +import org.kiwix.kiwixmobile.core.main.PAGE_URL_KEY +import org.kiwix.kiwixmobile.core.main.READER_FRAGMENT +import org.kiwix.kiwixmobile.core.main.SEARCH_FRAGMENT +import org.kiwix.kiwixmobile.core.main.SETTINGS_FRAGMENT +import org.kiwix.kiwixmobile.core.main.SHOULD_OPEN_IN_NEW_TAB +import org.kiwix.kiwixmobile.core.main.ZIM_FILE_URI_KEY +import org.kiwix.kiwixmobile.core.main.reader.SEARCH_ITEM_TITLE_KEY +import org.kiwix.kiwixmobile.core.page.bookmark.BookmarksFragment +import org.kiwix.kiwixmobile.core.page.history.HistoryFragment +import org.kiwix.kiwixmobile.core.page.notes.NotesFragment +import org.kiwix.kiwixmobile.core.search.NAV_ARG_SEARCH_STRING +import org.kiwix.kiwixmobile.core.search.SearchFragment +import org.kiwix.kiwixmobile.core.utils.EXTRA_IS_WIDGET_VOICE +import org.kiwix.kiwixmobile.core.utils.TAG_FROM_TAB_SWITCHER +import org.kiwix.kiwixmobile.custom.download.CustomDownloadFragment +import org.kiwix.kiwixmobile.custom.help.CustomHelpFragment +import org.kiwix.kiwixmobile.custom.settings.CustomSettingsFragment + +@Suppress("LongMethod") +@Composable +fun CustomNavGraph( + navController: NavHostController, + modifier: Modifier = Modifier +) { + NavHost( + navController = navController, + startDestination = CustomDestination.Reader.route, + modifier = modifier + ) { + composable( + route = CustomDestination.Reader.route, + arguments = listOf( + navArgument(FIND_IN_PAGE_SEARCH_STRING) { + type = NavType.StringType + defaultValue = "" + }, + navArgument(PAGE_URL_KEY) { + type = NavType.StringType + defaultValue = "" + }, + navArgument(SHOULD_OPEN_IN_NEW_TAB) { + type = NavType.BoolType + defaultValue = false + } + ) + ) { backStackEntry -> + val findInPageSearchString = + backStackEntry.arguments?.getString(FIND_IN_PAGE_SEARCH_STRING).orEmpty() + val pageUrl = backStackEntry.arguments?.getString(PAGE_URL_KEY).orEmpty() + val shouldOpenInNewTab = backStackEntry.arguments?.getBoolean(SHOULD_OPEN_IN_NEW_TAB) ?: false + + FragmentContainer { + CustomReaderFragment().apply { + arguments = Bundle().apply { + putString(FIND_IN_PAGE_SEARCH_STRING, findInPageSearchString) + putString(PAGE_URL_KEY, pageUrl) + putBoolean(SHOULD_OPEN_IN_NEW_TAB, shouldOpenInNewTab) + } + } + } + } + composable(CustomDestination.History.route) { + FragmentContainer { + HistoryFragment() + } + } + composable(CustomDestination.Notes.route) { + FragmentContainer { + NotesFragment() + } + } + composable(CustomDestination.Bookmarks.route) { + FragmentContainer { + BookmarksFragment() + } + } + composable(CustomDestination.Help.route) { + FragmentContainer { + CustomHelpFragment() + } + } + composable(CustomDestination.Settings.route) { + FragmentContainer { + CustomSettingsFragment() + } + } + composable(CustomDestination.Downloads.route) { + FragmentContainer { + CustomDownloadFragment() + } + } + composable( + route = CustomDestination.Search.route, + arguments = listOf( + navArgument(NAV_ARG_SEARCH_STRING) { + type = NavType.StringType + defaultValue = "" + }, + navArgument(TAG_FROM_TAB_SWITCHER) { + type = NavType.BoolType + defaultValue = false + }, + navArgument(EXTRA_IS_WIDGET_VOICE) { + type = NavType.BoolType + defaultValue = false + } + ) + ) { backStackEntry -> + val searchString = backStackEntry.arguments?.getString(NAV_ARG_SEARCH_STRING).orEmpty() + val isOpenedFromTabSwitcher = + backStackEntry.arguments?.getBoolean(TAG_FROM_TAB_SWITCHER) ?: false + val isVoice = backStackEntry.arguments?.getBoolean(EXTRA_IS_WIDGET_VOICE) ?: false + FragmentContainer { + SearchFragment().apply { + arguments = Bundle().apply { + putString(NAV_ARG_SEARCH_STRING, searchString) + putBoolean(TAG_FROM_TAB_SWITCHER, isOpenedFromTabSwitcher) + putBoolean(EXTRA_IS_WIDGET_VOICE, isVoice) + } + } + } + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun FragmentContainer( + fragmentProvider: () -> Fragment +) { + val context = LocalContext.current + val fragmentManager = remember { + (context as AppCompatActivity).supportFragmentManager + } + val viewId = remember { View.generateViewId() } + + AndroidView( + modifier = Modifier.fillMaxSize(), + factory = { ctx -> + FragmentContainerView(ctx).apply { + id = viewId + doOnAttach { + fragmentManager.commit { + if (fragmentManager.findFragmentById(viewId) == null) { + add(viewId, fragmentProvider()) + } + } + } + } + } + ) +} + +sealed class CustomDestination(val route: String) { + object Reader : CustomDestination( + READER_FRAGMENT + + "?$ZIM_FILE_URI_KEY={$ZIM_FILE_URI_KEY}" + + "&$FIND_IN_PAGE_SEARCH_STRING={$FIND_IN_PAGE_SEARCH_STRING}" + + "&$PAGE_URL_KEY={$PAGE_URL_KEY}" + + "&$SHOULD_OPEN_IN_NEW_TAB={$SHOULD_OPEN_IN_NEW_TAB}" + + "&$SEARCH_ITEM_TITLE_KEY={$SEARCH_ITEM_TITLE_KEY}" + ) { + fun createRoute( + zimFileUri: String = "", + findInPageSearchString: String = "", + pageUrl: String = "", + shouldOpenInNewTab: Boolean = false, + searchItemTitle: String = "" + ): String { + return READER_FRAGMENT + + "?$ZIM_FILE_URI_KEY=${Uri.encode(zimFileUri)}" + + "&$FIND_IN_PAGE_SEARCH_STRING=${Uri.encode(findInPageSearchString)}" + + "&$PAGE_URL_KEY=${Uri.encode(pageUrl)}" + + "&$SHOULD_OPEN_IN_NEW_TAB=$shouldOpenInNewTab" + + "&$SEARCH_ITEM_TITLE_KEY=${Uri.encode(searchItemTitle)}" + } + } + + object History : CustomDestination(HISTORY_FRAGMENT) + object Notes : CustomDestination(NOTES_FRAGMENT) + object Bookmarks : CustomDestination(BOOKMARK_FRAGMENT) + object Help : CustomDestination(HELP_FRAGMENT) + object Settings : CustomDestination(SETTINGS_FRAGMENT) + object Downloads : CustomDestination(DOWNLOAD_FRAGMENT) + object Search : CustomDestination( + SEARCH_FRAGMENT + + "?$NAV_ARG_SEARCH_STRING={$NAV_ARG_SEARCH_STRING}" + + "&$TAG_FROM_TAB_SWITCHER={$TAG_FROM_TAB_SWITCHER}" + + "&$EXTRA_IS_WIDGET_VOICE={$EXTRA_IS_WIDGET_VOICE}" + ) { + fun createRoute( + searchString: String = "", + isOpenedFromTabView: Boolean = false, + isVoice: Boolean = false + ): String { + return SEARCH_FRAGMENT + + "?$NAV_ARG_SEARCH_STRING=$searchString" + + "&$TAG_FROM_TAB_SWITCHER=$isOpenedFromTabView" + + "&$EXTRA_IS_WIDGET_VOICE=$isVoice" + } + } +} 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 984b1c94f..15176467b 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 @@ -21,20 +21,19 @@ package org.kiwix.kiwixmobile.custom.main import android.app.Dialog import android.os.Bundle import android.view.Menu -import android.view.MenuInflater import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Menu import androidx.compose.ui.graphics.Color import androidx.core.net.toUri -import androidx.drawerlayout.widget.DrawerLayout -import com.google.android.material.bottomnavigation.BottomNavigationView +import androidx.navigation.NavOptions import kotlinx.coroutines.launch import org.kiwix.kiwixmobile.core.base.BaseActivity import org.kiwix.kiwixmobile.core.extensions.browserIntent import org.kiwix.kiwixmobile.core.extensions.isFileExist 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.reader.ReaderMenuState import org.kiwix.kiwixmobile.core.main.reader.RestoreOrigin @@ -75,10 +74,10 @@ class CustomReaderFragment : CoreReaderFragment() { } if (isAdded) { - setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED) + enableLeftDrawer() with(activity as AppCompatActivity) { supportActionBar?.setDisplayHomeAsUpEnabled(true) - setUpDrawerToggle() + enableLeftDrawer() } loadPageFromNavigationArguments() if (BuildConfig.DISABLE_EXTERNAL_LINK) { @@ -151,6 +150,28 @@ class CustomReaderFragment : CoreReaderFragment() { } } + /** + * Handles clicks on the navigation icon in custom apps. + * - If the tab switcher is active, triggers the home menu action. + * - Otherwise, toggles the navigation drawer: closes it if open; opens it only if the sidebar is enabled. + * + * This override customizes the default behavior by preventing the drawer from opening + * when the sidebar is disabled in the app configuration. + */ + override fun navigationIconClick() { + if (readerMenuState?.isInTabSwitcher == true) { + onHomeMenuClicked() + return + } + + val activity = activity as CoreMainActivity + if (activity.navigationDrawerIsOpen()) { + activity.closeNavigationDrawer() + } else if (!BuildConfig.DISABLE_SIDEBAR) { + activity.openNavigationDrawer() + } + } + private fun loadPageFromNavigationArguments() { val args = CustomReaderFragmentArgs.fromBundle(requireArguments()) if (args.pageUrl.isNotEmpty()) { @@ -188,18 +209,16 @@ class CustomReaderFragment : CoreReaderFragment() { } /** - * Sets the locking mode for the sidebar in a custom app. If the app is configured not to show the sidebar, - * this function disables the sidebar by locking it in the closed position through the parent class. - * https://developer.android.com/reference/kotlin/androidx/drawerlayout/widget/DrawerLayout#LOCK_MODE_LOCKED_CLOSED() + * Enables or disables the sidebar in a custom app based on the configuration. + * If the app is configured to disable the sidebar, this method disables it; + * otherwise, it enables the sidebar. */ - override fun setDrawerLockMode(lockMode: Int) { - super.setDrawerLockMode( - if (BuildConfig.DISABLE_SIDEBAR) { - DrawerLayout.LOCK_MODE_LOCKED_CLOSED - } else { - lockMode - } - ) + override fun enableLeftDrawer() { + if (BuildConfig.DISABLE_SIDEBAR) { + (requireActivity() as CoreMainActivity).disableLeftDrawer() + } else { + super.enableLeftDrawer() + } } /** @@ -268,8 +287,13 @@ class CustomReaderFragment : CoreReaderFragment() { }, onNoFilesFound = { if (sharedPreferenceUtil?.prefIsTest == false) { - // TODO refactor this when migrating the custom app in compose - // (requireActivity() as CoreMainActivity).navigate(R.id.customDownloadFragment) + val navOptions = NavOptions.Builder() + .setPopUpTo(CustomDestination.Reader.route, true) + .build() + (requireActivity() as CoreMainActivity).navigate( + CustomDestination.Downloads.route, + navOptions + ) } } ) @@ -280,13 +304,6 @@ class CustomReaderFragment : CoreReaderFragment() { if (!it.isFileExist()) it.createNewFile() } - @Suppress("DEPRECATION") - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - super.onCreateOptionsMenu(menu, inflater) - menu.findItem(org.kiwix.kiwixmobile.core.R.id.menu_help)?.isVisible = false - menu.findItem(org.kiwix.kiwixmobile.core.R.id.menu_host_books)?.isVisible = false - } - private fun enforcedLanguage(): Boolean { val currentLocaleCode = Locale.getDefault().toString() if (BuildConfig.ENFORCED_LANG.isNotEmpty() && BuildConfig.ENFORCED_LANG != currentLocaleCode) { @@ -304,17 +321,6 @@ class CustomReaderFragment : CoreReaderFragment() { return false } - /** - * This method is overridden to set the IDs of the `drawerLayout` and `tableDrawerRightContainer` - * specific to the custom module in the `CoreReaderFragment`. Since we have an app and a custom module, - * and `CoreReaderFragment` is a common class for both modules, we set the IDs of the custom module - * in the parent class to ensure proper integration. - */ - override fun loadDrawerViews() { - drawerLayout = requireActivity().findViewById(R.id.custom_drawer_container) - tableDrawerRightContainer = requireActivity().findViewById(R.id.activity_main_nav_view) - } - /** * Overrides the method to create the main menu for the app. The custom app can be configured to disable * features like "read aloud" and "tabs," and this method dynamically generates the menu based on the