diff --git a/app/src/main/java/org/kiwix/kiwixmobile/language/LanguageFragment.kt b/app/src/main/java/org/kiwix/kiwixmobile/language/LanguageFragment.kt
index ff820a756..7e85e9132 100644
--- a/app/src/main/java/org/kiwix/kiwixmobile/language/LanguageFragment.kt
+++ b/app/src/main/java/org/kiwix/kiwixmobile/language/LanguageFragment.kt
@@ -38,6 +38,7 @@ import org.kiwix.kiwixmobile.core.base.BaseActivity
import org.kiwix.kiwixmobile.core.base.BaseFragment
import org.kiwix.kiwixmobile.core.extensions.viewModel
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
+import org.kiwix.kiwixmobile.core.page.SEARCH_ICON_TESTING_TAG
import org.kiwix.kiwixmobile.core.ui.components.NavigationIcon
import org.kiwix.kiwixmobile.core.ui.models.ActionMenuItem
import org.kiwix.kiwixmobile.core.ui.models.IconItem
@@ -46,7 +47,6 @@ import org.kiwix.kiwixmobile.language.viewmodel.Action
import org.kiwix.kiwixmobile.language.viewmodel.LanguageViewModel
import javax.inject.Inject
-const val SEARCH_ICON_TESTING_TAG = "search"
const val SAVE_ICON_TESTING_TAG = "saveLanguages"
const val SEARCH_FIELD_TESTING_TAG = "searchField"
diff --git a/app/src/main/res/navigation/kiwix_nav_graph.xml b/app/src/main/res/navigation/kiwix_nav_graph.xml
index 8bf77c014..663efe176 100644
--- a/app/src/main/res/navigation/kiwix_nav_graph.xml
+++ b/app/src/main/res/navigation/kiwix_nav_graph.xml
@@ -94,13 +94,11 @@
+ android:label="BookmarksFragment" />
+ android:label="NotesFragment" />
+ android:label="HistoryFragment" />
@@ -74,7 +87,26 @@ abstract class PageFragment : OnItemClickListener, BaseFragment(), FragmentActiv
abstract val searchQueryHint: String
abstract val pageAdapter: PageAdapter
abstract val switchIsChecked: Boolean
- abstract val deleteIconTitle: String
+ abstract val deleteIconTitle: Int
+ private val pageState: MutableState> =
+ mutableStateOf(
+ NotesState(
+ emptyList(),
+ true,
+ ""
+ ),
+ policy = referentialEqualityPolicy()
+ )
+
+ /**
+ * Controls the visibility of the "Switch", and its controls.
+ *
+ * A [Triple] containing:
+ * - [String]: The text displayed with switch.
+ * - [Boolean]: Whether the switch is checked or not.
+ * - [Boolean]: Whether the switch is enabled or disabled.
+ */
+ private val pageSwitchItem = mutableStateOf(Triple("", true, true))
private var fragmentPageBinding: FragmentPageBinding? = null
override val fragmentToolbar: Toolbar? by lazy {
fragmentPageBinding?.root?.findViewById(R.id.toolbar)
@@ -119,7 +151,7 @@ abstract class PageFragment : OnItemClickListener, BaseFragment(), FragmentActiv
}
)
}
- menu.findItem(R.id.menu_pages_clear).title = deleteIconTitle // Bug fix #3825
+ // menu.findItem(R.id.menu_pages_clear).title = deleteIconTitle // Bug fix #3825
}
@Suppress("ReturnCount")
@@ -155,16 +187,16 @@ abstract class PageFragment : OnItemClickListener, BaseFragment(), FragmentActiv
}
fragmentPageBinding?.noPage?.text = noItemsString
- fragmentPageBinding?.pageSwitch?.apply {
- text = switchString
- isChecked = switchIsChecked
- // hide switches for custom apps, see more info here https://github.com/kiwix/kiwix-android/issues/3523
- visibility = if (requireActivity().isCustomApp()) GONE else VISIBLE
- }
+ // fragmentPageBinding?.pageSwitch?.apply {
+ // text = switchString
+ // isChecked = switchIsChecked
+ // // hide switches for custom apps, see more info here https://github.com/kiwix/kiwix-android/issues/3523
+ // visibility = if (requireActivity().isCustomApp()) GONE else VISIBLE
+ // }
compositeDisposable.add(pageViewModel.effects.subscribe { it.invokeWith(activity) })
- fragmentPageBinding?.pageSwitch?.setOnCheckedChangeListener { _, isChecked ->
- pageViewModel.actions.offer(Action.UserClickedShowAllToggle(isChecked))
- }
+ // fragmentPageBinding?.pageSwitch?.setOnCheckedChangeListener { _, isChecked ->
+ // pageViewModel.actions.offer(Action.UserClickedShowAllToggle(isChecked))
+ // }
pageViewModel.state.observe(viewLifecycleOwner, Observer(::render))
// hides keyboard when scrolled
@@ -184,38 +216,85 @@ abstract class PageFragment : OnItemClickListener, BaseFragment(), FragmentActiv
): View? {
return ComposeView(requireContext()).apply {
setContent {
+ val isSearchActive = remember { mutableStateOf(false) }
PageScreen(
- pageState = pageViewModel.state,
- effects = pageViewModel.effects,
+ pageState = pageState.value,
+ pageSwitchItem = pageSwitchItem.value,
screenTitle = screenTitle,
noItemsString = noItemsString,
- switchString = switchString,
searchQueryHint = searchQueryHint,
- switchIsChecked = switchIsChecked,
- onSwitchChanged = { isChecked ->
- pageViewModel.actions.offer(Action.UserClickedShowAllToggle(isChecked))
+ onSwitchChanged = { onSwitchCheckedChanged(it) },
+ itemClickListener = this@PageFragment,
+ navigationIcon = {
+ NavigationIcon(
+ iconItem = navigationIconItem(isSearchActive.value),
+ onClick = navigationIconClick(isSearchActive)
+ )
},
- onItemClick = { pageViewModel.actions.offer(Action.OnItemClick(it)) },
- onItemLongClick = { pageViewModel.actions.offer(Action.OnItemLongClick(it)) }
+ actionMenuItems = actionMenuList(
+ isSearchActive = isSearchActive.value,
+ onSearchClick = { isSearchActive.value = true },
+ onDeleteClick = { pageViewModel.actions.offer(Action.UserClickedDeleteButton) }
+ )
)
}
}
}
+ private fun onSwitchCheckedChanged(isChecked: Boolean): () -> Unit = {
+ pageSwitchItem.value = pageSwitchItem.value.copy(second = isChecked)
+ pageViewModel.actions.offer(Action.UserClickedShowAllToggle(isChecked))
+ }
+
+ private fun navigationIconItem(isSearchActive: Boolean) = if (isSearchActive) {
+ IconItem.Drawable(R.drawable.ic_close_white_24dp)
+ } else {
+ IconItem.Vector(Icons.AutoMirrored.Filled.ArrowBack)
+ }
+
+ private fun navigationIconClick(isSearchActive: MutableState): () -> Unit = {
+ if (isSearchActive.value) {
+ isSearchActive.value = false
+ pageViewModel.actions.offer(Action.Exit)
+ } else {
+ requireActivity().onBackPressedDispatcher.onBackPressed()
+ }
+ }
+
+ private fun actionMenuList(
+ isSearchActive: Boolean,
+ onSearchClick: () -> Unit,
+ onDeleteClick: () -> Unit
+ ): List {
+ return listOfNotNull(
+ when {
+ !isSearchActive -> ActionMenuItem(
+ icon = IconItem.Drawable(R.drawable.action_search),
+ contentDescription = R.string.search_label,
+ onClick = onSearchClick,
+ testingTag = SEARCH_ICON_TESTING_TAG
+ )
+
+ else -> null
+ },
+ ActionMenuItem(
+ icon = IconItem.Vector(Icons.Default.Delete),
+ // Adding content description for #3825.
+ contentDescription = deleteIconTitle,
+ onClick = onDeleteClick,
+ testingTag = DELETE_MENU_ICON_TESTING_TAG
+ )
+ )
+ }
+
override fun onDestroyView() {
super.onDestroyView()
compositeDisposable.clear()
- fragmentPageBinding?.apply {
- recyclerView.adapter = null
- root.removeAllViews()
- }
- fragmentPageBinding = null
}
private fun render(state: PageState<*>) {
- pageAdapter.items = state.visiblePageItems
- fragmentPageBinding?.pageSwitch?.isEnabled = !state.isInSelectionState
- fragmentPageBinding?.noPage?.visibility = if (state.pageItems.isEmpty()) VISIBLE else GONE
+ pageState.value = state
+ pageSwitchItem.value = Triple(switchString, switchIsChecked, !state.isInSelectionState)
if (state.isInSelectionState) {
if (actionMode == null) {
actionMode =
diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/PageListItem.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/PageListItem.kt
index a74c560d2..411aa9b9e 100644
--- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/PageListItem.kt
+++ b/core/src/main/java/org/kiwix/kiwixmobile/core/page/PageListItem.kt
@@ -39,6 +39,7 @@ import androidx.compose.ui.text.style.TextOverflow
import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.core.downloader.model.Base64String
import org.kiwix.kiwixmobile.core.downloader.model.toPainter
+import org.kiwix.kiwixmobile.core.page.adapter.OnItemClickListener
import org.kiwix.kiwixmobile.core.page.adapter.Page
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.EIGHT_DP
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.PAGE_LIST_ITEM_FAVICON_SIZE
@@ -48,13 +49,15 @@ import org.kiwix.kiwixmobile.core.utils.ComposeDimens.SIXTEEN_DP
@Composable
fun PageListItem(
page: Page,
- onClick: () -> Unit,
- onLongClick: () -> Unit
+ itemClickListener: OnItemClickListener
) {
Row(
modifier = Modifier
.fillMaxWidth()
- .combinedClickable(onClick = onClick, onLongClick = onLongClick)
+ .combinedClickable(
+ onClick = { itemClickListener.onItemClick(page) },
+ onLongClick = { itemClickListener.onItemLongClick(page) }
+ )
.background(MaterialTheme.colorScheme.surface)
.padding(
horizontal = SIXTEEN_DP,
diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/PageScreen.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/PageScreen.kt
index 8eae0c5f0..b160783b5 100644
--- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/PageScreen.kt
+++ b/core/src/main/java/org/kiwix/kiwixmobile/core/page/PageScreen.kt
@@ -32,55 +32,51 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.lifecycle.MutableLiveData
-import io.reactivex.processors.PublishProcessor
-import org.kiwix.kiwixmobile.core.base.SideEffect
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.isCustomApp
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
+import org.kiwix.kiwixmobile.core.page.adapter.OnItemClickListener
import org.kiwix.kiwixmobile.core.page.adapter.Page
import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.DateItem
import org.kiwix.kiwixmobile.core.page.viewmodel.PageState
import org.kiwix.kiwixmobile.core.ui.components.KiwixAppBar
+import org.kiwix.kiwixmobile.core.ui.models.ActionMenuItem
import org.kiwix.kiwixmobile.core.ui.theme.KiwixTheme
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.EIGHT_DP
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.SIXTEEN_DP
-@Suppress("LongParameterList", "IgnoredReturnValue", "UnusedParameter")
+@Suppress(
+ "LongParameterList",
+ "IgnoredReturnValue",
+ "UnusedParameter",
+ "ComposableLambdaParameterNaming"
+)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PageScreen(
- pageState: MutableLiveData>,
- effects: PublishProcessor>,
+ pageState: PageState,
+ pageSwitchItem: Triple,
screenTitle: Int,
noItemsString: String,
- switchString: String,
searchQueryHint: String,
- switchIsChecked: Boolean,
onSwitchChanged: (Boolean) -> Unit,
- onItemClick: (Page) -> Unit,
- onItemLongClick: (Page) -> Unit
+ itemClickListener: OnItemClickListener,
+ actionMenuItems: List,
+ navigationIcon: @Composable () -> Unit,
) {
val context = LocalActivity.current as CoreMainActivity
- val state by pageState.observeAsState()
-
- LaunchedEffect(Unit) {
- effects.subscribe { it.invokeWith(context) }
- }
-
KiwixTheme {
Scaffold(
topBar = {
Column {
KiwixAppBar(
titleId = screenTitle,
- navigationIcon = {},
+ navigationIcon = navigationIcon,
+ actionMenuItems = actionMenuItems
)
+ // hide switches for custom apps, see more info here https://github.com/kiwix/kiwix-android/issues/3523
if (!context.isCustomApp()) {
Row(
modifier = Modifier
@@ -88,14 +84,18 @@ fun PageScreen(
.padding(horizontal = SIXTEEN_DP, vertical = EIGHT_DP),
verticalAlignment = Alignment.CenterVertically
) {
- Text(switchString, modifier = Modifier.weight(1f))
- Switch(checked = switchIsChecked, onCheckedChange = onSwitchChanged)
+ Text(pageSwitchItem.first, modifier = Modifier.weight(1f))
+ Switch(
+ checked = pageSwitchItem.second,
+ onCheckedChange = onSwitchChanged,
+ enabled = pageSwitchItem.third
+ )
}
}
}
}
) { padding ->
- val items = state?.visiblePageItems.orEmpty()
+ val items = pageState.pageItems
Box(modifier = Modifier.padding(padding)) {
if (items.isEmpty()) {
Text(
@@ -105,13 +105,12 @@ fun PageScreen(
)
} else {
LazyColumn {
- items(items) { item ->
+ items(pageState.visiblePageItems) { item ->
when (item) {
is Page -> {
PageListItem(
page = item,
- onClick = { onItemClick(item) },
- onLongClick = { onItemLongClick(item) }
+ itemClickListener = itemClickListener
)
}
diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/bookmark/BookmarksFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/bookmark/BookmarksFragment.kt
index 2ba944d47..9e57f0f01 100644
--- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/bookmark/BookmarksFragment.kt
+++ b/core/src/main/java/org/kiwix/kiwixmobile/core/page/bookmark/BookmarksFragment.kt
@@ -19,8 +19,8 @@ class BookmarksFragment : PageFragment() {
override val screenTitle: Int by lazy { R.string.bookmarks }
override val noItemsString: String by lazy { getString(R.string.no_bookmarks) }
override val switchString: String by lazy { getString(R.string.bookmarks_from_current_book) }
- override val deleteIconTitle: String by lazy {
- getString(R.string.pref_clear_all_bookmarks_title)
+ override val deleteIconTitle: Int by lazy {
+ R.string.pref_clear_all_bookmarks_title
}
override val switchIsChecked: Boolean by lazy { sharedPreferenceUtil.showBookmarksAllBooks }
diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/HistoryFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/HistoryFragment.kt
index 85d2d822e..891c60758 100644
--- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/HistoryFragment.kt
+++ b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/HistoryFragment.kt
@@ -22,8 +22,8 @@ class HistoryFragment : PageFragment() {
override val noItemsString: String by lazy { getString(R.string.no_history) }
override val switchString: String by lazy { getString(R.string.history_from_current_book) }
override val screenTitle: Int by lazy { R.string.history }
- override val deleteIconTitle: String by lazy {
- getString(R.string.pref_clear_all_history_title)
+ override val deleteIconTitle: Int by lazy {
+ R.string.pref_clear_all_history_title
}
override val switchIsChecked: Boolean by lazy { sharedPreferenceUtil.showHistoryAllBooks }
diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/notes/NotesFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/notes/NotesFragment.kt
index 4c6a4ae44..aaa610ff3 100644
--- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/notes/NotesFragment.kt
+++ b/core/src/main/java/org/kiwix/kiwixmobile/core/page/notes/NotesFragment.kt
@@ -38,8 +38,8 @@ class NotesFragment : PageFragment() {
override val noItemsString: String by lazy { getString(R.string.no_notes) }
override val switchString: String by lazy { getString(R.string.notes_from_all_books) }
- override val deleteIconTitle: String by lazy {
- getString(R.string.pref_clear_notes)
+ override val deleteIconTitle: Int by lazy {
+ R.string.pref_clear_notes
}
override val switchIsChecked: Boolean by lazy { sharedPreferenceUtil.showNotesAllBooks }