mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 10:46:53 -04:00
Fixed: When selecting page items the changes are not reflecting in UI.
* Improved the clicking on page item. * Fixed: Page items are not showing updating after deleting. * Fixed: Switch was not disabling when selecting the page items. * Added SearchView, navigationIcon, and menuItems to page fragment.
This commit is contained in:
parent
bceebd5de4
commit
acbf1bfec3
@ -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"
|
||||
|
||||
|
@ -94,13 +94,11 @@
|
||||
<fragment
|
||||
android:id="@+id/bookmarksFragment"
|
||||
android:name="org.kiwix.kiwixmobile.core.page.bookmark.BookmarksFragment"
|
||||
android:label="BookmarksFragment"
|
||||
tools:layout="@layout/fragment_page" />
|
||||
android:label="BookmarksFragment" />
|
||||
<fragment
|
||||
android:id="@+id/notesFragment"
|
||||
android:name="org.kiwix.kiwixmobile.core.page.notes.NotesFragment"
|
||||
android:label="NotesFragment"
|
||||
tools:layout="@layout/fragment_page" />
|
||||
android:label="NotesFragment" />
|
||||
<fragment
|
||||
android:id="@+id/introFragment"
|
||||
android:name="org.kiwix.kiwixmobile.intro.IntroFragment"
|
||||
@ -115,8 +113,7 @@
|
||||
<fragment
|
||||
android:id="@+id/historyFragment"
|
||||
android:name="org.kiwix.kiwixmobile.core.page.history.HistoryFragment"
|
||||
android:label="HistoryFragment"
|
||||
tools:layout="@layout/fragment_page" />
|
||||
android:label="HistoryFragment" />
|
||||
<fragment
|
||||
android:id="@+id/languageFragment"
|
||||
android:name="org.kiwix.kiwixmobile.language.LanguageFragment"
|
||||
|
@ -24,13 +24,20 @@ import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.referentialEqualityPolicy
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.core.view.MenuHost
|
||||
import androidx.core.view.MenuProvider
|
||||
@ -44,7 +51,6 @@ import org.kiwix.kiwixmobile.core.R
|
||||
import org.kiwix.kiwixmobile.core.base.BaseFragment
|
||||
import org.kiwix.kiwixmobile.core.base.FragmentActivityExtensions
|
||||
import org.kiwix.kiwixmobile.core.databinding.FragmentPageBinding
|
||||
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.isCustomApp
|
||||
import org.kiwix.kiwixmobile.core.extensions.closeKeyboard
|
||||
import org.kiwix.kiwixmobile.core.extensions.setToolTipWithContentDescription
|
||||
import org.kiwix.kiwixmobile.core.extensions.setUpSearchView
|
||||
@ -52,14 +58,21 @@ 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.adapter.PageAdapter
|
||||
import org.kiwix.kiwixmobile.core.page.notes.viewmodel.NotesState
|
||||
import org.kiwix.kiwixmobile.core.page.viewmodel.Action
|
||||
import org.kiwix.kiwixmobile.core.page.viewmodel.PageState
|
||||
import org.kiwix.kiwixmobile.core.page.viewmodel.PageViewModel
|
||||
import org.kiwix.kiwixmobile.core.ui.components.NavigationIcon
|
||||
import org.kiwix.kiwixmobile.core.ui.models.ActionMenuItem
|
||||
import org.kiwix.kiwixmobile.core.ui.models.IconItem
|
||||
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
||||
import org.kiwix.kiwixmobile.core.utils.SimpleRecyclerViewScrollListener
|
||||
import org.kiwix.kiwixmobile.core.utils.SimpleTextListener
|
||||
import javax.inject.Inject
|
||||
|
||||
const val SEARCH_ICON_TESTING_TAG = "search"
|
||||
const val DELETE_MENU_ICON_TESTING_TAG = "deleteMenuIconTestingTag"
|
||||
|
||||
abstract class PageFragment : OnItemClickListener, BaseFragment(), FragmentActivityExtensions {
|
||||
abstract val pageViewModel: PageViewModel<*, *>
|
||||
|
||||
@ -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<PageState<*>> =
|
||||
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<Boolean>): () -> 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<ActionMenuItem> {
|
||||
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 =
|
||||
|
@ -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,
|
||||
|
@ -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<out PageState<out Page>>,
|
||||
effects: PublishProcessor<SideEffect<*>>,
|
||||
pageState: PageState<out Page>,
|
||||
pageSwitchItem: Triple<String, Boolean, Boolean>,
|
||||
screenTitle: Int,
|
||||
noItemsString: String,
|
||||
switchString: String,
|
||||
searchQueryHint: String,
|
||||
switchIsChecked: Boolean,
|
||||
onSwitchChanged: (Boolean) -> Unit,
|
||||
onItemClick: (Page) -> Unit,
|
||||
onItemLongClick: (Page) -> Unit
|
||||
itemClickListener: OnItemClickListener,
|
||||
actionMenuItems: List<ActionMenuItem>,
|
||||
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
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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 }
|
||||
|
||||
|
@ -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 }
|
||||
|
||||
|
@ -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 }
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user