For #17044: Explicitly set a new default engine when default is deleted.

upstream-sync
mcarare 3 years ago committed by Mihai Adrian Carare
parent 20f2135578
commit 633bf384e2

@ -14,6 +14,7 @@ import android.view.ViewGroup
import android.widget.CompoundButton
import android.widget.LinearLayout
import android.widget.RadioGroup
import androidx.annotation.VisibleForTesting
import androidx.core.view.isVisible
import androidx.navigation.Navigation
import androidx.preference.Preference
@ -62,12 +63,13 @@ class RadioSearchEngineListPreference @JvmOverloads constructor(
}
@OptIn(ExperimentalCoroutinesApi::class)
private fun subscribeToSearchEngineUpdates(store: BrowserStore, view: View) = view.toScope().launch {
store.flow()
.map { state -> state.search }
.ifChanged()
.collect { state -> refreshSearchEngineViews(view, state) }
}
private fun subscribeToSearchEngineUpdates(store: BrowserStore, view: View) =
view.toScope().launch {
store.flow()
.map { state -> state.search }
.ifChanged()
.collect { state -> refreshSearchEngineViews(view, state) }
}
private fun refreshSearchEngineViews(view: View, state: SearchState) {
val searchEngineGroup = view.findViewById<RadioGroup>(R.id.search_engine_group)
@ -118,7 +120,8 @@ class RadioSearchEngineListPreference @JvmOverloads constructor(
is SearchEngineMenu.Item.Edit -> editCustomSearchEngine(wrapper, engine)
is SearchEngineMenu.Item.Delete -> deleteSearchEngine(
context,
engine
engine,
engine == context.components.core.store.state.search.selectedOrDefaultSearchEngine
)
}
}
@ -149,21 +152,50 @@ class RadioSearchEngineListPreference @JvmOverloads constructor(
Navigation.findNavController(view).navigate(directions)
}
private fun deleteSearchEngine(
@VisibleForTesting
internal fun deleteSearchEngine(
context: Context,
engine: SearchEngine
engine: SearchEngine,
isDefaultSearchEngine: Boolean
) {
context.components.useCases.searchUseCases.removeSearchEngine(engine)
if (isDefaultSearchEngine) {
context.components.useCases.searchUseCases.selectSearchEngine(
context.components.core.store.state.search.searchEngines.first {
it.id != engine.id
}
)
}
showUndoSnackbar(context, engine, isDefaultSearchEngine)
}
@VisibleForTesting
internal fun showUndoSnackbar(
context: Context,
engine: SearchEngine,
isDefaultSearchEngine: Boolean
) {
MainScope().allowUndo(
view = context.getRootView()!!,
message = context
.getString(R.string.search_delete_search_engine_success_message, engine.name),
undoActionTitle = context.getString(R.string.snackbar_deleted_undo),
onCancel = {
context.components.useCases.searchUseCases.addSearchEngine(engine)
restoreSearchEngine(engine, isDefaultSearchEngine)
},
operation = {}
)
}
@VisibleForTesting
internal fun restoreSearchEngine(
engine: SearchEngine,
isDefaultSearchEngine: Boolean
) {
context.components.useCases.searchUseCases.addSearchEngine(engine)
if (isDefaultSearchEngine) {
context.components.useCases.searchUseCases.selectSearchEngine(engine)
}
}
}

@ -0,0 +1,96 @@
/* 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.settings.search
import android.content.Context
import io.mockk.Runs
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.spyk
import io.mockk.verify
import mozilla.components.browser.state.search.SearchEngine
import mozilla.components.browser.state.state.SearchState
import mozilla.components.feature.search.SearchUseCases
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@RunWith(FenixRobolectricTestRunner::class)
class RadioSearchEngineListPreferenceTest {
private lateinit var radioSearchEngineListPreference: RadioSearchEngineListPreference
private lateinit var searchUseCases: SearchUseCases
private lateinit var searchState: SearchState
private lateinit var testContext: Context
private lateinit var defaultSearchEngine: SearchEngine
private lateinit var otherSearchEngine: SearchEngine
@Before
fun before() {
testContext = mockk(relaxed = true)
searchUseCases = mockk(relaxed = true)
defaultSearchEngine = mockk {
every { id } returns "default"
}
otherSearchEngine = mockk {
every { id } returns "other"
}
val engineList = listOf(defaultSearchEngine, otherSearchEngine)
searchState = SearchState(customSearchEngines = engineList)
every { testContext.components.useCases.searchUseCases } returns searchUseCases
every { testContext.components.core.store.state.search } returns searchState
radioSearchEngineListPreference = spyk(RadioSearchEngineListPreference(testContext))
}
@Test
fun `when deleting default search engine a new one is selected`() {
every { radioSearchEngineListPreference.showUndoSnackbar(any(), any(), any()) } just Runs
radioSearchEngineListPreference.deleteSearchEngine(
testContext,
defaultSearchEngine,
true
)
verify { searchUseCases.removeSearchEngine(defaultSearchEngine) }
verify { searchUseCases.selectSearchEngine(otherSearchEngine) }
verify {
radioSearchEngineListPreference.showUndoSnackbar(
testContext,
defaultSearchEngine,
true
)
}
}
@Test
fun `restoreSearchEngine ads engine and makes it default if it was the default before deletion`() {
radioSearchEngineListPreference.restoreSearchEngine(
defaultSearchEngine,
true
)
verify { searchUseCases.addSearchEngine(defaultSearchEngine) }
verify { searchUseCases.selectSearchEngine(defaultSearchEngine) }
}
@Test
fun `restoreSearchEngine ads engine and it doe NOT make it default if it was NOT the default before deletion`() {
radioSearchEngineListPreference.restoreSearchEngine(
otherSearchEngine,
false
)
verify { searchUseCases.addSearchEngine(otherSearchEngine) }
verify(exactly = 0) { searchUseCases.selectSearchEngine(defaultSearchEngine) }
}
}
Loading…
Cancel
Save