mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-04 03:06:41 -04:00
Fixed: The system bar was not correctly showing the icons.
* Fixed: When scrolling, the BottomAppBar was appearing behind the navigation buttons. * Fixed: The hint in the table of contents was not showing on first-time app install. * Fixed: Pressing the back button was immediately exiting the app when the table of contents drawer was open. * Created the `CustomNavGraph` for custom app navigation and refactored related code. * Refactored the logic to dynamically disable the left drawer when a custom app is configured not to show it. * Simplified the code for enabling/disabling the sidebar. * Resolved all lint and Detekt errors.
This commit is contained in:
parent
8afaa8be52
commit
4d97eeebc8
@ -23,7 +23,6 @@ import android.content.res.Configuration
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.view.MenuItem
|
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
@ -50,7 +49,6 @@ import org.kiwix.kiwixmobile.BuildConfig
|
|||||||
import org.kiwix.kiwixmobile.R
|
import org.kiwix.kiwixmobile.R
|
||||||
import org.kiwix.kiwixmobile.core.CoreApp
|
import org.kiwix.kiwixmobile.core.CoreApp
|
||||||
import org.kiwix.kiwixmobile.core.R.drawable
|
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.mipmap
|
||||||
import org.kiwix.kiwixmobile.core.R.string
|
import org.kiwix.kiwixmobile.core.R.string
|
||||||
import org.kiwix.kiwixmobile.core.base.FragmentActivityExtensions
|
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.DrawerMenuItem
|
||||||
import org.kiwix.kiwixmobile.core.main.NEW_TAB_SHORTCUT_ID
|
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.LanguageUtils.Companion.handleLocaleChange
|
||||||
import org.kiwix.kiwixmobile.core.utils.dialog.AlertDialogShower
|
|
||||||
import org.kiwix.kiwixmobile.core.utils.dialog.DialogHost
|
import org.kiwix.kiwixmobile.core.utils.dialog.DialogHost
|
||||||
import org.kiwix.kiwixmobile.kiwixActivityComponent
|
import org.kiwix.kiwixmobile.kiwixActivityComponent
|
||||||
import org.kiwix.kiwixmobile.ui.KiwixDestination
|
import org.kiwix.kiwixmobile.ui.KiwixDestination
|
||||||
@ -72,25 +69,12 @@ import javax.inject.Inject
|
|||||||
const val ACTION_GET_CONTENT = "GET_CONTENT"
|
const val ACTION_GET_CONTENT = "GET_CONTENT"
|
||||||
const val OPENING_ZIM_FILE_DELAY = 300L
|
const val OPENING_ZIM_FILE_DELAY = 300L
|
||||||
const val GET_CONTENT_SHORTCUT_ID = "get_content_shortcut"
|
const val GET_CONTENT_SHORTCUT_ID = "get_content_shortcut"
|
||||||
const val KIWIX_BOTTOM_BAR_ANIMATION_DURATION = 250L
|
|
||||||
|
|
||||||
class KiwixMainActivity : CoreMainActivity() {
|
class KiwixMainActivity : CoreMainActivity() {
|
||||||
private var actionMode: ActionMode? = null
|
private var actionMode: ActionMode? = null
|
||||||
override val cachedComponent by lazy { kiwixActivityComponent }
|
override val cachedComponent by lazy { kiwixActivityComponent }
|
||||||
override val searchFragmentRoute: String = KiwixDestination.Search.route
|
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
|
@Inject lateinit var libkiwixBookOnDisk: LibkiwixBookOnDisk
|
||||||
|
|
||||||
override val mainActivity: AppCompatActivity by lazy { this }
|
override val mainActivity: AppCompatActivity by lazy { this }
|
||||||
@ -288,14 +272,6 @@ class KiwixMainActivity : CoreMainActivity() {
|
|||||||
navigate(KiwixDestination.Reader.createRoute(zimFileUri = path))
|
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(
|
override val zimHostDrawerMenuItem: DrawerMenuItem? = DrawerMenuItem(
|
||||||
title = CoreApp.instance.getString(string.menu_wifi_hotspot),
|
title = CoreApp.instance.getString(string.menu_wifi_hotspot),
|
||||||
iconRes = drawable.ic_mobile_screen_share_24px,
|
iconRes = drawable.ic_mobile_screen_share_24px,
|
||||||
@ -323,7 +299,7 @@ class KiwixMainActivity : CoreMainActivity() {
|
|||||||
override val aboutAppDrawerMenuItem: DrawerMenuItem? = null
|
override val aboutAppDrawerMenuItem: DrawerMenuItem? = null
|
||||||
|
|
||||||
private fun openZimHostFragment() {
|
private fun openZimHostFragment() {
|
||||||
disableDrawer()
|
disableLeftDrawer()
|
||||||
handleDrawerOnNavigation()
|
handleDrawerOnNavigation()
|
||||||
navigate(KiwixDestination.ZimHost.route)
|
navigate(KiwixDestination.ZimHost.route)
|
||||||
}
|
}
|
||||||
@ -336,10 +312,6 @@ class KiwixMainActivity : CoreMainActivity() {
|
|||||||
ShortcutManagerCompat.addDynamicShortcuts(this, dynamicShortcutList())
|
ShortcutManagerCompat.addDynamicShortcuts(this, dynamicShortcutList())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setDialogHostToActivity(alertDialogShower: AlertDialogShower) {
|
|
||||||
// activityKiwixMainBinding.root.addView(getDialogHostComposeView(alertDialogShower), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openSearch(searchString: String, isOpenedFromTabView: Boolean, isVoice: Boolean) {
|
override fun openSearch(searchString: String, isOpenedFromTabView: Boolean, isVoice: Boolean) {
|
||||||
navigate(
|
navigate(
|
||||||
KiwixDestination.Search.createRoute(
|
KiwixDestination.Search.createRoute(
|
||||||
|
@ -22,6 +22,7 @@ import androidx.compose.foundation.layout.Box
|
|||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.systemBarsPadding
|
||||||
import androidx.compose.material3.BottomAppBar
|
import androidx.compose.material3.BottomAppBar
|
||||||
import androidx.compose.material3.BottomAppBarScrollBehavior
|
import androidx.compose.material3.BottomAppBarScrollBehavior
|
||||||
import androidx.compose.material3.DrawerState
|
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.KiwixDestination
|
||||||
import org.kiwix.kiwixmobile.ui.KiwixNavGraph
|
import org.kiwix.kiwixmobile.ui.KiwixNavGraph
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun KiwixMainActivityScreen(
|
fun KiwixMainActivityScreen(
|
||||||
@ -83,28 +85,28 @@ fun KiwixMainActivityScreen(
|
|||||||
// on the hamburger button.
|
// on the hamburger button.
|
||||||
(currentRoute != KiwixDestination.Reader.route || leftDrawerState.isOpen)
|
(currentRoute != KiwixDestination.Reader.route || leftDrawerState.isOpen)
|
||||||
) {
|
) {
|
||||||
Box {
|
Scaffold(
|
||||||
Scaffold(
|
bottomBar = {
|
||||||
bottomBar = {
|
if (shouldShowBottomBar) {
|
||||||
if (shouldShowBottomBar) {
|
BottomNavigationBar(
|
||||||
BottomNavigationBar(
|
|
||||||
navController = navController,
|
|
||||||
bottomAppBarScrollBehaviour = bottomAppBarScrollBehaviour,
|
|
||||||
navBackStackEntry = navBackStackEntry,
|
|
||||||
leftDrawerState = leftDrawerState,
|
|
||||||
uiCoroutineScope = uiCoroutineScope
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
modifier = Modifier.fillMaxSize()
|
|
||||||
) { paddingValues ->
|
|
||||||
Box(modifier = Modifier.padding(paddingValues)) {
|
|
||||||
KiwixNavGraph(
|
|
||||||
navController = navController,
|
navController = navController,
|
||||||
startDestination = startDestination,
|
bottomAppBarScrollBehaviour = bottomAppBarScrollBehaviour,
|
||||||
modifier = Modifier.fillMaxSize()
|
navBackStackEntry = navBackStackEntry,
|
||||||
|
leftDrawerState = leftDrawerState,
|
||||||
|
uiCoroutineScope = uiCoroutineScope
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.systemBarsPadding()
|
||||||
|
) { paddingValues ->
|
||||||
|
Box(modifier = Modifier.padding(paddingValues)) {
|
||||||
|
KiwixNavGraph(
|
||||||
|
navController = navController,
|
||||||
|
startDestination = startDestination,
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,6 @@ import java.util.Locale
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
private const val WAS_IN_ACTION_MODE = "WAS_IN_ACTION_MODE"
|
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"
|
const val LOCAL_FILE_TRANSFER_MENU_BUTTON_TESTING_TAG = "localFileTransferMenuButtonTestingTag"
|
||||||
|
|
||||||
@Suppress("LargeClass")
|
@Suppress("LargeClass")
|
||||||
|
@ -26,10 +26,8 @@ import android.view.MenuInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.drawerlayout.widget.DrawerLayout
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.NavOptions
|
import androidx.navigation.NavOptions
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.kiwix.kiwixmobile.cachedComponent
|
import org.kiwix.kiwixmobile.cachedComponent
|
||||||
import org.kiwix.kiwixmobile.core.R.string
|
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
|
||||||
import org.kiwix.kiwixmobile.core.base.FragmentActivityExtensions.Super.ShouldCall
|
import org.kiwix.kiwixmobile.core.base.FragmentActivityExtensions.Super.ShouldCall
|
||||||
import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO
|
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.isFileExist
|
||||||
import org.kiwix.kiwixmobile.core.extensions.snack
|
import org.kiwix.kiwixmobile.core.extensions.snack
|
||||||
import org.kiwix.kiwixmobile.core.extensions.toast
|
import org.kiwix.kiwixmobile.core.extensions.toast
|
||||||
@ -79,7 +76,7 @@ class KiwixReaderFragment : CoreReaderFragment() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
activity.setupDrawerToggle(true)
|
activity.enableLeftDrawer()
|
||||||
openPageInBookFromNavigationArguments()
|
openPageInBookFromNavigationArguments()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,11 +144,6 @@ class KiwixReaderFragment : CoreReaderFragment() {
|
|||||||
openZimFile(zimReaderSource)
|
openZimFile(zimReaderSource)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadDrawerViews() {
|
|
||||||
// drawerLayout = requireActivity().findViewById(R.id.navigation_container)
|
|
||||||
// tableDrawerRightContainer = requireActivity().findViewById(R.id.reader_drawer_nav_view)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openHomeScreen() {
|
override fun openHomeScreen() {
|
||||||
Handler(Looper.getMainLooper()).postDelayed({
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
if (webViewList.isEmpty()) {
|
if (webViewList.isEmpty()) {
|
||||||
@ -174,9 +166,8 @@ class KiwixReaderFragment : CoreReaderFragment() {
|
|||||||
* @see closeAllTabs
|
* @see closeAllTabs
|
||||||
*/
|
*/
|
||||||
override fun hideTabSwitcher(shouldCloseZimBook: Boolean) {
|
override fun hideTabSwitcher(shouldCloseZimBook: Boolean) {
|
||||||
activity?.setupDrawerToggle(true)
|
enableLeftDrawer()
|
||||||
(requireActivity() as CoreMainActivity).showBottomAppBar()
|
(requireActivity() as CoreMainActivity).showBottomAppBar()
|
||||||
setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
|
|
||||||
if (webViewList.isEmpty()) {
|
if (webViewList.isEmpty()) {
|
||||||
readerMenuState?.hideTabSwitcher()
|
readerMenuState?.hideTabSwitcher()
|
||||||
exitBook(shouldCloseZimBook)
|
exitBook(shouldCloseZimBook)
|
||||||
|
@ -74,6 +74,7 @@ import org.kiwix.kiwixmobile.nav.destination.reader.KiwixReaderFragment
|
|||||||
import org.kiwix.kiwixmobile.settings.KiwixSettingsFragment
|
import org.kiwix.kiwixmobile.settings.KiwixSettingsFragment
|
||||||
import org.kiwix.kiwixmobile.webserver.ZimHostFragment
|
import org.kiwix.kiwixmobile.webserver.ZimHostFragment
|
||||||
|
|
||||||
|
@Suppress("LongMethod")
|
||||||
@Composable
|
@Composable
|
||||||
fun KiwixNavGraph(
|
fun KiwixNavGraph(
|
||||||
navController: NavHostController,
|
navController: NavHostController,
|
||||||
|
@ -95,9 +95,6 @@ object ActivityExtensions {
|
|||||||
val Activity.cachedComponent: CoreActivityComponent
|
val Activity.cachedComponent: CoreActivityComponent
|
||||||
get() = coreMainActivity.cachedComponent
|
get() = coreMainActivity.cachedComponent
|
||||||
|
|
||||||
fun Activity.setupDrawerToggle(shouldEnableRightDrawer: Boolean = false) =
|
|
||||||
coreMainActivity.setupDrawerToggle(shouldEnableRightDrawer)
|
|
||||||
|
|
||||||
fun Activity.navigate(route: String, navOptions: NavOptions? = null) {
|
fun Activity.navigate(route: String, navOptions: NavOptions? = null) {
|
||||||
coreMainActivity.navigate(route, navOptions)
|
coreMainActivity.navigate(route, navOptions)
|
||||||
}
|
}
|
||||||
|
@ -21,16 +21,13 @@ package org.kiwix.kiwixmobile.core.extensions
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.Window
|
import android.view.Window
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import androidx.annotation.ColorInt
|
import androidx.annotation.ColorInt
|
||||||
import androidx.appcompat.widget.TooltipCompat
|
import androidx.appcompat.widget.TooltipCompat
|
||||||
import androidx.core.view.ViewCompat
|
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.WindowInsetsControllerCompat
|
import androidx.core.view.WindowInsetsControllerCompat
|
||||||
import androidx.core.view.updateLayoutParams
|
|
||||||
import com.google.android.material.snackbar.BaseTransientBottomBar
|
import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
|
||||||
@ -130,31 +127,3 @@ fun View.closeFullScreenMode(window: Window) {
|
|||||||
clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
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<ViewGroup.MarginLayoutParams> {
|
|
||||||
topMargin = systemBarsInsets.top
|
|
||||||
leftMargin = systemBarsInsets.left
|
|
||||||
bottomMargin = systemBarsInsets.bottom
|
|
||||||
rightMargin = systemBarsInsets.right
|
|
||||||
}
|
|
||||||
WindowInsetsCompat.CONSUMED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -127,17 +127,13 @@ abstract class CoreMainActivity : BaseActivity(), WebViewProvider {
|
|||||||
/**
|
/**
|
||||||
* Manages the enabling/disabling the left drawer
|
* 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.
|
* For managing the the showing/hiding the bottomAppBar when scrolling.
|
||||||
*/
|
*/
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
var bottomAppBarScrollBehaviour: BottomAppBarScrollBehavior? = null
|
var bottomAppBarScrollBehaviour: BottomAppBarScrollBehavior? = null
|
||||||
|
|
||||||
// abstract val drawerContainerLayout: DrawerLayout
|
|
||||||
// abstract val drawerNavView: NavigationView
|
|
||||||
// abstract val readerTableOfContentsDrawer: NavigationView
|
|
||||||
abstract val bookmarksFragmentRoute: String
|
abstract val bookmarksFragmentRoute: String
|
||||||
abstract val settingsFragmentRoute: String
|
abstract val settingsFragmentRoute: String
|
||||||
abstract val historyFragmentRoute: String
|
abstract val historyFragmentRoute: String
|
||||||
@ -145,8 +141,6 @@ abstract class CoreMainActivity : BaseActivity(), WebViewProvider {
|
|||||||
abstract val helpFragmentRoute: String
|
abstract val helpFragmentRoute: String
|
||||||
abstract val cachedComponent: CoreActivityComponent
|
abstract val cachedComponent: CoreActivityComponent
|
||||||
abstract val topLevelDestinationsRoute: Set<String>
|
abstract val topLevelDestinationsRoute: Set<String>
|
||||||
|
|
||||||
// abstract val navHostContainer: FragmentContainerView
|
|
||||||
abstract val mainActivity: AppCompatActivity
|
abstract val mainActivity: AppCompatActivity
|
||||||
abstract val appName: String
|
abstract val appName: String
|
||||||
|
|
||||||
@ -200,15 +194,11 @@ abstract class CoreMainActivity : BaseActivity(), WebViewProvider {
|
|||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
setDialogHostToActivity(alertDialogShower)
|
|
||||||
externalLinkOpener.setAlertDialogShower(alertDialogShower)
|
externalLinkOpener.setAlertDialogShower(alertDialogShower)
|
||||||
rateDialogHandler.setAlertDialogShower(alertDialogShower)
|
rateDialogHandler.setAlertDialogShower(alertDialogShower)
|
||||||
downloadMonitor.startMonitoringDownload()
|
downloadMonitor.startMonitoringDownload()
|
||||||
stopDownloadServiceIfRunning()
|
stopDownloadServiceIfRunning()
|
||||||
rateDialogHandler.checkForRateDialog(getIconResId())
|
rateDialogHandler.checkForRateDialog(getIconResId())
|
||||||
// navController.addOnDestinationChangedListener { _, destination, _ ->
|
|
||||||
// configureActivityBasedOn(destination)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -302,59 +292,12 @@ abstract class CoreMainActivity : BaseActivity(), WebViewProvider {
|
|||||||
override fun onSupportNavigateUp(): Boolean =
|
override fun onSupportNavigateUp(): Boolean =
|
||||||
navController.navigateUp() || super.onSupportNavigateUp()
|
navController.navigateUp() || super.onSupportNavigateUp()
|
||||||
|
|
||||||
open fun setupDrawerToggle(shouldEnableRightDrawer: Boolean = false) {
|
fun enableLeftDrawer() {
|
||||||
enableLeftDrawer.value = true
|
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
|
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() {
|
protected fun openHelpFragment() {
|
||||||
@ -492,7 +435,7 @@ abstract class CoreMainActivity : BaseActivity(), WebViewProvider {
|
|||||||
|
|
||||||
protected fun handleDrawerOnNavigation() {
|
protected fun handleDrawerOnNavigation() {
|
||||||
closeNavigationDrawer()
|
closeNavigationDrawer()
|
||||||
disableDrawer()
|
disableLeftDrawer()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setMainActivityToCoreApp() {
|
private fun setMainActivityToCoreApp() {
|
||||||
@ -592,7 +535,6 @@ abstract class CoreMainActivity : BaseActivity(), WebViewProvider {
|
|||||||
protected abstract fun getIconResId(): Int
|
protected abstract fun getIconResId(): Int
|
||||||
abstract val readerFragmentRoute: String
|
abstract val readerFragmentRoute: String
|
||||||
abstract fun createApplicationShortcuts()
|
abstract fun createApplicationShortcuts()
|
||||||
abstract fun setDialogHostToActivity(alertDialogShower: AlertDialogShower)
|
|
||||||
abstract fun hideBottomAppBar()
|
abstract fun hideBottomAppBar()
|
||||||
abstract fun showBottomAppBar()
|
abstract fun showBottomAppBar()
|
||||||
}
|
}
|
||||||
|
@ -68,8 +68,6 @@ import androidx.core.app.ActivityCompat
|
|||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.core.view.GravityCompat
|
|
||||||
import androidx.drawerlayout.widget.DrawerLayout
|
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
@ -193,8 +191,6 @@ abstract class CoreReaderFragment :
|
|||||||
protected val webViewList = mutableStateListOf<KiwixWebView>()
|
protected val webViewList = mutableStateListOf<KiwixWebView>()
|
||||||
private val webUrlsFlow = MutableStateFlow("")
|
private val webUrlsFlow = MutableStateFlow("")
|
||||||
|
|
||||||
var drawerLayout: DrawerLayout? = null
|
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
@Inject
|
@Inject
|
||||||
var sharedPreferenceUtil: SharedPreferenceUtil? = null
|
var sharedPreferenceUtil: SharedPreferenceUtil? = null
|
||||||
@ -490,7 +486,6 @@ abstract class CoreReaderFragment :
|
|||||||
}
|
}
|
||||||
handleLocaleCheck()
|
handleLocaleCheck()
|
||||||
initHideBackToTopTimer()
|
initHideBackToTopTimer()
|
||||||
loadDrawerViews()
|
|
||||||
addFileReader()
|
addFileReader()
|
||||||
activity?.let {
|
activity?.let {
|
||||||
compatCallback = CompatFindActionModeCallback(it)
|
compatCallback = CompatFindActionModeCallback(it)
|
||||||
@ -561,16 +556,28 @@ abstract class CoreReaderFragment :
|
|||||||
string.open_drawer
|
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) {
|
if (readerMenuState?.isInTabSwitcher == true) {
|
||||||
onHomeMenuClicked()
|
onHomeMenuClicked()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val activity = activity as CoreMainActivity
|
||||||
|
if (activity.navigationDrawerIsOpen()) {
|
||||||
|
activity.closeNavigationDrawer()
|
||||||
} else {
|
} else {
|
||||||
val activity = activity as CoreMainActivity
|
activity.openNavigationDrawer()
|
||||||
if (activity.navigationDrawerIsOpen()) {
|
|
||||||
activity.closeNavigationDrawer()
|
|
||||||
} else {
|
|
||||||
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(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
@ -672,10 +672,9 @@ abstract class CoreReaderFragment :
|
|||||||
|
|
||||||
private fun showTabSwitcher() {
|
private fun showTabSwitcher() {
|
||||||
(requireActivity() as CoreMainActivity).apply {
|
(requireActivity() as CoreMainActivity).apply {
|
||||||
disableDrawer()
|
disableLeftDrawer()
|
||||||
hideBottomAppBar()
|
hideBottomAppBar()
|
||||||
}
|
}
|
||||||
setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
|
|
||||||
readerScreenState.update {
|
readerScreenState.update {
|
||||||
copy(
|
copy(
|
||||||
shouldShowBottomAppBar = false,
|
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.
|
* 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) {
|
protected open fun hideTabSwitcher(shouldCloseZimBook: Boolean = true) {
|
||||||
setUpDrawerToggle()
|
enableLeftDrawer()
|
||||||
(requireActivity() as CoreMainActivity).showBottomAppBar()
|
(requireActivity() as CoreMainActivity).showBottomAppBar()
|
||||||
setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
|
|
||||||
readerScreenState.update {
|
readerScreenState.update {
|
||||||
copy(
|
copy(
|
||||||
shouldShowBottomAppBar = true,
|
shouldShowBottomAppBar = true,
|
||||||
@ -730,20 +728,15 @@ abstract class CoreReaderFragment :
|
|||||||
selectTab(currentWebViewIndex)
|
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.
|
* Enables the activity's left drawer, allowing it to be opened by clicking the hamburger icon.
|
||||||
* Subclasses like CustomReaderFragment override this method to provide custom
|
* Subclasses like CustomReaderFragment can override this method to customize the behavior,
|
||||||
* behavior, such as disabling the sidebar when configured not to show it.
|
* for example, to disable the sidebar when it shouldn't be shown.
|
||||||
*
|
*
|
||||||
* WARNING: If modifying this method, ensure thorough testing with custom apps
|
* WARNING: If you modify this method, thoroughly test it in custom apps to ensure it works correctly.
|
||||||
* to verify proper functionality.
|
|
||||||
*/
|
*/
|
||||||
protected open fun setDrawerLockMode(lockMode: Int) {
|
open fun enableLeftDrawer() {
|
||||||
drawerLayout?.setDrawerLockMode(lockMode)
|
(requireActivity() as CoreMainActivity).enableLeftDrawer()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun goBack() {
|
private fun goBack() {
|
||||||
@ -873,8 +866,8 @@ abstract class CoreReaderFragment :
|
|||||||
return FragmentActivityExtensions.Super.ShouldNotCall
|
return FragmentActivityExtensions.Super.ShouldNotCall
|
||||||
}
|
}
|
||||||
|
|
||||||
drawerLayout?.isDrawerOpen(GravityCompat.END) == true -> {
|
shouldTableOfContentDrawer.value -> {
|
||||||
drawerLayout?.closeDrawers()
|
shouldTableOfContentDrawer.update { false }
|
||||||
return FragmentActivityExtensions.Super.ShouldNotCall
|
return FragmentActivityExtensions.Super.ShouldNotCall
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1108,7 +1101,6 @@ abstract class CoreReaderFragment :
|
|||||||
private fun unBindViewsAndBinding() {
|
private fun unBindViewsAndBinding() {
|
||||||
compatCallback?.finish()
|
compatCallback?.finish()
|
||||||
compatCallback = null
|
compatCallback = null
|
||||||
drawerLayout = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateTableOfContents() {
|
private fun updateTableOfContents() {
|
||||||
@ -1484,13 +1476,12 @@ abstract class CoreReaderFragment :
|
|||||||
shouldShowBottomAppBar = false
|
shouldShowBottomAppBar = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
(requireActivity() as CoreMainActivity).disableDrawer(false)
|
(requireActivity() as CoreMainActivity).disableLeftDrawer()
|
||||||
} else {
|
} else {
|
||||||
readerScreenState.update { copy(fullScreenItem = fullScreenItem.copy(first = false)) }
|
readerScreenState.update { copy(fullScreenItem = fullScreenItem.copy(first = false)) }
|
||||||
if (!isInFullScreenMode()) {
|
if (!isInFullScreenMode()) {
|
||||||
readerScreenState.update { copy(shouldShowBottomAppBar = true) }
|
readerScreenState.update { copy(shouldShowBottomAppBar = true) }
|
||||||
setUpDrawerToggle()
|
enableLeftDrawer()
|
||||||
setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1498,7 +1489,7 @@ abstract class CoreReaderFragment :
|
|||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
protected open fun openFullScreen() {
|
protected open fun openFullScreen() {
|
||||||
(requireActivity() as CoreMainActivity).apply {
|
(requireActivity() as CoreMainActivity).apply {
|
||||||
disableDrawer(false)
|
disableLeftDrawer()
|
||||||
hideBottomAppBar()
|
hideBottomAppBar()
|
||||||
}
|
}
|
||||||
readerScreenState.update {
|
readerScreenState.update {
|
||||||
@ -1518,9 +1509,8 @@ abstract class CoreReaderFragment :
|
|||||||
|
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
open fun closeFullScreen() {
|
open fun closeFullScreen() {
|
||||||
setUpDrawerToggle()
|
enableLeftDrawer()
|
||||||
(requireActivity() as CoreMainActivity).showBottomAppBar()
|
(requireActivity() as CoreMainActivity).showBottomAppBar()
|
||||||
setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
|
|
||||||
sharedPreferenceUtil?.putPrefFullScreen(false)
|
sharedPreferenceUtil?.putPrefFullScreen(false)
|
||||||
updateBottomToolbarVisibility()
|
updateBottomToolbarVisibility()
|
||||||
val window = requireActivity().window
|
val window = requireActivity().window
|
||||||
@ -1982,7 +1972,9 @@ abstract class CoreReaderFragment :
|
|||||||
|
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
private fun contentsDrawerHint() {
|
private fun contentsDrawerHint() {
|
||||||
drawerLayout?.postDelayed({ drawerLayout?.openDrawer(GravityCompat.END) }, 500)
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
|
shouldTableOfContentDrawer.update { true }
|
||||||
|
}, 500)
|
||||||
alertDialogShower?.show(KiwixDialog.ContentsDrawerHint)
|
alertDialogShower?.show(KiwixDialog.ContentsDrawerHint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ const val CLOSE_ALL_TABS_BUTTON_TESTING_TAG = "closeAllTabsButtonTestingTag"
|
|||||||
const val TAB_TITLE_TESTING_TAG = "tabTitleTestingTag"
|
const val TAB_TITLE_TESTING_TAG = "tabTitleTestingTag"
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Suppress("ComposableLambdaParameterNaming")
|
@Suppress("ComposableLambdaParameterNaming", "LongMethod")
|
||||||
@Composable
|
@Composable
|
||||||
fun ReaderScreen(
|
fun ReaderScreen(
|
||||||
state: ReaderScreenState,
|
state: ReaderScreenState,
|
||||||
@ -305,6 +305,7 @@ private fun ReaderContentLayout(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("LongMethod", "UnsafeCallOnNullableType")
|
||||||
@Composable
|
@Composable
|
||||||
fun TableDrawerSheet(
|
fun TableDrawerSheet(
|
||||||
title: String,
|
title: String,
|
||||||
@ -372,7 +373,7 @@ fun TableDrawerSheet(
|
|||||||
"document.getElementById('$targetId')?.scrollIntoView();",
|
"document.getElementById('$targetId')?.scrollIntoView();",
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
delay(100)
|
delay(HUNDERED.toLong())
|
||||||
webViewScrollState.value = ScrollState(selectedWebView?.scrollY ?: ZERO)
|
webViewScrollState.value = ScrollState(selectedWebView?.scrollY ?: ZERO)
|
||||||
scrollToSectionIndex = null
|
scrollToSectionIndex = null
|
||||||
showTableOfContentDrawer.update { false }
|
showTableOfContentDrawer.update { false }
|
||||||
|
@ -20,178 +20,64 @@ package org.kiwix.kiwixmobile.custom.main
|
|||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.MenuItem
|
import androidx.activity.compose.setContent
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
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.ShortcutInfoCompat
|
||||||
import androidx.core.content.pm.ShortcutManagerCompat
|
import androidx.core.content.pm.ShortcutManagerCompat
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.drawerlayout.widget.DrawerLayout
|
import androidx.navigation.compose.rememberNavController
|
||||||
import androidx.navigation.NavController
|
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
|
||||||
import com.google.android.material.navigation.NavigationView
|
|
||||||
import org.kiwix.kiwixmobile.core.CoreApp
|
import org.kiwix.kiwixmobile.core.CoreApp
|
||||||
import org.kiwix.kiwixmobile.core.R.drawable
|
import org.kiwix.kiwixmobile.core.R.drawable
|
||||||
import org.kiwix.kiwixmobile.core.R.string
|
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.browserIntent
|
||||||
import org.kiwix.kiwixmobile.core.extensions.getDialogHostComposeView
|
|
||||||
import org.kiwix.kiwixmobile.core.main.ACTION_NEW_TAB
|
import org.kiwix.kiwixmobile.core.main.ACTION_NEW_TAB
|
||||||
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
|
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
|
||||||
import org.kiwix.kiwixmobile.core.main.DrawerMenuItem
|
import org.kiwix.kiwixmobile.core.main.DrawerMenuItem
|
||||||
import org.kiwix.kiwixmobile.core.main.NEW_TAB_SHORTCUT_ID
|
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.BuildConfig
|
||||||
import org.kiwix.kiwixmobile.custom.R
|
import org.kiwix.kiwixmobile.custom.R
|
||||||
import org.kiwix.kiwixmobile.custom.customActivityComponent
|
import org.kiwix.kiwixmobile.custom.customActivityComponent
|
||||||
import org.kiwix.kiwixmobile.custom.databinding.ActivityCustomMainBinding
|
|
||||||
|
|
||||||
class CustomMainActivity : CoreMainActivity() {
|
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 mainActivity: AppCompatActivity by lazy { this }
|
||||||
override val appName: String by lazy { getString(R.string.app_name) }
|
override val appName: String by lazy { getString(R.string.app_name) }
|
||||||
|
|
||||||
override val searchFragmentResId: Int = R.id.searchFragment
|
override val searchFragmentRoute: String = CustomDestination.Search.route
|
||||||
override val bookmarksFragmentResId: Int = R.id.bookmarksFragment
|
override val bookmarksFragmentRoute: String = CustomDestination.Bookmarks.route
|
||||||
override val settingsFragmentResId: Int = R.id.customSettingsFragment
|
override val settingsFragmentRoute: String = CustomDestination.Settings.route
|
||||||
override val readerFragmentResId: Int = R.id.customReaderFragment
|
override val readerFragmentRoute: String = CustomDestination.Reader.route
|
||||||
override val historyFragmentResId: Int = R.id.historyFragment
|
override val historyFragmentRoute: String = CustomDestination.History.route
|
||||||
override val notesFragmentResId: Int = R.id.notesFragment
|
override val notesFragmentRoute: String = CustomDestination.Notes.route
|
||||||
override val helpFragmentResId: Int = R.id.helpFragment
|
override val helpFragmentRoute: String = CustomDestination.Help.route
|
||||||
override val cachedComponent by lazy { customActivityComponent }
|
override val cachedComponent by lazy { customActivityComponent }
|
||||||
override val topLevelDestinations =
|
override val topLevelDestinationsRoute = setOf(CustomDestination.Reader.route)
|
||||||
setOf(R.id.customReaderFragment)
|
|
||||||
|
|
||||||
lateinit var activityCustomMainBinding: ActivityCustomMainBinding
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
customActivityComponent.inject(this)
|
customActivityComponent.inject(this)
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
activityCustomMainBinding = ActivityCustomMainBinding.inflate(layoutInflater)
|
setContent {
|
||||||
setContentView(activityCustomMainBinding.root)
|
navController = rememberNavController()
|
||||||
activityCustomMainBinding.root.applyEdgeToEdgeInsets()
|
leftDrawerState = rememberDrawerState(DrawerValue.Closed)
|
||||||
|
uiCoroutineScope = rememberCoroutineScope()
|
||||||
|
CustomMainActivityScreen(
|
||||||
|
navController = navController,
|
||||||
|
leftDrawerContent = leftDrawerMenu,
|
||||||
|
topLevelDestinationsRoute = topLevelDestinationsRoute,
|
||||||
|
leftDrawerState = leftDrawerState,
|
||||||
|
enableLeftDrawer = enableLeftDrawer.value
|
||||||
|
)
|
||||||
|
DialogHost(alertDialogShower)
|
||||||
|
}
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
return
|
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
|
override fun getIconResId() = R.mipmap.ic_launcher
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -256,7 +142,10 @@ class CustomMainActivity : CoreMainActivity() {
|
|||||||
true,
|
true,
|
||||||
onClick = {
|
onClick = {
|
||||||
closeNavigationDrawer()
|
closeNavigationDrawer()
|
||||||
externalLinkOpener.openExternalUrl(BuildConfig.ABOUT_APP_URL.toUri().browserIntent(), false)
|
externalLinkOpener.openExternalUrl(
|
||||||
|
BuildConfig.ABOUT_APP_URL.toUri().browserIntent(),
|
||||||
|
false
|
||||||
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@ -281,12 +170,14 @@ class CustomMainActivity : CoreMainActivity() {
|
|||||||
ShortcutManagerCompat.addDynamicShortcuts(this, listOf(newTabShortcut))
|
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) {
|
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() {
|
override fun hideBottomAppBar() {
|
||||||
|
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Kiwix Android
|
||||||
|
* Copyright (c) 2025 Kiwix <android.kiwix.org>
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.kiwix.kiwixmobile.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<DrawerMenuGroup>,
|
||||||
|
topLevelDestinationsRoute: Set<String>,
|
||||||
|
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()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,248 @@
|
|||||||
|
/*
|
||||||
|
* Kiwix Android
|
||||||
|
* Copyright (c) 2025 Kiwix <android.kiwix.org>
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.kiwix.kiwixmobile.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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,20 +21,19 @@ package org.kiwix.kiwixmobile.custom.main
|
|||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Menu
|
import androidx.compose.material.icons.filled.Menu
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.drawerlayout.widget.DrawerLayout
|
import androidx.navigation.NavOptions
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.kiwix.kiwixmobile.core.base.BaseActivity
|
import org.kiwix.kiwixmobile.core.base.BaseActivity
|
||||||
import org.kiwix.kiwixmobile.core.extensions.browserIntent
|
import org.kiwix.kiwixmobile.core.extensions.browserIntent
|
||||||
import org.kiwix.kiwixmobile.core.extensions.isFileExist
|
import org.kiwix.kiwixmobile.core.extensions.isFileExist
|
||||||
import org.kiwix.kiwixmobile.core.extensions.update
|
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.CoreReaderFragment
|
||||||
import org.kiwix.kiwixmobile.core.main.reader.ReaderMenuState
|
import org.kiwix.kiwixmobile.core.main.reader.ReaderMenuState
|
||||||
import org.kiwix.kiwixmobile.core.main.reader.RestoreOrigin
|
import org.kiwix.kiwixmobile.core.main.reader.RestoreOrigin
|
||||||
@ -75,10 +74,10 @@ class CustomReaderFragment : CoreReaderFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isAdded) {
|
if (isAdded) {
|
||||||
setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
|
enableLeftDrawer()
|
||||||
with(activity as AppCompatActivity) {
|
with(activity as AppCompatActivity) {
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
setUpDrawerToggle()
|
enableLeftDrawer()
|
||||||
}
|
}
|
||||||
loadPageFromNavigationArguments()
|
loadPageFromNavigationArguments()
|
||||||
if (BuildConfig.DISABLE_EXTERNAL_LINK) {
|
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() {
|
private fun loadPageFromNavigationArguments() {
|
||||||
val args = CustomReaderFragmentArgs.fromBundle(requireArguments())
|
val args = CustomReaderFragmentArgs.fromBundle(requireArguments())
|
||||||
if (args.pageUrl.isNotEmpty()) {
|
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,
|
* Enables or disables the sidebar in a custom app based on the configuration.
|
||||||
* this function disables the sidebar by locking it in the closed position through the parent class.
|
* If the app is configured to disable the sidebar, this method disables it;
|
||||||
* https://developer.android.com/reference/kotlin/androidx/drawerlayout/widget/DrawerLayout#LOCK_MODE_LOCKED_CLOSED()
|
* otherwise, it enables the sidebar.
|
||||||
*/
|
*/
|
||||||
override fun setDrawerLockMode(lockMode: Int) {
|
override fun enableLeftDrawer() {
|
||||||
super.setDrawerLockMode(
|
if (BuildConfig.DISABLE_SIDEBAR) {
|
||||||
if (BuildConfig.DISABLE_SIDEBAR) {
|
(requireActivity() as CoreMainActivity).disableLeftDrawer()
|
||||||
DrawerLayout.LOCK_MODE_LOCKED_CLOSED
|
} else {
|
||||||
} else {
|
super.enableLeftDrawer()
|
||||||
lockMode
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -268,8 +287,13 @@ class CustomReaderFragment : CoreReaderFragment() {
|
|||||||
},
|
},
|
||||||
onNoFilesFound = {
|
onNoFilesFound = {
|
||||||
if (sharedPreferenceUtil?.prefIsTest == false) {
|
if (sharedPreferenceUtil?.prefIsTest == false) {
|
||||||
// TODO refactor this when migrating the custom app in compose
|
val navOptions = NavOptions.Builder()
|
||||||
// (requireActivity() as CoreMainActivity).navigate(R.id.customDownloadFragment)
|
.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()
|
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 {
|
private fun enforcedLanguage(): Boolean {
|
||||||
val currentLocaleCode = Locale.getDefault().toString()
|
val currentLocaleCode = Locale.getDefault().toString()
|
||||||
if (BuildConfig.ENFORCED_LANG.isNotEmpty() && BuildConfig.ENFORCED_LANG != currentLocaleCode) {
|
if (BuildConfig.ENFORCED_LANG.isNotEmpty() && BuildConfig.ENFORCED_LANG != currentLocaleCode) {
|
||||||
@ -304,17 +321,6 @@ class CustomReaderFragment : CoreReaderFragment() {
|
|||||||
return false
|
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
|
* 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
|
* features like "read aloud" and "tabs," and this method dynamically generates the menu based on the
|
||||||
|
Loading…
x
Reference in New Issue
Block a user