diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkComponent.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkComponent.kt index c920aa471..5b9bd010d 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkComponent.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkComponent.kt @@ -67,7 +67,7 @@ sealed class BookmarkAction : Action { data class Deselect(val item: BookmarkNode) : BookmarkAction() data class Delete(val item: BookmarkNode) : BookmarkAction() object BackPressed : BookmarkAction() - object ModeChanged : BookmarkAction() + object SwitchMode : BookmarkAction() } sealed class BookmarkChange : Change { 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 bd7370117..aa7700262 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 @@ -231,7 +231,7 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve refreshBookmarks(components) } } - is BookmarkAction.ModeChanged -> activity?.invalidateOptionsMenu() + is BookmarkAction.SwitchMode -> activity?.invalidateOptionsMenu() } } diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkUIView.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkUIView.kt index 357d27298..54d865dee 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkUIView.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkUIView.kt @@ -63,7 +63,7 @@ class BookmarkUIView( } if (it.mode != mode) { mode = it.mode - actionEmitter.onNext(BookmarkAction.ModeChanged) + actionEmitter.onNext(BookmarkAction.SwitchMode) } bookmarkAdapter.updateData(it.tree, it.mode) when (val modeCopy = mode) { @@ -78,7 +78,7 @@ class BookmarkUIView( mode = BookmarkState.Mode.Normal bookmarkAdapter.updateData(tree, mode) setUIForNormalMode(tree) - actionEmitter.onNext(BookmarkAction.ModeChanged) + actionEmitter.onNext(BookmarkAction.SwitchMode) true } canGoBack -> { @@ -113,7 +113,7 @@ class BookmarkUIView( context.getString(R.string.bookmarks_multi_select_title, mode.selectedItems.size) setToolbarColors( R.color.white_color, - R.attr.accentBright.getColorIntFromAttr(context!!) + R.attr.accentHighContrast.getColorIntFromAttr(context!!) ) } diff --git a/app/src/main/java/org/mozilla/fenix/library/history/HistoryAdapter.kt b/app/src/main/java/org/mozilla/fenix/library/history/HistoryAdapter.kt index f94209f97..79d6e80a5 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/HistoryAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/HistoryAdapter.kt @@ -98,10 +98,13 @@ class HistoryAdapter( private var historyList: HistoryList = HistoryList(emptyList()) private var mode: HistoryState.Mode = HistoryState.Mode.Normal private lateinit var job: Job + var selected = listOf() fun updateData(items: List, mode: HistoryState.Mode) { this.historyList = HistoryList(items) this.mode = mode + this.selected = if (mode is HistoryState.Mode.Editing) mode.selectedItems else listOf() + notifyDataSetChanged() } diff --git a/app/src/main/java/org/mozilla/fenix/library/history/HistoryComponent.kt b/app/src/main/java/org/mozilla/fenix/library/history/HistoryComponent.kt index 35ebef3a7..09be4fbb4 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/HistoryComponent.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/HistoryComponent.kt @@ -30,6 +30,7 @@ class HistoryComponent( bus.getManagedEmitter(HistoryAction::class.java), bus.getSafeManagedObservable(HistoryChange::class.java) ) { + override fun initView() = HistoryUIView(container, actionEmitter, changesObservable) override fun render(): Observable = @@ -51,11 +52,12 @@ data class HistoryState(val items: List, val mode: Mode) : ViewStat } sealed class HistoryAction : Action { - data class Select(val item: HistoryItem) : HistoryAction() + data class Open(val item: HistoryItem) : HistoryAction() data class EnterEditMode(val item: HistoryItem) : HistoryAction() object BackPressed : HistoryAction() data class AddItemForRemoval(val item: HistoryItem) : HistoryAction() data class RemoveItemForRemoval(val item: HistoryItem) : HistoryAction() + object SwitchMode : HistoryAction() sealed class Delete : HistoryAction() { object All : Delete() @@ -99,10 +101,13 @@ class HistoryViewModel(initialState: HistoryState, changesObservable: Observable } } is HistoryChange.RemoveItemForRemoval -> { - val mode = state.mode + var mode = state.mode + if (mode is HistoryState.Mode.Editing) { val items = mode.selectedItems.filter { it.id != change.item.id } - state.copy(mode = mode.copy(selectedItems = items)) + mode = if (items.isEmpty()) HistoryState.Mode.Normal else HistoryState.Mode.Editing(items) + + state.copy(mode = mode) } else { state } 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 a2f61cb00..4d9fb1a02 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 @@ -4,6 +4,8 @@ package org.mozilla.fenix.library.history +import android.graphics.PorterDuff +import android.graphics.PorterDuffColorFilter import android.os.Bundle import android.text.TextUtils import android.view.LayoutInflater @@ -13,23 +15,30 @@ import android.view.MenuItem 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.navigation.Navigation import kotlinx.android.synthetic.main.fragment_history.view.* import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.launch import kotlinx.coroutines.coroutineScope import mozilla.components.concept.storage.VisitType import mozilla.components.support.base.feature.BackHandler import org.mozilla.fenix.BrowserDirection +import org.mozilla.fenix.BrowsingModeManager import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R +import org.mozilla.fenix.components.Components +import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.requireComponents +import org.mozilla.fenix.ext.share import org.mozilla.fenix.mvi.ActionBusFactory import org.mozilla.fenix.mvi.getAutoDisposeObservable import org.mozilla.fenix.mvi.getManagedEmitter +import org.mozilla.fenix.utils.ItsNotBrokenSnack import java.net.MalformedURLException import java.net.URL import kotlin.coroutines.CoroutineContext @@ -39,6 +48,7 @@ class HistoryFragment : Fragment(), CoroutineScope, BackHandler { private lateinit var job: Job private lateinit var historyComponent: HistoryComponent + private val navigation by lazy { Navigation.findNavController(requireView()) } override val coroutineContext: CoroutineContext get() = Dispatchers.Main + job @@ -66,7 +76,7 @@ class HistoryFragment : Fragment(), CoroutineScope, BackHandler { (activity as AppCompatActivity).supportActionBar?.show() } - private fun selectItem(item: HistoryItem) { + private fun openItem(item: HistoryItem) { (activity as HomeActivity).openToBrowserAndLoad( searchTermOrURL = item.url, newTab = false, @@ -79,7 +89,19 @@ class HistoryFragment : Fragment(), CoroutineScope, BackHandler { } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - inflater.inflate(R.menu.library_menu, menu) + when (val mode = (historyComponent.uiView as HistoryUIView).mode) { + HistoryState.Mode.Normal -> inflater.inflate(R.menu.library_menu, menu) + is HistoryState.Mode.Editing -> { + inflater.inflate(R.menu.history_select_multi, menu) + menu.findItem(R.id.share_history_multi_select)?.run { + isVisible = mode.selectedItems.isNotEmpty() + icon.colorFilter = PorterDuffColorFilter( + ContextCompat.getColor(context!!, R.color.white_color), + PorterDuff.Mode.SRC_IN + ) + } + } + } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -96,7 +118,7 @@ class HistoryFragment : Fragment(), CoroutineScope, BackHandler { getAutoDisposeObservable() .subscribe { when (it) { - is HistoryAction.Select -> selectItem(it.item) + is HistoryAction.Open -> openItem(it.item) is HistoryAction.EnterEditMode -> getManagedEmitter() .onNext(HistoryChange.EnterEditMode(it.item)) is HistoryAction.AddItemForRemoval -> getManagedEmitter() @@ -119,17 +141,59 @@ class HistoryFragment : Fragment(), CoroutineScope, BackHandler { } reloadData() } + is HistoryAction.SwitchMode -> activity?.invalidateOptionsMenu() } } } + @Suppress("ComplexMethod") override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { + R.id.share_history_multi_select -> { + val selectedHistory = (historyComponent.uiView as HistoryUIView).getSelected() + when { + selectedHistory.size == 1 -> context?.share(selectedHistory.first().url) + selectedHistory.size > 1 -> ItsNotBrokenSnack(context!!).showSnackbar(issueNumber = "2377") + } + true + } R.id.libraryClose -> { Navigation.findNavController(requireActivity(), R.id.container) .popBackStack(R.id.libraryFragment, true) true } + R.id.delete_history_multi_select -> { + val components = context?.applicationContext?.components!! + val selectedHistory = (historyComponent.uiView as HistoryUIView).getSelected() + + CoroutineScope(Main).launch { + deleteSelectedHistory(selectedHistory, components) + reloadData() + } + true + } + R.id.open_history_in_new_tabs_multi_select -> { + val selectedHistory = (historyComponent.uiView as HistoryUIView).getSelected() + selectedHistory.forEach { + requireComponents.useCases.tabsUseCases.addTab.invoke(it.url) + } + + (activity as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Normal + (activity as HomeActivity).supportActionBar?.hide() + navigation.navigate(HistoryFragmentDirections.actionHistoryFragmentToHomeFragment()) + true + } + R.id.open_history_in_private_tabs_multi_select -> { + val selectedHistory = (historyComponent.uiView as HistoryUIView).getSelected() + selectedHistory.forEach { + requireComponents.useCases.tabsUseCases.addPrivateTab.invoke(it.url) + } + + (activity as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Private + (activity as HomeActivity).supportActionBar?.hide() + navigation.navigate(HistoryFragmentDirections.actionHistoryFragmentToHomeFragment()) + true + } else -> super.onOptionsItemSelected(item) } } @@ -171,4 +235,13 @@ class HistoryFragment : Fragment(), CoroutineScope, BackHandler { } } } + + private suspend fun deleteSelectedHistory( + selected: List, + components: Components = requireComponents + ) { + selected.forEach { + components.core.historyStorage.deleteVisit(it.url, it.visitedAt) + } + } } diff --git a/app/src/main/java/org/mozilla/fenix/library/history/HistoryUIView.kt b/app/src/main/java/org/mozilla/fenix/library/history/HistoryUIView.kt index 67a81e64e..19e2d3aa3 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/HistoryUIView.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/HistoryUIView.kt @@ -4,9 +4,15 @@ package org.mozilla.fenix.library.history +import android.graphics.PorterDuff +import android.graphics.PorterDuffColorFilter import android.view.LayoutInflater import android.view.ViewGroup +import androidx.appcompat.widget.Toolbar +import android.widget.ImageButton import android.widget.LinearLayout +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat import androidx.recyclerview.widget.LinearLayoutManager import io.reactivex.Observable import io.reactivex.Observer @@ -14,6 +20,8 @@ import io.reactivex.functions.Consumer import kotlinx.android.synthetic.main.component_history.view.* import mozilla.components.support.base.feature.BackHandler import org.mozilla.fenix.R +import org.mozilla.fenix.ext.asActivity +import org.mozilla.fenix.ext.getColorIntFromAttr import org.mozilla.fenix.mvi.UIView class HistoryUIView( @@ -27,28 +35,103 @@ class HistoryUIView( var mode: HistoryState.Mode = HistoryState.Mode.Normal private set + private val historyAdapter: HistoryAdapter + private var items: List = listOf() + private val context = container.context + private val activity = context?.asActivity() + + fun getSelected(): List = historyAdapter.selected + override val view: LinearLayout = LayoutInflater.from(container.context) .inflate(R.layout.component_history, container, true) .findViewById(R.id.history_wrapper) init { view.history_list.apply { - adapter = HistoryAdapter(actionEmitter) + historyAdapter = HistoryAdapter(actionEmitter) + adapter = historyAdapter layoutManager = LinearLayoutManager(container.context) } } override fun updateView() = Consumer { - mode = it.mode + if (it.mode != mode) { + mode = it.mode + actionEmitter.onNext(HistoryAction.SwitchMode) + } (view.history_list.adapter as HistoryAdapter).updateData(it.items, it.mode) + + items = it.items + when (val modeCopy = mode) { + is HistoryState.Mode.Normal -> setUIForNormalMode() + is HistoryState.Mode.Editing -> setUIForSelectingMode(modeCopy) + } } - override fun onBackPressed(): Boolean { - if (mode is HistoryState.Mode.Editing) { - actionEmitter.onNext(HistoryAction.BackPressed) - return true + private fun setUIForSelectingMode( + mode: HistoryState.Mode.Editing + ) { + (activity as? AppCompatActivity)?.title = + context.getString(R.string.history_multi_select_title, mode.selectedItems.size) + setToolbarColors( + R.color.white_color, + R.attr.accentHighContrast.getColorIntFromAttr(context!!) + ) + } + + private fun setUIForNormalMode() { + (activity as? AppCompatActivity)?.title = context.getString(R.string.library_history) + setToolbarColors( + R.attr.primaryText.getColorIntFromAttr(context!!), + R.attr.foundation.getColorIntFromAttr(context) + ) + } + + 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: androidx.appcompat.widget.Toolbar, + textColor: Int, + backgroundColor: Int, + colorFilter: PorterDuffColorFilter? = null + ) { + toolbar.setTitleTextColor(ContextCompat.getColor(context!!, textColor)) + toolbar.setBackgroundColor(ContextCompat.getColor(context, backgroundColor)) + + if (colorFilter == null) { + return } - return false + 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 when { + mode is HistoryState.Mode.Editing -> { + mode = HistoryState.Mode.Normal + historyAdapter.updateData(items, mode) + setUIForNormalMode() + actionEmitter.onNext(HistoryAction.SwitchMode) + true + } + else -> false + } } } diff --git a/app/src/main/java/org/mozilla/fenix/library/history/viewholders/HistoryDeleteButtonViewHolder.kt b/app/src/main/java/org/mozilla/fenix/library/history/viewholders/HistoryDeleteButtonViewHolder.kt index 96d6924fb..a67bd8891 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/viewholders/HistoryDeleteButtonViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/viewholders/HistoryDeleteButtonViewHolder.kt @@ -35,20 +35,19 @@ class HistoryDeleteButtonViewHolder( fun bind(mode: HistoryState.Mode) { this.mode = mode - val text = if (mode is HistoryState.Mode.Editing && mode.selectedItems.isNotEmpty()) { - textView.context.resources.getString( - R.string.history_delete_some, - mode.selectedItems.size - ) - } else { - textView.context.resources.getString(R.string.history_delete_all) + buttonView.run { + if (mode is HistoryState.Mode.Editing && mode.selectedItems.isNotEmpty()) { + isEnabled = false + alpha = DISABLED_ALPHA + } else { + isEnabled = true + alpha = 1f + } } - - buttonView.contentDescription = text - textView.text = text } companion object { + const val DISABLED_ALPHA = 0.4f const val LAYOUT_ID = R.layout.delete_history_button } } diff --git a/app/src/main/java/org/mozilla/fenix/library/history/viewholders/HistoryListItemViewHolder.kt b/app/src/main/java/org/mozilla/fenix/library/history/viewholders/HistoryListItemViewHolder.kt index 7ae804062..63006c1a8 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/viewholders/HistoryListItemViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/viewholders/HistoryListItemViewHolder.kt @@ -6,6 +6,7 @@ package org.mozilla.fenix.library.history.viewholders import android.view.View import android.widget.CompoundButton +import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import io.reactivex.Observer import kotlinx.android.synthetic.main.history_list_item.view.* @@ -15,6 +16,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch import mozilla.components.browser.icons.IconRequest import mozilla.components.browser.menu.BrowserMenu +import org.mozilla.fenix.DefaultThemeManager import org.mozilla.fenix.R import org.mozilla.fenix.ext.components import org.mozilla.fenix.library.history.HistoryAction @@ -32,7 +34,6 @@ class HistoryListItemViewHolder( override val coroutineContext: CoroutineContext get() = Dispatchers.IO + job - private val checkbox = view.should_remove_checkbox private val favicon = view.history_favicon private val title = view.history_title private val url = view.history_url @@ -60,17 +61,6 @@ class HistoryListItemViewHolder( init { setupMenu() - view.setOnClickListener { - if (mode is HistoryState.Mode.Editing) { - checkbox.isChecked = !checkbox.isChecked - return@setOnClickListener - } - - item?.apply { - actionEmitter.onNext(HistoryAction.Select(this)) - } - } - view.setOnLongClickListener { item?.apply { actionEmitter.onNext(HistoryAction.EnterEditMode(this)) @@ -84,8 +74,6 @@ class HistoryListItemViewHolder( anchor = it, orientation = BrowserMenu.Orientation.DOWN) } - - checkbox.setOnCheckedChangeListener(checkListener) } fun bind(item: HistoryItem, mode: HistoryState.Mode) { @@ -95,23 +83,31 @@ class HistoryListItemViewHolder( title.text = item.title url.text = item.url - val isEditing = mode is HistoryState.Mode.Editing - checkbox.visibility = if (isEditing) View.VISIBLE else View.GONE - favicon.visibility = if (isEditing) View.INVISIBLE else View.VISIBLE + val selected = when (mode) { + is HistoryState.Mode.Editing -> mode.selectedItems.contains(item) + HistoryState.Mode.Normal -> false + } + + setClickListeners(item, selected) if (mode is HistoryState.Mode.Editing) { - checkbox.setOnCheckedChangeListener(null) + val backgroundTint = + if (selected) { + DefaultThemeManager.resolveAttribute(R.attr.accentHighContrast, itemView.context) + } else { + DefaultThemeManager.resolveAttribute(R.attr.neutral, itemView.context) + } + val backgroundTintList = ContextCompat.getColorStateList(itemView.context, backgroundTint) + favicon.backgroundTintList = backgroundTintList - // Don't set the checkbox if it already contains the right value. - // This prevent us from cutting off the animation - val shouldCheck = mode.selectedItems.contains(item) - if (checkbox.isChecked != shouldCheck) { - checkbox.isChecked = shouldCheck + if (selected) { + favicon.setImageResource(R.drawable.mozac_ic_check) + } else { + favicon.setImageResource(0) } - checkbox.setOnCheckedChangeListener(checkListener) + } else { + updateFavIcon(item.url) } - - updateFavIcon(item.url) } private fun setupMenu() { @@ -134,6 +130,21 @@ class HistoryListItemViewHolder( } } + private fun setClickListeners( + item: HistoryItem, + selected: Boolean + ) { + itemView.history_layout.setOnClickListener { + if (mode == HistoryState.Mode.Normal) { + actionEmitter.onNext(HistoryAction.Open(item)) + } else { + if (selected) actionEmitter.onNext(HistoryAction.RemoveItemForRemoval(item)) else actionEmitter.onNext( + HistoryAction.AddItemForRemoval(item) + ) + } + } + } + companion object { const val LAYOUT_ID = R.layout.history_list_item } diff --git a/app/src/main/res/drawable/button_background.xml b/app/src/main/res/drawable/button_background.xml index 41c37d094..2128b740d 100644 --- a/app/src/main/res/drawable/button_background.xml +++ b/app/src/main/res/drawable/button_background.xml @@ -5,5 +5,5 @@ - + \ No newline at end of file diff --git a/app/src/main/res/layout/delete_history_button.xml b/app/src/main/res/layout/delete_history_button.xml index 12882cb6f..735f27ca8 100644 --- a/app/src/main/res/layout/delete_history_button.xml +++ b/app/src/main/res/layout/delete_history_button.xml @@ -16,14 +16,18 @@ + android:drawableTint="?primaryText" + android:drawableStart="@drawable/ic_delete" + android:drawablePadding="12dp"/> + \ No newline at end of file diff --git a/app/src/main/res/layout/history_list_item.xml b/app/src/main/res/layout/history_list_item.xml index 3fb4aaf86..c8465b2e6 100644 --- a/app/src/main/res/layout/history_list_item.xml +++ b/app/src/main/res/layout/history_list_item.xml @@ -4,6 +4,7 @@ - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - - + + + + + + + diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 43679399c..21bfedf90 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -137,6 +137,7 @@ android:label="@string/library_history" tools:layout="@layout/fragment_history" > + Disable private browsing Search or enter address + + No tabs opened + + Your open tabs will be shown here. @@ -77,11 +81,9 @@ Fill link from clipboard - + Settings - - Basics @@ -281,16 +283,15 @@ The first parameter is a digit that shows the cardinal number of how many additional tabs the session has. --> %1$d sites… - - No tabs opened - - Your open tabs will be shown here. Delete history Delete + + %1$d selected Delete %1$d items @@ -302,13 +303,10 @@ This month Older - - Entering full screen mode Sorry. %1$s can’t load that page. - You can attempt to restore or close this tab below. @@ -324,6 +322,7 @@ Share session + Bookmark menu @@ -338,7 +337,6 @@ Bookmark saved! EDIT - Edit @@ -384,9 +382,6 @@ UNDO - - URL copied - Go to Settings @@ -434,58 +429,48 @@ No collections Your collections will be shown here. - Select Tabs - Select collection - Name collection - Add new collection - Select All Select tabs to save - %d tabs selected - %d tab selected - Tabs saved! - Tab saved! - Close - Save Collection %d + Collection deleted - Tab deleted - UNDO - Allow %1$s to open %2$s - + + Entering full screen mode + + URL copied diff --git a/app/src/test/java/org/mozilla/fenix/library/history/HistoryComponentTest.kt b/app/src/test/java/org/mozilla/fenix/library/history/HistoryComponentTest.kt index c1e1398ca..f82647583 100644 --- a/app/src/test/java/org/mozilla/fenix/library/history/HistoryComponentTest.kt +++ b/app/src/test/java/org/mozilla/fenix/library/history/HistoryComponentTest.kt @@ -39,22 +39,40 @@ class HistoryComponentTest { } @Test - fun `add and remove one history item normally`() { - val historyItem = HistoryItem(123, "Mozilla", "http://mozilla.org", 0) + fun `select two items for removal, then deselect one, then select it again`() { + val historyItem = HistoryItem(1, "Mozilla", "http://mozilla.org", 0) + val historyItem2 = HistoryItem(2, "Mozilla", "http://mozilla.org", 0) - emitter.onNext(HistoryChange.Change(listOf(historyItem))) + emitter.onNext(HistoryChange.Change(listOf(historyItem, historyItem2))) emitter.onNext(HistoryChange.EnterEditMode(historyItem)) + emitter.onNext(HistoryChange.AddItemForRemoval(historyItem2)) emitter.onNext(HistoryChange.RemoveItemForRemoval(historyItem)) emitter.onNext(HistoryChange.AddItemForRemoval(historyItem)) emitter.onNext(HistoryChange.ExitEditMode) + historyObserver.assertSubscribed().awaitCount(7).assertNoErrors() + .assertValues( + HistoryState(listOf(), HistoryState.Mode.Normal), + HistoryState(listOf(historyItem, historyItem2), HistoryState.Mode.Normal), + HistoryState(listOf(historyItem, historyItem2), HistoryState.Mode.Editing(listOf(historyItem))), + HistoryState(listOf(historyItem, historyItem2), HistoryState.Mode.Editing(listOf(historyItem, historyItem2))), + HistoryState(listOf(historyItem, historyItem2), HistoryState.Mode.Editing(listOf(historyItem2))), + HistoryState(listOf(historyItem, historyItem2), HistoryState.Mode.Editing(listOf(historyItem2, historyItem))), + HistoryState(listOf(historyItem, historyItem2), HistoryState.Mode.Normal) + ) + } + @Test + fun `deselecting all items triggers normal mode`() { + val historyItem = HistoryItem(123, "Mozilla", "http://mozilla.org", 0) + + emitter.onNext(HistoryChange.Change(listOf(historyItem))) + emitter.onNext(HistoryChange.EnterEditMode(historyItem)) + emitter.onNext(HistoryChange.RemoveItemForRemoval(historyItem)) historyObserver.assertSubscribed().awaitCount(6).assertNoErrors() .assertValues( HistoryState(listOf(), HistoryState.Mode.Normal), HistoryState(listOf(historyItem), HistoryState.Mode.Normal), HistoryState(listOf(historyItem), HistoryState.Mode.Editing(listOf(historyItem))), - HistoryState(listOf(historyItem), HistoryState.Mode.Editing(listOf())), - HistoryState(listOf(historyItem), HistoryState.Mode.Editing(listOf(historyItem))), HistoryState(listOf(historyItem), HistoryState.Mode.Normal) ) }