diff --git a/app/src/main/java/org/mozilla/fenix/ext/Context.kt b/app/src/main/java/org/mozilla/fenix/ext/Context.kt index 0c6d68a1f..8e7dc2f5f 100644 --- a/app/src/main/java/org/mozilla/fenix/ext/Context.kt +++ b/app/src/main/java/org/mozilla/fenix/ext/Context.kt @@ -17,7 +17,6 @@ import android.view.View import android.view.ViewGroup import androidx.annotation.AttrRes import androidx.annotation.ColorInt -import androidx.annotation.ColorRes import androidx.annotation.StringRes import androidx.core.content.ContextCompat import androidx.fragment.app.FragmentActivity @@ -100,14 +99,9 @@ fun Context.share(text: String, subject: String = ""): Boolean { fun Context.getRootView(): View? = asActivity()?.window?.decorView?.findViewById(android.R.id.content) as? ViewGroup -/** - * Returns the color resource corresponding to the attribute. - */ -@ColorRes -fun Context.getColorResFromAttr(@AttrRes attr: Int) = ThemeManager.resolveAttribute(attr, this) - /** * Returns the color int corresponding to the attribute. */ @ColorInt -fun Context.getColorFromAttr(@AttrRes attr: Int) = ContextCompat.getColor(this, getColorResFromAttr(attr)) +fun Context.getColorFromAttr(@AttrRes attr: Int) = + ContextCompat.getColor(this, ThemeManager.resolveAttribute(attr, this)) diff --git a/app/src/main/java/org/mozilla/fenix/library/LibraryPageFragment.kt b/app/src/main/java/org/mozilla/fenix/library/LibraryPageFragment.kt new file mode 100644 index 000000000..93625ba69 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/library/LibraryPageFragment.kt @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.library + +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.findNavController +import org.mozilla.fenix.BrowsingModeManager +import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.R +import org.mozilla.fenix.ext.components + +abstract class LibraryPageFragment : Fragment() { + + abstract val selectedItems: Set + + protected fun close() { + findNavController().popBackStack(R.id.libraryFragment, true) + } + + protected fun openItemsInNewTab(private: Boolean = false, toUrl: (T) -> String?) { + context?.components?.useCases?.tabsUseCases?.let { tabsUseCases -> + val addTab = if (private) tabsUseCases.addPrivateTab else tabsUseCases.addTab + selectedItems.asSequence() + .mapNotNull(toUrl) + .forEach { url -> + addTab.invoke(url) + } + } + + (activity as HomeActivity).browsingModeManager.mode = if (private) { + BrowsingModeManager.Mode.Private + } else { + BrowsingModeManager.Mode.Normal + } + (activity as HomeActivity).supportActionBar?.hide() + } +} diff --git a/app/src/main/java/org/mozilla/fenix/library/LibraryPageView.kt b/app/src/main/java/org/mozilla/fenix/library/LibraryPageView.kt index 138179705..f2ed33d8f 100644 --- a/app/src/main/java/org/mozilla/fenix/library/LibraryPageView.kt +++ b/app/src/main/java/org/mozilla/fenix/library/LibraryPageView.kt @@ -11,29 +11,44 @@ import android.graphics.PorterDuffColorFilter import android.view.ViewGroup import android.widget.ActionMenuView import android.widget.ImageButton -import androidx.annotation.ColorRes +import androidx.annotation.ColorInt import androidx.appcompat.view.menu.ActionMenuItemView import androidx.appcompat.widget.Toolbar import androidx.core.content.ContextCompat import androidx.core.view.forEach +import kotlinx.android.extensions.LayoutContainer import org.mozilla.fenix.R import org.mozilla.fenix.ext.asActivity +import org.mozilla.fenix.ext.getColorFromAttr open class LibraryPageView( - container: ViewGroup -) { - protected val context: Context = container.context + override val containerView: ViewGroup +) : LayoutContainer { + protected val context: Context inline get() = containerView.context protected val activity = context.asActivity() + protected fun setUiForNormalMode(title: String?) { + activity?.title = title + setToolbarColors( + ContextCompat.getColor(context, R.color.white_color), + context.getColorFromAttr(R.attr.accentHighContrast) + ) + } + + protected fun setUiForSelectingMode(title: String?) { + activity?.title = title + setToolbarColors( + context.getColorFromAttr(R.attr.primaryText), + context.getColorFromAttr(R.attr.foundation) + ) + } + /** * Adjust the colors of the [Toolbar] on the top of the screen. */ - protected fun setToolbarColors(@ColorRes foregroundRes: Int, @ColorRes backgroundRes: Int) { + private fun setToolbarColors(@ColorInt foreground: Int, @ColorInt background: Int) { val toolbar = activity?.findViewById(R.id.navigationToolbar) - val foreground = ContextCompat.getColor(context, foregroundRes) - val background = ContextCompat.getColor(context, backgroundRes) - toolbar?.apply { setBackgroundColor(background) setTitleTextColor(foreground) diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt index bf72f49be..083aec15d 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt @@ -15,7 +15,6 @@ import android.view.View import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat -import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.lifecycle.Observer import androidx.lifecycle.lifecycleScope @@ -34,8 +33,6 @@ import mozilla.components.concept.sync.OAuthAccount import mozilla.components.concept.sync.Profile import mozilla.components.lib.state.ext.consumeFrom import mozilla.components.support.base.feature.BackHandler -import org.mozilla.fenix.BrowsingModeManager -import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.components.FenixSnackbarPresenter import org.mozilla.fenix.components.StoreProvider @@ -47,10 +44,11 @@ import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.setRootTitles import org.mozilla.fenix.ext.urlToTrimmedHost import org.mozilla.fenix.ext.withOptionalDesktopFolders +import org.mozilla.fenix.library.LibraryPageFragment import org.mozilla.fenix.utils.allowUndo @SuppressWarnings("TooManyFunctions", "LargeClass") -class BookmarkFragment : Fragment(), BackHandler, AccountObserver { +class BookmarkFragment : LibraryPageFragment(), BackHandler, AccountObserver { private lateinit var bookmarkStore: BookmarkStore private lateinit var bookmarkView: BookmarkView @@ -75,6 +73,8 @@ class BookmarkFragment : Fragment(), BackHandler, AccountObserver { private val metrics get() = context?.components?.analytics?.metrics + override val selectedItems get() = bookmarkStore.state.mode.selectedItems + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_bookmark, container, false) @@ -173,8 +173,7 @@ class BookmarkFragment : Fragment(), BackHandler, AccountObserver { override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.libraryClose -> { - navigation - .popBackStack(R.id.libraryFragment, true) + close() true } R.id.add_bookmark_folder -> { @@ -186,20 +185,21 @@ class BookmarkFragment : Fragment(), BackHandler, AccountObserver { true } R.id.open_bookmarks_in_new_tabs_multi_select -> { - getSelectedBookmarks().forEach { node -> - node.url?.let { - context?.components?.useCases?.tabsUseCases?.addTab?.invoke(it) - } - } + openItemsInNewTab { node -> node.url } - (activity as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Normal - (activity as HomeActivity).supportActionBar?.hide() nav(R.id.bookmarkFragment, BookmarkFragmentDirections.actionBookmarkFragmentToHomeFragment()) metrics?.track(Event.OpenedBookmarksInNewTabs) true } + R.id.open_bookmarks_in_private_tabs_multi_select -> { + openItemsInNewTab(private = true) { node -> node.url } + + nav(R.id.bookmarkFragment, BookmarkFragmentDirections.actionBookmarkFragmentToHomeFragment()) + metrics?.track(Event.OpenedBookmarksInPrivateTabs) + true + } R.id.edit_bookmark_multi_select -> { - val bookmark = getSelectedBookmarks().first() + val bookmark = bookmarkStore.state.mode.selectedItems.first() nav( R.id.bookmarkFragment, BookmarkFragmentDirections @@ -207,21 +207,8 @@ class BookmarkFragment : Fragment(), BackHandler, AccountObserver { ) true } - R.id.open_bookmarks_in_private_tabs_multi_select -> { - getSelectedBookmarks().forEach { node -> - node.url?.let { - context?.components?.useCases?.tabsUseCases?.addPrivateTab?.invoke(it) - } - } - - (activity as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Private - (activity as HomeActivity).supportActionBar?.hide() - nav(R.id.bookmarkFragment, BookmarkFragmentDirections.actionBookmarkFragmentToHomeFragment()) - metrics?.track(Event.OpenedBookmarksInPrivateTabs) - true - } R.id.delete_bookmarks_multi_select -> { - deleteMulti(getSelectedBookmarks()) + deleteMulti(bookmarkStore.state.mode.selectedItems) true } else -> super.onOptionsItemSelected(item) @@ -247,8 +234,6 @@ class BookmarkFragment : Fragment(), BackHandler, AccountObserver { override fun onProfileUpdated(profile: Profile) { } - private fun getSelectedBookmarks() = bookmarkView.getSelected() - private suspend fun refreshBookmarks() { context?.bookmarkStorage()?.getTree(bookmarkStore.state.tree!!.guid, false).withOptionalDesktopFolders(context) ?.let { node -> @@ -265,7 +250,7 @@ class BookmarkFragment : Fragment(), BackHandler, AccountObserver { super.onPause() } - private suspend fun deleteSelectedBookmarks(selected: Set = getSelectedBookmarks()) { + private suspend fun deleteSelectedBookmarks(selected: Set) { selected.forEach { context?.bookmarkStorage()?.deleteNode(it.guid) } diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkStore.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkStore.kt index 57ae6dd42..969f5a1e9 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkStore.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkStore.kt @@ -22,8 +22,10 @@ class BookmarkStore( */ data class BookmarkState(val tree: BookmarkNode?, val mode: Mode = Mode.Normal) : State { sealed class Mode { + open val selectedItems = emptySet() + object Normal : Mode() - data class Selecting(val selectedItems: Set) : Mode() + data class Selecting(override val selectedItems: Set) : Mode() } } @@ -46,32 +48,22 @@ sealed class BookmarkAction : Action { fun bookmarkStateReducer(state: BookmarkState, action: BookmarkAction): BookmarkState { return when (action) { is BookmarkAction.Change -> { - val mode = - if (state.mode is BookmarkState.Mode.Selecting) { - val items = state.mode.selectedItems.filter { - it in action.tree - }.toSet() - if (items.isEmpty()) BookmarkState.Mode.Normal else BookmarkState.Mode.Selecting(items) - } else state.mode - state.copy(tree = action.tree, mode = mode) - } - is BookmarkAction.Select -> { - val selectedItems = if (state.mode is BookmarkState.Mode.Selecting) { - state.mode.selectedItems + action.item - } else setOf(action.item) - state.copy(mode = BookmarkState.Mode.Selecting(selectedItems)) + val items = state.mode.selectedItems.filter { it in action.tree } + state.copy( + tree = action.tree, + mode = if (items.isEmpty()) BookmarkState.Mode.Normal else BookmarkState.Mode.Selecting(items.toSet()) + ) } + is BookmarkAction.Select -> + state.copy(mode = BookmarkState.Mode.Selecting(state.mode.selectedItems + action.item)) is BookmarkAction.Deselect -> { - val selectedItems = if (state.mode is BookmarkState.Mode.Selecting) { - state.mode.selectedItems - action.item - } else setOf() - val mode = - if (selectedItems.isEmpty()) BookmarkState.Mode.Normal else BookmarkState.Mode.Selecting(selectedItems) - state.copy(mode = mode) + val items = state.mode.selectedItems - action.item + state.copy( + mode = if (items.isEmpty()) BookmarkState.Mode.Normal else BookmarkState.Mode.Selecting(items) + ) } - BookmarkAction.DeselectAll -> { + BookmarkAction.DeselectAll -> state.copy(mode = BookmarkState.Mode.Normal) - } } } diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkView.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkView.kt index 309a9f7f5..bab1214cd 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkView.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkView.kt @@ -5,16 +5,13 @@ package org.mozilla.fenix.library.bookmarks import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup import android.widget.LinearLayout -import kotlinx.android.extensions.LayoutContainer import kotlinx.android.synthetic.main.component_bookmark.view.* import mozilla.appservices.places.BookmarkRoot import mozilla.components.concept.storage.BookmarkNode import mozilla.components.support.base.feature.BackHandler import org.mozilla.fenix.R -import org.mozilla.fenix.ext.getColorResFromAttr import org.mozilla.fenix.library.LibraryPageView /** @@ -129,12 +126,13 @@ interface BookmarkViewInteractor { } class BookmarkView( - private val container: ViewGroup, + container: ViewGroup, val interactor: BookmarkViewInteractor -) : LibraryPageView(container), LayoutContainer, BackHandler { +) : LibraryPageView(container), BackHandler { - override val containerView: View? - get() = container + val view: LinearLayout = LayoutInflater.from(container.context) + .inflate(R.layout.component_bookmark, container, true) + .findViewById(R.id.bookmarks_wrapper) var mode: BookmarkState.Mode = BookmarkState.Mode.Normal private set @@ -142,9 +140,6 @@ class BookmarkView( private set private var canGoBack = false - val view: LinearLayout = LayoutInflater.from(container.context) - .inflate(R.layout.component_bookmark, container, true) as LinearLayout - private val bookmarkAdapter: BookmarkAdapter init { @@ -155,17 +150,19 @@ class BookmarkView( } fun update(state: BookmarkState) { - canGoBack = !(listOf(null, BookmarkRoot.Root.id).contains(state.tree?.guid)) - if (state.tree != tree) { - tree = state.tree - } + canGoBack = BookmarkRoot.Root.matches(state.tree) + tree = state.tree if (state.mode != mode) { mode = state.mode interactor.switchMode(mode) } - when (val modeCopy = state.mode) { - is BookmarkState.Mode.Normal -> setUIForNormalMode(state.tree) - is BookmarkState.Mode.Selecting -> setUIForSelectingMode(state.tree, modeCopy) + + bookmarkAdapter.updateData(state.tree, mode) + when (state.mode) { + is BookmarkState.Mode.Normal -> + setUiForNormalMode(state.tree) + is BookmarkState.Mode.Selecting -> + setUiForSelectingMode(context.getString(R.string.bookmarks_multi_select_title, mode.selectedItems.size)) } } @@ -183,34 +180,16 @@ class BookmarkView( } } - fun getSelected(): Set = bookmarkAdapter.selected - - private fun setUIForSelectingMode( - root: BookmarkNode?, - mode: BookmarkState.Mode.Selecting - ) { - bookmarkAdapter.updateData(root, mode) - activity?.title = - context.getString(R.string.bookmarks_multi_select_title, mode.selectedItems.size) - setToolbarColors( - R.color.white_color, - context.getColorResFromAttr(R.attr.accentHighContrast) + private fun setUiForNormalMode(root: BookmarkNode?) { + super.setUiForNormalMode( + if (BookmarkRoot.Mobile.matches(root)) context.getString(R.string.library_bookmarks) else root?.title ) } - private fun setUIForNormalMode(root: BookmarkNode?) { - bookmarkAdapter.updateData(root, BookmarkState.Mode.Normal) - setTitle(root) - setToolbarColors( - context.getColorResFromAttr(R.attr.primaryText), - context.getColorResFromAttr(R.attr.foundation) - ) - } - - private fun setTitle(root: BookmarkNode?) { - activity?.title = when (root?.guid) { - BookmarkRoot.Mobile.id, null -> context.getString(R.string.library_bookmarks) - else -> root.title - } + /** + * Returns true if [root] matches the bookmark root ID. + */ + private fun BookmarkRoot.matches(root: BookmarkNode?): Boolean { + return root == null || id == root.guid } } diff --git a/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragment.kt b/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragment.kt index 86626d772..6c3801c56 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragment.kt @@ -17,10 +17,8 @@ import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat -import androidx.fragment.app.Fragment import androidx.lifecycle.Observer import androidx.lifecycle.lifecycleScope -import androidx.navigation.Navigation import kotlinx.android.synthetic.main.fragment_history.view.* import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.launch @@ -37,10 +35,11 @@ import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.requireComponents +import org.mozilla.fenix.library.LibraryPageFragment import org.mozilla.fenix.share.ShareTab @SuppressWarnings("TooManyFunctions") -class HistoryFragment : Fragment(), BackHandler { +class HistoryFragment : LibraryPageFragment(), BackHandler { private lateinit var historyStore: HistoryStore private lateinit var historyView: HistoryView private lateinit var historyInteractor: HistoryInteractor @@ -71,6 +70,8 @@ class HistoryFragment : Fragment(), BackHandler { return view } + override val selectedItems get() = historyStore.state.mode.selectedItems + private fun invalidateOptionsMenu() { activity?.invalidateOptionsMenu() } @@ -91,7 +92,7 @@ class HistoryFragment : Fragment(), BackHandler { setHasOptionsMenu(true) } - fun deleteHistoryItems(items: Set) { + private fun deleteHistoryItems(items: Set) { lifecycleScope.launch { val storage = context?.components?.core?.historyStorage for (item in items) { @@ -126,10 +127,8 @@ class HistoryFragment : Fragment(), BackHandler { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { val mode = historyStore.state.mode when (mode) { - HistoryState.Mode.Normal -> - R.menu.library_menu - is HistoryState.Mode.Editing -> - R.menu.history_select_multi + HistoryState.Mode.Normal -> R.menu.library_menu + is HistoryState.Mode.Editing -> R.menu.history_select_multi else -> null }?.let { inflater.inflate(it, menu) } @@ -146,11 +145,10 @@ class HistoryFragment : Fragment(), BackHandler { override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { R.id.share_history_multi_select -> { - val selectedHistory = - (historyStore.state.mode as? HistoryState.Mode.Editing)?.selectedItems ?: setOf() + val selectedHistory = historyStore.state.mode.selectedItems when { selectedHistory.size == 1 -> - share(selectedHistory.first().url) + share(url = selectedHistory.first().url) selectedHistory.size > 1 -> { val shareTabs = selectedHistory.map { ShareTab(it.url, it.title) } share(tabs = shareTabs) @@ -159,36 +157,25 @@ class HistoryFragment : Fragment(), BackHandler { true } R.id.libraryClose -> { - Navigation.findNavController(requireActivity(), R.id.container) - .popBackStack(R.id.libraryFragment, true) + close() true } R.id.delete_history_multi_select -> { - val components = context?.applicationContext?.components!! - val selectedHistory = - (historyStore.state.mode as? HistoryState.Mode.Editing)?.selectedItems ?: setOf() + val components = context?.components!! lifecycleScope.launch(Main) { - deleteSelectedHistory(selectedHistory, components) + deleteSelectedHistory(historyStore.state.mode.selectedItems, components) viewModel.invalidate() historyStore.dispatch(HistoryAction.ExitDeletionMode) } true } R.id.open_history_in_new_tabs_multi_select -> { - val selectedHistory = - (historyStore.state.mode as? HistoryState.Mode.Editing)?.selectedItems ?: setOf() - requireComponents.useCases.tabsUseCases.addTab.let { useCase -> - for (selectedItem in selectedHistory) { - requireComponents.analytics.metrics.track(Event.HistoryItemOpened) - useCase.invoke(selectedItem.url) - } + openItemsInNewTab { selectedItem -> + requireComponents.analytics.metrics.track(Event.HistoryItemOpened) + selectedItem.url } - (activity as HomeActivity).apply { - browsingModeManager.mode = BrowsingModeManager.Mode.Normal - supportActionBar?.hide() - } nav( R.id.historyFragment, HistoryFragmentDirections.actionHistoryFragmentToHomeFragment() @@ -196,13 +183,9 @@ class HistoryFragment : Fragment(), BackHandler { true } R.id.open_history_in_private_tabs_multi_select -> { - val selectedHistory = - (historyStore.state.mode as? HistoryState.Mode.Editing)?.selectedItems ?: setOf() - requireComponents.useCases.tabsUseCases.addPrivateTab.let { useCase -> - for (selectedItem in selectedHistory) { - requireComponents.analytics.metrics.track(Event.HistoryItemOpened) - useCase.invoke(selectedItem.url) - } + openItemsInNewTab(private = true) { selectedItem -> + requireComponents.analytics.metrics.track(Event.HistoryItemOpened) + selectedItem.url } (activity as HomeActivity).apply { @@ -220,7 +203,7 @@ class HistoryFragment : Fragment(), BackHandler { override fun onBackPressed(): Boolean = historyView.onBackPressed() - fun openItem(item: HistoryItem) { + private fun openItem(item: HistoryItem) { requireComponents.analytics.metrics.track(Event.HistoryItemOpened) (activity as HomeActivity).openToBrowserAndLoad( searchTermOrURL = item.url, diff --git a/app/src/main/java/org/mozilla/fenix/library/history/HistoryInteractor.kt b/app/src/main/java/org/mozilla/fenix/library/history/HistoryInteractor.kt index 898eb409f..b5f279d3a 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/HistoryInteractor.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/HistoryInteractor.kt @@ -16,8 +16,7 @@ class HistoryInteractor( private val deleteHistoryItems: (Set) -> Unit ) : HistoryViewInteractor { override fun onItemPress(item: HistoryItem) { - val mode = store.state.mode - when (mode) { + when (val mode = store.state.mode) { is HistoryState.Mode.Normal -> openToBrowser(item) is HistoryState.Mode.Editing -> { val isSelected = mode.selectedItems.contains(item) @@ -32,9 +31,7 @@ class HistoryInteractor( } override fun onItemLongPress(item: HistoryItem) { - val isSelected = (store.state.mode as? HistoryState.Mode.Editing)?.let { - it.selectedItems.contains(item) - } ?: false + val isSelected = store.state.mode.selectedItems.contains(item) if (isSelected) { store.dispatch(HistoryAction.RemoveItemForRemoval(item)) diff --git a/app/src/main/java/org/mozilla/fenix/library/history/HistoryStore.kt b/app/src/main/java/org/mozilla/fenix/library/history/HistoryStore.kt index 1af172254..1be5675ee 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/HistoryStore.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/HistoryStore.kt @@ -41,9 +41,11 @@ sealed class HistoryAction : Action { */ data class HistoryState(val items: List, val mode: Mode) : State { sealed class Mode { + open val selectedItems = emptySet() + object Normal : Mode() - data class Editing(val selectedItems: Set) : Mode() object Deleting : Mode() + data class Editing(override val selectedItems: Set) : Mode() } } @@ -52,24 +54,13 @@ data class HistoryState(val items: List, val mode: Mode) : State { */ fun historyStateReducer(state: HistoryState, action: HistoryAction): HistoryState { return when (action) { - is HistoryAction.AddItemForRemoval -> { - val mode = state.mode - if (mode is HistoryState.Mode.Editing) { - val items = mode.selectedItems + setOf(action.item) - state.copy(mode = HistoryState.Mode.Editing(items)) - } else { - state.copy(mode = HistoryState.Mode.Editing(setOf(action.item))) - } - } + is HistoryAction.AddItemForRemoval -> + state.copy(mode = HistoryState.Mode.Editing(state.mode.selectedItems + action.item)) is HistoryAction.RemoveItemForRemoval -> { - var mode = state.mode - - if (mode is HistoryState.Mode.Editing) { - val items = mode.selectedItems.minus(action.item) - state.copy(mode = HistoryState.Mode.Editing(items)) - } else { - state - } + val selected = state.mode.selectedItems - action.item + state.copy( + mode = if (selected.isEmpty()) HistoryState.Mode.Normal else HistoryState.Mode.Editing(selected) + ) } is HistoryAction.ExitEditMode -> state.copy(mode = HistoryState.Mode.Normal) is HistoryAction.EnterDeletionMode -> state.copy(mode = HistoryState.Mode.Deleting) diff --git a/app/src/main/java/org/mozilla/fenix/library/history/HistoryView.kt b/app/src/main/java/org/mozilla/fenix/library/history/HistoryView.kt index 13c2a079b..d7b9c524a 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/HistoryView.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/HistoryView.kt @@ -4,27 +4,17 @@ package org.mozilla.fenix.library.history -import android.graphics.PorterDuff -import android.graphics.PorterDuffColorFilter import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup -import android.widget.ImageButton -import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.widget.Toolbar import androidx.constraintlayout.widget.ConstraintLayout -import androidx.core.content.ContextCompat import androidx.core.view.isVisible import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.SimpleItemAnimator -import kotlinx.android.extensions.LayoutContainer import kotlinx.android.synthetic.main.component_history.* import kotlinx.android.synthetic.main.component_history.view.* -import kotlinx.android.synthetic.main.component_history.view.history_list import mozilla.components.support.base.feature.BackHandler import org.mozilla.fenix.R -import org.mozilla.fenix.ext.asActivity -import org.mozilla.fenix.ext.getColorResFromAttr +import org.mozilla.fenix.library.LibraryPageView /** * Interface for the HistoryViewInteractor. This interface is implemented by objects that want @@ -73,27 +63,22 @@ interface HistoryViewInteractor { * View that contains and configures the History List */ class HistoryView( - private val container: ViewGroup, + container: ViewGroup, val interactor: HistoryInteractor -) : LayoutContainer, BackHandler { +) : LibraryPageView(container), BackHandler { val view: ConstraintLayout = LayoutInflater.from(container.context) .inflate(R.layout.component_history, container, true) .findViewById(R.id.history_wrapper) - override val containerView: View? - get() = container - - val historyAdapter: HistoryAdapter private var items: List = listOf() - private val context = container.context var mode: HistoryState.Mode = HistoryState.Mode.Normal private set - private val activity = context?.asActivity() - private val layoutManager = LinearLayoutManager(container.context) - init { - historyAdapter = HistoryAdapter(interactor) + val historyAdapter = HistoryAdapter(interactor) + private val layoutManager = LinearLayoutManager(container.context) + + init { view.history_list.apply { layoutManager = this@HistoryView.layoutManager adapter = historyAdapter @@ -102,37 +87,36 @@ class HistoryView( } fun update(state: HistoryState) { - view.progress_bar.visibility = - if (state.mode is HistoryState.Mode.Deleting) View.VISIBLE else View.GONE + val oldMode = mode - if (state.mode != mode) { + view.progress_bar.isVisible = state.mode === HistoryState.Mode.Deleting + items = state.items + mode = state.mode + + if (state.mode != oldMode) { interactor.onModeSwitched() historyAdapter.updateMode(state.mode) - val oldMode = mode - if (oldMode is HistoryState.Mode.Editing) { - oldMode.selectedItems.forEach { - historyAdapter.notifyItemChanged(it.id) - } + // Deselect all the previously selected items + oldMode.selectedItems.forEach { + historyAdapter.notifyItemChanged(it.id) } } - (state.mode as? HistoryState.Mode.Editing)?.also { - val oldMode = (mode as? HistoryState.Mode.Editing) - val unselectedItems = oldMode?.selectedItems?.minus(it.selectedItems) ?: setOf() + if (state.mode is HistoryState.Mode.Editing) { + val unselectedItems = oldMode.selectedItems - state.mode.selectedItems - it.selectedItems.union(unselectedItems).forEach { item -> + state.mode.selectedItems.union(unselectedItems).forEach { item -> historyAdapter.notifyItemChanged(item.id) } } - items = state.items when (val mode = state.mode) { - is HistoryState.Mode.Normal -> setUIForNormalMode() - is HistoryState.Mode.Editing -> setUIForSelectingMode(mode.selectedItems.size) + is HistoryState.Mode.Normal -> + setUiForNormalMode(context.getString(R.string.library_history)) + is HistoryState.Mode.Editing -> + setUiForSelectingMode(context.getString(R.string.history_multi_select_title, mode.selectedItems.size)) } - - mode = state.mode } fun updateEmptyState(userHasHistory: Boolean) { @@ -140,59 +124,6 @@ class HistoryView( history_empty_view.isVisible = !userHasHistory } - private fun setUIForSelectingMode(selectedItemSize: Int) { - activity?.title = - context.getString(R.string.history_multi_select_title, selectedItemSize) - setToolbarColors( - R.color.white_color, - context!!.getColorResFromAttr(R.attr.accentHighContrast) - ) - } - - private fun setUIForNormalMode() { - activity?.title = context.getString(R.string.library_history) - setToolbarColors( - context!!.getColorResFromAttr(R.attr.primaryText), - context.getColorResFromAttr(R.attr.foundation) - ) - } - - private fun setToolbarColors(foreground: Int, background: Int) { - val toolbar = (activity as AppCompatActivity).findViewById(R.id.navigationToolbar) - val colorFilter = PorterDuffColorFilter( - ContextCompat.getColor(context, foreground), - PorterDuff.Mode.SRC_IN - ) - toolbar.setBackgroundColor(ContextCompat.getColor(context, background)) - toolbar.setTitleTextColor(ContextCompat.getColor(context, foreground)) - - themeToolbar( - toolbar, foreground, - background, colorFilter - ) - } - - private fun themeToolbar( - toolbar: Toolbar, - textColor: Int, - backgroundColor: Int, - colorFilter: PorterDuffColorFilter? = null - ) { - toolbar.setTitleTextColor(ContextCompat.getColor(context!!, textColor)) - toolbar.setBackgroundColor(ContextCompat.getColor(context, backgroundColor)) - - if (colorFilter == null) { - return - } - - toolbar.overflowIcon?.colorFilter = colorFilter - (0 until toolbar.childCount).forEach { - when (val item = toolbar.getChildAt(it)) { - is ImageButton -> item.drawable.colorFilter = colorFilter - } - } - } - override fun onBackPressed(): Boolean { return interactor.onBackPressed() } diff --git a/app/src/main/res/layout/component_bookmark.xml b/app/src/main/res/layout/component_bookmark.xml index bbc73468c..52ba0ca14 100644 --- a/app/src/main/res/layout/component_bookmark.xml +++ b/app/src/main/res/layout/component_bookmark.xml @@ -6,6 +6,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/bookmarks_wrapper" android:layout_width="match_parent" android:layout_height="match_parent"> @@ -17,7 +18,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - tools:listitem="@layout/bookmark_row" /> + tools:listitem="@layout/library_site_item" />