From 9de216beec0886d1572891cca3c0f8ba0d6d344c Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Tue, 29 Apr 2025 18:42:42 +0530 Subject: [PATCH] Migrated the `NavigationHistoryDialog` to Jetpack Compose. * Created the `NavigationHistoryDialogScreen` using our app theme. * Refactored the code according to comose UI. * Refactored the UI test cases according to compose UI. * Removed the unused code from project. --- .../page/history/NavigationHistoryRobot.kt | 55 +++++-- .../page/history/NavigationHistoryTest.kt | 13 +- .../core/main/CoreReaderFragment.kt | 4 +- .../kiwixmobile/core/page/PageFragment.kt | 2 - .../kiwixmobile/core/page/PageListItem.kt | 3 +- .../core/page/adapter/PageDelegate.kt | 52 ------- .../adapter/PageRelatedListItemViewHolder.kt | 73 --------- .../core/page/bookmark/BookmarksFragment.kt | 6 - .../core/page/history/HistoryFragment.kt | 9 -- .../page/history/NavigationHistoryDialog.kt | 96 +++++------- .../history/NavigationHistoryDialogScreen.kt | 144 ++++++++++++++++++ .../adapter/NavigationHistoryAdapter.kt | 28 ---- .../adapter/NavigationHistoryDelegate.kt | 43 ------ .../adapter/NavigationHistoryViewHolder.kt | 41 ----- .../core/page/notes/NotesFragment.kt | 6 - .../res/layout/dialog_navigation_history.xml | 49 ------ core/src/main/res/layout/header_date.xml | 19 --- .../main/res/layout/item_bookmark_history.xml | 39 ----- 18 files changed, 235 insertions(+), 447 deletions(-) delete mode 100644 core/src/main/java/org/kiwix/kiwixmobile/core/page/adapter/PageDelegate.kt delete mode 100644 core/src/main/java/org/kiwix/kiwixmobile/core/page/adapter/PageRelatedListItemViewHolder.kt create mode 100644 core/src/main/java/org/kiwix/kiwixmobile/core/page/history/NavigationHistoryDialogScreen.kt delete mode 100644 core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/NavigationHistoryAdapter.kt delete mode 100644 core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/NavigationHistoryDelegate.kt delete mode 100644 core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/NavigationHistoryViewHolder.kt delete mode 100644 core/src/main/res/layout/dialog_navigation_history.xml delete mode 100644 core/src/main/res/layout/header_date.xml delete mode 100644 core/src/main/res/layout/item_bookmark_history.xml diff --git a/app/src/androidTest/java/org/kiwix/kiwixmobile/page/history/NavigationHistoryRobot.kt b/app/src/androidTest/java/org/kiwix/kiwixmobile/page/history/NavigationHistoryRobot.kt index 2580bb1c4..1c234ba80 100644 --- a/app/src/androidTest/java/org/kiwix/kiwixmobile/page/history/NavigationHistoryRobot.kt +++ b/app/src/androidTest/java/org/kiwix/kiwixmobile/page/history/NavigationHistoryRobot.kt @@ -18,6 +18,10 @@ package org.kiwix.kiwixmobile.page.history import android.util.Log +import androidx.compose.ui.test.assertTextEquals +import androidx.compose.ui.test.junit4.ComposeContentTestRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.performClick import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.longClick @@ -30,9 +34,11 @@ import applyWithViewHierarchyPrinting import com.adevinta.android.barista.interaction.BaristaSleepInteractions import junit.framework.AssertionFailedError import org.kiwix.kiwixmobile.BaseRobot -import org.kiwix.kiwixmobile.Findable.StringId.TextId import org.kiwix.kiwixmobile.Findable.ViewId import org.kiwix.kiwixmobile.core.R +import org.kiwix.kiwixmobile.core.page.DELETE_MENU_ICON_TESTING_TAG +import org.kiwix.kiwixmobile.core.ui.components.TOOLBAR_TITLE_TESTING_TAG +import org.kiwix.kiwixmobile.core.utils.dialog.ALERT_DIALOG_TITLE_TEXT_TESTING_TAG import org.kiwix.kiwixmobile.testutils.TestUtils import org.kiwix.kiwixmobile.testutils.TestUtils.testFlakyView @@ -54,7 +60,7 @@ class NavigationHistoryRobot : BaseRobot() { pauseForBetterTestPerformance() isVisible(ViewId(R.id.tab_switcher_close_all_tabs)) pressBack() - } catch (ignore: Exception) { + } catch (_: Exception) { Log.i( "NAVIGATION_HISTORY_TEST", "Couldn't found tab switcher, probably it is not visible" @@ -95,14 +101,18 @@ class NavigationHistoryRobot : BaseRobot() { longClickOn(ViewId(R.id.bottom_toolbar_arrow_forward)) } - fun assertBackwardNavigationHistoryDialogDisplayed() { + fun assertBackwardNavigationHistoryDialogDisplayed(composeTestRule: ComposeContentTestRule) { try { - isVisible(TextId(R.string.backward_history)) - } catch (ignore: AssertionFailedError) { + composeTestRule.apply { + waitForIdle() + onNodeWithTag(TOOLBAR_TITLE_TESTING_TAG) + .assertTextEquals(context.getString(R.string.backward_history)) + } + } catch (_: AssertionError) { pauseForBetterTestPerformance() if (retryCountForBackwardNavigationHistory > 0) { retryCountForBackwardNavigationHistory-- - assertBackwardNavigationHistoryDialogDisplayed() + assertBackwardNavigationHistoryDialogDisplayed(composeTestRule) } } } @@ -112,31 +122,46 @@ class NavigationHistoryRobot : BaseRobot() { clickOn(ViewId(R.id.bottom_toolbar_arrow_back)) } - fun assertForwardNavigationHistoryDialogDisplayed() { + fun assertForwardNavigationHistoryDialogDisplayed(composeTestRule: ComposeContentTestRule) { try { - isVisible(TextId(R.string.forward_history)) - } catch (ignore: AssertionFailedError) { + composeTestRule.apply { + waitForIdle() + onNodeWithTag(TOOLBAR_TITLE_TESTING_TAG) + .assertTextEquals(context.getString(R.string.forward_history)) + } + } catch (_: AssertionError) { pauseForBetterTestPerformance() if (retryCountForForwardNavigationHistory > 0) { retryCountForForwardNavigationHistory-- - assertForwardNavigationHistoryDialogDisplayed() + assertForwardNavigationHistoryDialogDisplayed(composeTestRule) } } } - fun clickOnDeleteHistory() { + fun clickOnDeleteHistory(composeTestRule: ComposeContentTestRule) { pauseForBetterTestPerformance() - clickOn(ViewId(R.id.menu_pages_clear)) + testFlakyView({ + composeTestRule.apply { + waitForIdle() + onNodeWithTag(DELETE_MENU_ICON_TESTING_TAG).performClick() + } + }) } - fun assertDeleteDialogDisplayed() { + fun assertDeleteDialogDisplayed(composeTestRule: ComposeContentTestRule) { try { - isVisible(TextId(R.string.clear_all_history_dialog_title)) + composeTestRule.apply { + waitForIdle() + onNodeWithTag(ALERT_DIALOG_TITLE_TEXT_TESTING_TAG) + .assertTextEquals(context.getString(R.string.clear_all_history_dialog_title)) + } } catch (ignore: AssertionFailedError) { pauseForBetterTestPerformance() if (retryCountForClearNavigationHistory > 0) { retryCountForClearNavigationHistory-- - assertDeleteDialogDisplayed() + assertDeleteDialogDisplayed(composeTestRule) + } else { + throw RuntimeException("Could not found the NavigationHistoryDeleteDialog. Original exception = $ignore") } } } diff --git a/app/src/androidTest/java/org/kiwix/kiwixmobile/page/history/NavigationHistoryTest.kt b/app/src/androidTest/java/org/kiwix/kiwixmobile/page/history/NavigationHistoryTest.kt index 91fe987e3..307fcc819 100644 --- a/app/src/androidTest/java/org/kiwix/kiwixmobile/page/history/NavigationHistoryTest.kt +++ b/app/src/androidTest/java/org/kiwix/kiwixmobile/page/history/NavigationHistoryTest.kt @@ -19,6 +19,7 @@ package org.kiwix.kiwixmobile.page.history import android.os.Build +import androidx.compose.ui.test.junit4.createComposeRule import androidx.core.content.edit import androidx.core.net.toUri import androidx.lifecycle.Lifecycle @@ -44,6 +45,7 @@ import org.kiwix.kiwixmobile.BaseActivityTest import org.kiwix.kiwixmobile.R import org.kiwix.kiwixmobile.core.utils.LanguageUtils.Companion.handleLocaleChange import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil +import org.kiwix.kiwixmobile.core.utils.TestingUtils.COMPOSE_TEST_RULE_ORDER import org.kiwix.kiwixmobile.core.utils.TestingUtils.RETRY_RULE_ORDER import org.kiwix.kiwixmobile.main.KiwixMainActivity import org.kiwix.kiwixmobile.nav.destination.library.local.LocalLibraryFragmentDirections @@ -61,6 +63,9 @@ class NavigationHistoryTest : BaseActivityTest() { @JvmField val retryRule = RetryRule() + @get:Rule(order = COMPOSE_TEST_RULE_ORDER) + val composeTestRule = createComposeRule() + private lateinit var kiwixMainActivity: KiwixMainActivity @Before @@ -146,13 +151,13 @@ class NavigationHistoryTest : BaseActivityTest() { checkZimFileLoadedSuccessful(R.id.readerFragment) clickOnAndroidArticle() longClickOnBackwardButton() - assertBackwardNavigationHistoryDialogDisplayed() + assertBackwardNavigationHistoryDialogDisplayed(composeTestRule) pressBack() clickOnBackwardButton() longClickOnForwardButton() - assertForwardNavigationHistoryDialogDisplayed() - clickOnDeleteHistory() - assertDeleteDialogDisplayed() + assertForwardNavigationHistoryDialogDisplayed(composeTestRule) + clickOnDeleteHistory(composeTestRule) + assertDeleteDialogDisplayed(composeTestRule) pressBack() pressBack() } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt index e254f4300..647bad484 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt @@ -1005,9 +1005,9 @@ abstract class CoreReaderFragment : **/ val dialogFragment = NavigationHistoryDialog( if (isForwardHistory) { - getString(R.string.forward_history) + R.string.forward_history } else { - getString(R.string.backward_history) + R.string.backward_history }, navigationHistoryList, this diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/PageFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/PageFragment.kt index 9cda39cc3..f71cd2d42 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/PageFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/page/PageFragment.kt @@ -42,7 +42,6 @@ import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO 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 @@ -72,7 +71,6 @@ abstract class PageFragment : OnItemClickListener, BaseFragment(), FragmentActiv abstract val noItemsString: String abstract val switchString: String abstract val searchQueryHint: String - abstract val pageAdapter: PageAdapter abstract val switchIsChecked: Boolean abstract val deleteIconTitle: Int private val pageState: MutableState> = 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 80727191b..49ca11c88 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 @@ -43,6 +43,7 @@ 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.ui.components.ONE import org.kiwix.kiwixmobile.core.utils.ComposeDimens.EIGHT_DP import org.kiwix.kiwixmobile.core.utils.ComposeDimens.PAGE_LIST_ITEM_FAVICON_SIZE import org.kiwix.kiwixmobile.core.utils.ComposeDimens.SIXTEEN_DP @@ -87,7 +88,7 @@ fun PageListItem( text = page.title, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.weight(1f), - maxLines = 1, + maxLines = ONE, overflow = TextOverflow.Ellipsis ) } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/adapter/PageDelegate.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/adapter/PageDelegate.kt deleted file mode 100644 index 06a3f8a6d..000000000 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/adapter/PageDelegate.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Kiwix Android - * Copyright (c) 2020 Kiwix - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package org.kiwix.kiwixmobile.core.page.adapter - -import android.view.ViewGroup -import org.kiwix.kiwixmobile.core.base.adapter.AbsDelegateAdapter -import org.kiwix.kiwixmobile.core.databinding.HeaderDateBinding -import org.kiwix.kiwixmobile.core.databinding.ItemBookmarkHistoryBinding -import org.kiwix.kiwixmobile.core.extensions.ViewGroupExtensions.viewBinding -import org.kiwix.kiwixmobile.core.page.adapter.PageRelatedListItemViewHolder.DateItemViewHolder -import org.kiwix.kiwixmobile.core.page.adapter.PageRelatedListItemViewHolder.PageListItemViewHolder -import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.DateItem - -sealed class PageDelegate> : - AbsDelegateAdapter { - class PageItemDelegate( - private val itemClickListener: OnItemClickListener - ) : PageDelegate() { - override val itemClass = Page::class.java - - override fun createViewHolder(parent: ViewGroup) = - PageListItemViewHolder( - parent.viewBinding(ItemBookmarkHistoryBinding::inflate, false), - itemClickListener - ) - } - - class HistoryDateDelegate : PageDelegate() { - override val itemClass = DateItem::class.java - - override fun createViewHolder(parent: ViewGroup): DateItemViewHolder = - DateItemViewHolder( - parent.viewBinding(HeaderDateBinding::inflate, false) - ) - } -} diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/adapter/PageRelatedListItemViewHolder.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/adapter/PageRelatedListItemViewHolder.kt deleted file mode 100644 index 7c917695d..000000000 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/adapter/PageRelatedListItemViewHolder.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Kiwix Android - * Copyright (c) 2020 Kiwix - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package org.kiwix.kiwixmobile.core.page.adapter - -import android.view.View -import org.kiwix.kiwixmobile.core.R -import org.kiwix.kiwixmobile.core.base.adapter.BaseViewHolder -import org.kiwix.kiwixmobile.core.databinding.HeaderDateBinding -import org.kiwix.kiwixmobile.core.databinding.ItemBookmarkHistoryBinding -import org.kiwix.kiwixmobile.core.downloader.model.Base64String -import org.kiwix.kiwixmobile.core.extensions.setBitmap -import org.kiwix.kiwixmobile.core.extensions.setImageDrawableCompat -import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.DateItem -import org.threeten.bp.LocalDate -import org.threeten.bp.format.DateTimeFormatter -import org.threeten.bp.format.DateTimeParseException - -sealed class PageRelatedListItemViewHolder(containerView: View) : - BaseViewHolder(containerView) { - class PageListItemViewHolder( - private val itemBookmarkHistoryBinding: ItemBookmarkHistoryBinding, - private val itemClickListener: OnItemClickListener - ) : PageRelatedListItemViewHolder(itemBookmarkHistoryBinding.root) { - override fun bind(item: Page) { - itemBookmarkHistoryBinding.title.text = item.title - if (item.isSelected) { - itemBookmarkHistoryBinding.favicon.setImageDrawableCompat( - R.drawable.ic_check_circle_blue_24dp - ) - } else { - itemBookmarkHistoryBinding.favicon.setBitmap(Base64String(item.favicon)) - } - itemView.setOnClickListener { itemClickListener.onItemClick(item) } - itemView.setOnLongClickListener { itemClickListener.onItemLongClick(item) } - } - } - - class DateItemViewHolder(private val headerDateBinding: HeaderDateBinding) : - PageRelatedListItemViewHolder(headerDateBinding.root) { - override fun bind(item: DateItem) { - val todaysDate = LocalDate.now() - val yesterdayDate = todaysDate.minusDays(1) - val givenDate = - try { - LocalDate.parse(item.dateString, DateTimeFormatter.ofPattern("d MMM yyyy")) - } catch (ignore: DateTimeParseException) { - null - } - - when (givenDate) { - todaysDate -> headerDateBinding.headerDate.setText(R.string.time_today) - yesterdayDate -> headerDateBinding.headerDate.setText(R.string.time_yesterday) - else -> headerDateBinding.headerDate.text = item.dateString - } - } - } -} 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 cfda39f2a..cd21ac416 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 @@ -5,17 +5,11 @@ import org.kiwix.kiwixmobile.core.base.BaseActivity import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.cachedComponent import org.kiwix.kiwixmobile.core.extensions.viewModel import org.kiwix.kiwixmobile.core.page.PageFragment -import org.kiwix.kiwixmobile.core.page.adapter.PageAdapter -import org.kiwix.kiwixmobile.core.page.adapter.PageDelegate.PageItemDelegate import org.kiwix.kiwixmobile.core.page.bookmark.viewmodel.BookmarkViewModel class BookmarksFragment : PageFragment() { override val pageViewModel by lazy { viewModel(viewModelFactory) } - override val pageAdapter: PageAdapter by lazy { - PageAdapter(PageItemDelegate(this)) - } - override val screenTitle: Int = 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) } 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 8e01f27b5..2e39a7947 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 @@ -5,20 +5,11 @@ import org.kiwix.kiwixmobile.core.base.BaseActivity import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.cachedComponent import org.kiwix.kiwixmobile.core.extensions.viewModel import org.kiwix.kiwixmobile.core.page.PageFragment -import org.kiwix.kiwixmobile.core.page.adapter.PageAdapter -import org.kiwix.kiwixmobile.core.page.adapter.PageDelegate.HistoryDateDelegate -import org.kiwix.kiwixmobile.core.page.adapter.PageDelegate.PageItemDelegate import org.kiwix.kiwixmobile.core.page.history.viewmodel.HistoryViewModel -const val USER_CLEARED_HISTORY: String = "user_cleared_history" - class HistoryFragment : PageFragment() { override val pageViewModel by lazy { viewModel(viewModelFactory) } - override val pageAdapter by lazy { - PageAdapter(PageItemDelegate(this), HistoryDateDelegate()) - } - 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 = R.string.history diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/NavigationHistoryDialog.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/NavigationHistoryDialog.kt index fb1373dc1..85ce446af 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/NavigationHistoryDialog.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/NavigationHistoryDialog.kt @@ -24,39 +24,31 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.activity.OnBackPressedCallback -import androidx.appcompat.widget.Toolbar +import androidx.annotation.StringRes +import androidx.compose.ui.platform.ComposeView import androidx.fragment.app.DialogFragment -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView import org.kiwix.kiwixmobile.core.CoreApp import org.kiwix.kiwixmobile.core.R -import org.kiwix.kiwixmobile.core.databinding.DialogNavigationHistoryBinding -import org.kiwix.kiwixmobile.core.extensions.getDialogHostComposeView -import org.kiwix.kiwixmobile.core.main.DISABLE_ICON_ITEM_ALPHA -import org.kiwix.kiwixmobile.core.main.ENABLE_ICON_ITEM_ALPHA -import org.kiwix.kiwixmobile.core.page.history.adapter.NavigationHistoryAdapter -import org.kiwix.kiwixmobile.core.page.history.adapter.NavigationHistoryDelegate.NavigationDelegate +import org.kiwix.kiwixmobile.core.page.DELETE_MENU_ICON_TESTING_TAG import org.kiwix.kiwixmobile.core.page.history.adapter.NavigationHistoryListItem +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.dialog.AlertDialogShower +import org.kiwix.kiwixmobile.core.utils.dialog.DialogHost import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog import javax.inject.Inject class NavigationHistoryDialog( - private val toolbarTitle: String, + @StringRes private val titleId: Int, private val navigationHistoryList: MutableList, private val navigationHistoryClickListener: NavigationHistoryClickListener ) : DialogFragment() { - private var dialogNavigationHistoryBinding: DialogNavigationHistoryBinding? = null - private var navigationHistoryAdapter: NavigationHistoryAdapter? = null + private var composeView: ComposeView? = null @Inject lateinit var alertDialogShower: AlertDialogShower - private val toolbar by lazy { - dialogNavigationHistoryBinding?.root?.findViewById(R.id.toolbar) - } - private val deleteItem by lazy { toolbar?.menu?.findItem(R.id.menu_pages_clear) } - override fun onStart() { super.onStart() dialog?.let { @@ -79,46 +71,34 @@ class NavigationHistoryDialog( savedInstanceState: Bundle? ): View? { super.onCreateView(inflater, container, savedInstanceState) - dialogNavigationHistoryBinding = - DialogNavigationHistoryBinding.inflate(inflater, container, false) - return dialogNavigationHistoryBinding?.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - navigationHistoryAdapter = - NavigationHistoryAdapter(NavigationDelegate(::onItemClick)).apply { - items = navigationHistoryList + return ComposeView(requireContext()).apply { + setContent { + NavigationHistoryDialogScreen( + titleId, + navigationHistoryList, + listOf( + ActionMenuItem( + IconItem.Drawable(R.drawable.ic_delete_white_24dp), + R.string.pref_clear_all_history_title, + { showConfirmClearHistoryDialog() }, + isEnabled = navigationHistoryList.isNotEmpty(), + testingTag = DELETE_MENU_ICON_TESTING_TAG + ) + ), + { onItemClick(it) }, + { + NavigationIcon( + iconItem = IconItem.Drawable(R.drawable.ic_close_white_24dp), + onClick = { + dismissNavigationHistoryDialog() + } + ) + } + ) + DialogHost(alertDialogShower) } - toolbar?.apply { - title = toolbarTitle - setNavigationIcon(R.drawable.ic_close_white_24dp) - setNavigationOnClickListener { dismissNavigationHistoryDialog() } - inflateMenu(R.menu.menu_page) - this.menu?.findItem(R.id.menu_page_search)?.isVisible = false - } - dialogNavigationHistoryBinding?.apply { - root.addView(requireContext().getDialogHostComposeView(alertDialogShower)) - if (navigationHistoryList.isEmpty()) { - deleteItem?.isEnabled = false - deleteItem?.icon?.alpha = DISABLE_ICON_ITEM_ALPHA - searchNoResults.visibility = View.VISIBLE - navigationHistoryRecyclerView.visibility = View.GONE - } else { - deleteItem?.isEnabled = true - deleteItem?.icon?.alpha = ENABLE_ICON_ITEM_ALPHA - searchNoResults.visibility = View.GONE - navigationHistoryRecyclerView.visibility = View.VISIBLE - } - navigationHistoryRecyclerView.run { - adapter = navigationHistoryAdapter - layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false) - setHasFixedSize(true) - } - } - deleteItem?.setOnMenuItemClickListener { - showConfirmClearHistoryDialog() - true + }.also { + composeView = it } } @@ -151,8 +131,8 @@ class NavigationHistoryDialog( override fun onDestroyView() { super.onDestroyView() - navigationHistoryAdapter = null - dialogNavigationHistoryBinding = null + composeView?.disposeComposition() + composeView = null onBackPressedCallBack.remove() } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/NavigationHistoryDialogScreen.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/NavigationHistoryDialogScreen.kt new file mode 100644 index 000000000..0bf84774a --- /dev/null +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/NavigationHistoryDialogScreen.kt @@ -0,0 +1,144 @@ +/* + * Kiwix Android + * Copyright (c) 2025 Kiwix + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package org.kiwix.kiwixmobile.core.page.history + +import androidx.annotation.StringRes +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.testTag +import androidx.compose.ui.text.style.TextOverflow +import org.kiwix.kiwixmobile.core.R +import org.kiwix.kiwixmobile.core.page.NO_ITEMS_TEXT_TESTING_TAG +import org.kiwix.kiwixmobile.core.page.history.adapter.NavigationHistoryListItem +import org.kiwix.kiwixmobile.core.ui.components.KiwixAppBar +import org.kiwix.kiwixmobile.core.ui.components.ONE +import org.kiwix.kiwixmobile.core.ui.models.ActionMenuItem +import org.kiwix.kiwixmobile.core.ui.models.IconItem +import org.kiwix.kiwixmobile.core.ui.models.toPainter +import org.kiwix.kiwixmobile.core.ui.theme.KiwixDialogTheme +import org.kiwix.kiwixmobile.core.utils.ComposeDimens.EIGHT_DP +import org.kiwix.kiwixmobile.core.utils.ComposeDimens.PAGE_LIST_ITEM_FAVICON_SIZE +import org.kiwix.kiwixmobile.core.utils.ComposeDimens.SIXTEEN_DP + +@Suppress("ComposableLambdaParameterNaming") +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun NavigationHistoryDialogScreen( + @StringRes titleId: Int, + navigationHistoryList: MutableList, + actionMenuItems: List, + onNavigationItemClick: ((NavigationHistoryListItem) -> Unit), + navigationIcon: @Composable () -> Unit +) { + KiwixDialogTheme { + Scaffold( + topBar = { KiwixAppBar(titleId, navigationIcon, actionMenuItems) } + ) { paddingValues -> + Box( + modifier = Modifier + .fillMaxSize() + .background(Color.Transparent) + .imePadding() + .padding(paddingValues), + ) { + if (navigationHistoryList.isEmpty()) { + Text( + text = stringResource(R.string.no_history), + style = MaterialTheme.typography.headlineSmall, + modifier = Modifier + .align(Alignment.Center) + .semantics { testTag = NO_ITEMS_TEXT_TESTING_TAG } + ) + } else { + NavigationHistoryList(navigationHistoryList, onNavigationItemClick) + } + } + } + } +} + +@Composable +fun NavigationHistoryList( + navigationHistoryList: MutableList, + onNavigationItemClick: (NavigationHistoryListItem) -> Unit +) { + LazyColumn { + items(navigationHistoryList) { + NavigationHistoryItem(it, onNavigationItemClick) + } + } +} + +@Composable +private fun NavigationHistoryItem( + item: NavigationHistoryListItem, + onNavigationItemClick: (NavigationHistoryListItem) -> Unit +) { + Row( + modifier = Modifier + .fillMaxWidth() + .clickable( + onClick = { onNavigationItemClick(item) }, + ) + .padding( + horizontal = SIXTEEN_DP, + vertical = EIGHT_DP + ), + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = IconItem.MipmapImage(R.mipmap.ic_launcher_round).toPainter(), + contentDescription = stringResource(R.string.fav_icon), + modifier = Modifier + .size(PAGE_LIST_ITEM_FAVICON_SIZE) + ) + + Spacer(modifier = Modifier.width(SIXTEEN_DP)) + + Text( + text = item.title, + style = MaterialTheme.typography.bodyLarge, + modifier = Modifier.weight(1f), + maxLines = ONE, + overflow = TextOverflow.Ellipsis + ) + } +} diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/NavigationHistoryAdapter.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/NavigationHistoryAdapter.kt deleted file mode 100644 index 9aed15372..000000000 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/NavigationHistoryAdapter.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Kiwix Android - * Copyright (c) 2023 Kiwix - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package org.kiwix.kiwixmobile.core.page.history.adapter - -import org.kiwix.kiwixmobile.core.base.adapter.AdapterDelegate -import org.kiwix.kiwixmobile.core.base.adapter.BaseDelegateAdapter - -class NavigationHistoryAdapter( - vararg delegates: AdapterDelegate -) : BaseDelegateAdapter(*delegates) { - override fun getIdFor(item: NavigationHistoryListItem) = item.title.hashCode().toLong() -} diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/NavigationHistoryDelegate.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/NavigationHistoryDelegate.kt deleted file mode 100644 index 30aef7ae5..000000000 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/NavigationHistoryDelegate.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Kiwix Android - * Copyright (c) 2023 Kiwix - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package org.kiwix.kiwixmobile.core.page.history.adapter - -import android.view.ViewGroup -import org.kiwix.kiwixmobile.core.base.adapter.AbsDelegateAdapter -import org.kiwix.kiwixmobile.core.databinding.ItemBookmarkHistoryBinding -import org.kiwix.kiwixmobile.core.extensions.ViewGroupExtensions.viewBinding - -sealed class NavigationHistoryDelegate< - I : NavigationHistoryListItem, - out VH : NavigationHistoryViewHolder - > : AbsDelegateAdapter { - class NavigationDelegate(private val onClickListener: ((NavigationHistoryListItem) -> Unit)) : - NavigationHistoryDelegate< - NavigationHistoryListItem, - NavigationHistoryViewHolder.HistoryViewHolder - >() { - override val itemClass = NavigationHistoryListItem::class.java - - override fun createViewHolder(parent: ViewGroup) = - NavigationHistoryViewHolder.HistoryViewHolder( - parent.viewBinding(ItemBookmarkHistoryBinding::inflate, false), - onClickListener - ) - } -} diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/NavigationHistoryViewHolder.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/NavigationHistoryViewHolder.kt deleted file mode 100644 index 24e718ca6..000000000 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/NavigationHistoryViewHolder.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Kiwix Android - * Copyright (c) 2023 Kiwix - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package org.kiwix.kiwixmobile.core.page.history.adapter - -import android.view.View -import org.kiwix.kiwixmobile.core.R -import org.kiwix.kiwixmobile.core.base.adapter.BaseViewHolder -import org.kiwix.kiwixmobile.core.databinding.ItemBookmarkHistoryBinding -import org.kiwix.kiwixmobile.core.extensions.setImageDrawableCompat - -sealed class NavigationHistoryViewHolder(containerView: View) : - BaseViewHolder(containerView) { - class HistoryViewHolder( - private val itemBookmarkHistoryBinding: ItemBookmarkHistoryBinding, - private val onClickListener: ((NavigationHistoryListItem) -> Unit) - ) : NavigationHistoryViewHolder(itemBookmarkHistoryBinding.root) { - override fun bind(item: NavigationHistoryListItem) { - containerView.setOnClickListener { onClickListener(item) } - itemBookmarkHistoryBinding.apply { - title.text = item.title - favicon.setImageDrawableCompat(R.mipmap.ic_launcher_round) - } - } - } -} 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 776dad427..5b9d35c95 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 @@ -23,8 +23,6 @@ import org.kiwix.kiwixmobile.core.base.BaseActivity import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.cachedComponent import org.kiwix.kiwixmobile.core.extensions.viewModel import org.kiwix.kiwixmobile.core.page.PageFragment -import org.kiwix.kiwixmobile.core.page.adapter.PageAdapter -import org.kiwix.kiwixmobile.core.page.adapter.PageDelegate import org.kiwix.kiwixmobile.core.page.notes.viewmodel.NotesViewModel class NotesFragment : PageFragment() { @@ -32,10 +30,6 @@ class NotesFragment : PageFragment() { override val screenTitle: Int = R.string.pref_notes - override val pageAdapter: PageAdapter by lazy { - PageAdapter(PageDelegate.PageItemDelegate(this)) - } - 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: Int by lazy { diff --git a/core/src/main/res/layout/dialog_navigation_history.xml b/core/src/main/res/layout/dialog_navigation_history.xml deleted file mode 100644 index 153001b26..000000000 --- a/core/src/main/res/layout/dialog_navigation_history.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - diff --git a/core/src/main/res/layout/header_date.xml b/core/src/main/res/layout/header_date.xml deleted file mode 100644 index cfe515c17..000000000 --- a/core/src/main/res/layout/header_date.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - diff --git a/core/src/main/res/layout/item_bookmark_history.xml b/core/src/main/res/layout/item_bookmark_history.xml deleted file mode 100644 index 8e101290b..000000000 --- a/core/src/main/res/layout/item_bookmark_history.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - -