mirror of
https://github.com/fork-maintainers/iceraven-browser
synced 2024-11-11 13:11:01 +00:00
parent
9ee8c00928
commit
ac6c1ec2ee
@ -5,8 +5,6 @@
|
|||||||
package org.mozilla.fenix.collections
|
package org.mozilla.fenix.collections
|
||||||
|
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.Tab
|
import org.mozilla.fenix.home.sessioncontrol.Tab
|
||||||
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
||||||
import org.mozilla.fenix.mvi.Action
|
import org.mozilla.fenix.mvi.Action
|
||||||
@ -18,19 +16,19 @@ import org.mozilla.fenix.mvi.UIComponentViewModelBase
|
|||||||
import org.mozilla.fenix.mvi.UIComponentViewModelProvider
|
import org.mozilla.fenix.mvi.UIComponentViewModelProvider
|
||||||
import org.mozilla.fenix.mvi.ViewState
|
import org.mozilla.fenix.mvi.ViewState
|
||||||
|
|
||||||
sealed class SaveCollectionStep {
|
enum class SaveCollectionStep {
|
||||||
object SelectTabs : SaveCollectionStep()
|
SelectTabs,
|
||||||
object SelectCollection : SaveCollectionStep()
|
SelectCollection,
|
||||||
object NameCollection : SaveCollectionStep()
|
NameCollection,
|
||||||
object RenameCollection : SaveCollectionStep()
|
RenameCollection
|
||||||
}
|
}
|
||||||
|
|
||||||
data class CollectionCreationState(
|
data class CollectionCreationState(
|
||||||
val tabs: List<Tab> = listOf(),
|
val tabs: List<Tab> = emptyList(),
|
||||||
val selectedTabs: Set<Tab> = setOf(),
|
val selectedTabs: Set<Tab> = emptySet(),
|
||||||
val saveCollectionStep: SaveCollectionStep = SaveCollectionStep.SelectTabs,
|
val saveCollectionStep: SaveCollectionStep = SaveCollectionStep.SelectTabs,
|
||||||
val tabCollections: List<TabCollection> = listOf(),
|
val tabCollections: List<TabCollection> = emptyList(),
|
||||||
val selectedTabCollection: TabCollection?
|
val selectedTabCollection: TabCollection? = null
|
||||||
) : ViewState
|
) : ViewState
|
||||||
|
|
||||||
sealed class CollectionCreationChange : Change {
|
sealed class CollectionCreationChange : Change {
|
||||||
@ -84,36 +82,17 @@ class CollectionCreationViewModel(
|
|||||||
reducer
|
reducer
|
||||||
) {
|
) {
|
||||||
|
|
||||||
class Factory(
|
|
||||||
private val initialState: CollectionCreationState
|
|
||||||
) : ViewModelProvider.Factory {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T =
|
|
||||||
CollectionCreationViewModel(initialState) as T
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val reducer: Reducer<CollectionCreationState, CollectionCreationChange> =
|
val reducer: Reducer<CollectionCreationState, CollectionCreationChange> = { state, change ->
|
||||||
{ state, change ->
|
when (change) {
|
||||||
when (change) {
|
is CollectionCreationChange.AddAllTabs -> state.copy(selectedTabs = state.tabs.toSet())
|
||||||
is CollectionCreationChange.AddAllTabs -> state.copy(selectedTabs = state.tabs.toSet())
|
is CollectionCreationChange.RemoveAllTabs -> state.copy(selectedTabs = emptySet())
|
||||||
is CollectionCreationChange.RemoveAllTabs -> state.copy(selectedTabs = setOf())
|
is CollectionCreationChange.TabListChange -> state.copy(tabs = change.tabs)
|
||||||
is CollectionCreationChange.TabListChange -> state.copy(tabs = change.tabs)
|
is CollectionCreationChange.TabAdded -> state.copy(selectedTabs = state.selectedTabs + change.tab)
|
||||||
is CollectionCreationChange.TabAdded -> {
|
is CollectionCreationChange.TabRemoved -> state.copy(selectedTabs = state.selectedTabs - change.tab)
|
||||||
val selectedTabs = state.selectedTabs + setOf(change.tab)
|
is CollectionCreationChange.StepChanged -> state.copy(saveCollectionStep = change.saveCollectionStep)
|
||||||
state.copy(selectedTabs = selectedTabs)
|
is CollectionCreationChange.CollectionSelected -> state.copy(selectedTabCollection = change.collection)
|
||||||
}
|
|
||||||
is CollectionCreationChange.TabRemoved -> {
|
|
||||||
val selectedTabs = state.selectedTabs - setOf(change.tab)
|
|
||||||
state.copy(selectedTabs = selectedTabs)
|
|
||||||
}
|
|
||||||
is CollectionCreationChange.StepChanged -> {
|
|
||||||
state.copy(saveCollectionStep = change.saveCollectionStep)
|
|
||||||
}
|
|
||||||
is CollectionCreationChange.CollectionSelected -> {
|
|
||||||
state.copy(selectedTabCollection = change.collection)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ package org.mozilla.fenix.collections
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.isGone
|
||||||
|
import androidx.core.view.isInvisible
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import io.reactivex.Observer
|
import io.reactivex.Observer
|
||||||
@ -42,8 +44,7 @@ class CollectionCreationTabListAdapter(
|
|||||||
} else if (checkChanged.shouldBeUnchecked) {
|
} else if (checkChanged.shouldBeUnchecked) {
|
||||||
holder.itemView.tab_selected_checkbox.isChecked = false
|
holder.itemView.tab_selected_checkbox.isChecked = false
|
||||||
}
|
}
|
||||||
holder.itemView.tab_selected_checkbox.visibility =
|
holder.itemView.tab_selected_checkbox.isGone = checkChanged.shouldHideCheckBox
|
||||||
if (checkChanged.shouldHideCheckBox) View.GONE else View.VISIBLE
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,7 +121,6 @@ data class CheckChanged(val shouldBeChecked: Boolean, val shouldBeUnchecked: Boo
|
|||||||
|
|
||||||
class TabViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
class TabViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
|
||||||
private var tab: Tab? = null
|
|
||||||
private val checkbox = view.tab_selected_checkbox!!
|
private val checkbox = view.tab_selected_checkbox!!
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -130,10 +130,9 @@ class TabViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun bind(tab: Tab, isSelected: Boolean, shouldHideCheckBox: Boolean) {
|
fun bind(tab: Tab, isSelected: Boolean, shouldHideCheckBox: Boolean) {
|
||||||
this.tab = tab
|
|
||||||
itemView.hostname.text = tab.hostname
|
itemView.hostname.text = tab.hostname
|
||||||
itemView.tab_title.text = tab.title
|
itemView.tab_title.text = tab.title
|
||||||
checkbox.visibility = if (shouldHideCheckBox) View.INVISIBLE else View.VISIBLE
|
checkbox.isInvisible = shouldHideCheckBox
|
||||||
itemView.isClickable = !shouldHideCheckBox
|
itemView.isClickable = !shouldHideCheckBox
|
||||||
if (checkbox.isChecked != isSelected) {
|
if (checkbox.isChecked != isSelected) {
|
||||||
checkbox.isChecked = isSelected
|
checkbox.isChecked = isSelected
|
||||||
|
@ -76,22 +76,17 @@ class CollectionCreationUIView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
view.name_collection_edittext.filters += InputFilter.LengthFilter(COLLECTION_NAME_MAX_LENGTH)
|
view.name_collection_edittext.filters += InputFilter.LengthFilter(COLLECTION_NAME_MAX_LENGTH)
|
||||||
view.name_collection_edittext.setOnEditorActionListener { v, actionId, _ ->
|
view.name_collection_edittext.setOnEditorActionListener { view, actionId, _ ->
|
||||||
if (actionId == EditorInfo.IME_ACTION_DONE && v.text.toString().isNotBlank()) {
|
val text = view.text.toString()
|
||||||
|
if (actionId == EditorInfo.IME_ACTION_DONE && text.isNotBlank()) {
|
||||||
when (step) {
|
when (step) {
|
||||||
is SaveCollectionStep.NameCollection -> {
|
SaveCollectionStep.NameCollection ->
|
||||||
actionEmitter.onNext(
|
CollectionCreationAction.SaveCollectionName(selectedTabs.toList(), text)
|
||||||
CollectionCreationAction.SaveCollectionName(
|
SaveCollectionStep.RenameCollection ->
|
||||||
selectedTabs.toList(),
|
selectedCollection?.let { CollectionCreationAction.RenameCollection(it, text) }
|
||||||
v.text.toString()
|
else -> null
|
||||||
)
|
}?.let { action ->
|
||||||
)
|
actionEmitter.onNext(action)
|
||||||
}
|
|
||||||
is SaveCollectionStep.RenameCollection -> {
|
|
||||||
selectedCollection?.let {
|
|
||||||
actionEmitter.onNext(CollectionCreationAction.RenameCollection(it, v.text.toString()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
@ -116,7 +111,7 @@ class CollectionCreationUIView(
|
|||||||
selectedCollection = it.selectedTabCollection
|
selectedCollection = it.selectedTabCollection
|
||||||
|
|
||||||
when (it.saveCollectionStep) {
|
when (it.saveCollectionStep) {
|
||||||
is SaveCollectionStep.SelectTabs -> {
|
SaveCollectionStep.SelectTabs -> {
|
||||||
view.context.components.analytics.metrics.track(Event.CollectionTabSelectOpened)
|
view.context.components.analytics.metrics.track(Event.CollectionTabSelectOpened)
|
||||||
|
|
||||||
view.tab_list.isClickable = true
|
view.tab_list.isClickable = true
|
||||||
@ -194,7 +189,7 @@ class CollectionCreationUIView(
|
|||||||
View.VISIBLE
|
View.VISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is SaveCollectionStep.SelectCollection -> {
|
SaveCollectionStep.SelectCollection -> {
|
||||||
view.tab_list.isClickable = false
|
view.tab_list.isClickable = false
|
||||||
|
|
||||||
save_button.visibility = View.GONE
|
save_button.visibility = View.GONE
|
||||||
@ -224,7 +219,7 @@ class CollectionCreationUIView(
|
|||||||
back_button.text =
|
back_button.text =
|
||||||
view.context.getString(R.string.create_collection_select_collection)
|
view.context.getString(R.string.create_collection_select_collection)
|
||||||
}
|
}
|
||||||
is SaveCollectionStep.NameCollection -> {
|
SaveCollectionStep.NameCollection -> {
|
||||||
view.tab_list.isClickable = false
|
view.tab_list.isClickable = false
|
||||||
|
|
||||||
collectionCreationTabListAdapter.updateData(it.selectedTabs.toList(), it.selectedTabs, true)
|
collectionCreationTabListAdapter.updateData(it.selectedTabs.toList(), it.selectedTabs, true)
|
||||||
@ -264,7 +259,7 @@ class CollectionCreationUIView(
|
|||||||
back_button.text =
|
back_button.text =
|
||||||
view.context.getString(R.string.create_collection_name_collection)
|
view.context.getString(R.string.create_collection_name_collection)
|
||||||
}
|
}
|
||||||
is SaveCollectionStep.RenameCollection -> {
|
SaveCollectionStep.RenameCollection -> {
|
||||||
view.tab_list.isClickable = false
|
view.tab_list.isClickable = false
|
||||||
|
|
||||||
it.selectedTabCollection?.let { tabCollection ->
|
it.selectedTabCollection?.let { tabCollection ->
|
||||||
@ -322,24 +317,11 @@ class CollectionCreationUIView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onKey(keyCode: Int, event: KeyEvent?): Boolean {
|
fun onKey(keyCode: Int, event: KeyEvent?): Boolean {
|
||||||
if (event?.action == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
return if (event?.action == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
when (step) {
|
actionEmitter.onNext(CollectionCreationAction.BackPressed(step))
|
||||||
SaveCollectionStep.SelectTabs -> {
|
true
|
||||||
actionEmitter.onNext(CollectionCreationAction.BackPressed(SaveCollectionStep.SelectTabs))
|
|
||||||
}
|
|
||||||
SaveCollectionStep.SelectCollection -> {
|
|
||||||
actionEmitter.onNext(CollectionCreationAction.BackPressed(SaveCollectionStep.SelectCollection))
|
|
||||||
}
|
|
||||||
SaveCollectionStep.NameCollection -> {
|
|
||||||
actionEmitter.onNext(CollectionCreationAction.BackPressed(SaveCollectionStep.NameCollection))
|
|
||||||
}
|
|
||||||
SaveCollectionStep.RenameCollection -> {
|
|
||||||
actionEmitter.onNext(CollectionCreationAction.BackPressed(SaveCollectionStep.RenameCollection))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
} else {
|
} else {
|
||||||
return false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,15 +50,7 @@ class CreateCollectionFragment : DialogFragment() {
|
|||||||
this,
|
this,
|
||||||
CollectionCreationViewModel::class.java
|
CollectionCreationViewModel::class.java
|
||||||
) {
|
) {
|
||||||
CollectionCreationViewModel(
|
CollectionCreationViewModel(viewModel.state)
|
||||||
CollectionCreationState(
|
|
||||||
viewModel.tabs,
|
|
||||||
viewModel.selectedTabs,
|
|
||||||
viewModel.saveCollectionStep,
|
|
||||||
viewModel.tabCollections,
|
|
||||||
viewModel.selectedTabCollection
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return view
|
return view
|
||||||
@ -87,7 +79,11 @@ class CreateCollectionFragment : DialogFragment() {
|
|||||||
getManagedEmitter<CollectionCreationChange>()
|
getManagedEmitter<CollectionCreationChange>()
|
||||||
.onNext(
|
.onNext(
|
||||||
CollectionCreationChange.StepChanged(
|
CollectionCreationChange.StepChanged(
|
||||||
viewModel.tabCollections.getStepForCollectionsSize()
|
if (viewModel.state.tabCollections.isEmpty()) {
|
||||||
|
SaveCollectionStep.NameCollection
|
||||||
|
} else {
|
||||||
|
SaveCollectionStep.SelectCollection
|
||||||
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -161,41 +157,38 @@ class CreateCollectionFragment : DialogFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleBackPress(backPressFrom: SaveCollectionStep) {
|
private fun handleBackPress(backPressFrom: SaveCollectionStep) {
|
||||||
when (backPressFrom) {
|
val newStep = stepBack(backPressFrom)
|
||||||
SaveCollectionStep.SelectTabs -> dismiss()
|
if (newStep != null) {
|
||||||
SaveCollectionStep.SelectCollection -> {
|
getManagedEmitter<CollectionCreationChange>().onNext(CollectionCreationChange.StepChanged(newStep))
|
||||||
if (viewModel.tabs.size <= 1) dismiss() else {
|
} else {
|
||||||
getManagedEmitter<CollectionCreationChange>().onNext(
|
dismiss()
|
||||||
CollectionCreationChange.StepChanged(SaveCollectionStep.SelectTabs)
|
}
|
||||||
)
|
}
|
||||||
}
|
|
||||||
|
private fun stepBack(backFromStep: SaveCollectionStep): SaveCollectionStep? {
|
||||||
|
val state = viewModel.state
|
||||||
|
return when (backFromStep) {
|
||||||
|
SaveCollectionStep.SelectTabs, SaveCollectionStep.RenameCollection -> null
|
||||||
|
SaveCollectionStep.SelectCollection -> if (state.tabs.size <= 1) {
|
||||||
|
stepBack(SaveCollectionStep.SelectTabs)
|
||||||
|
} else {
|
||||||
|
SaveCollectionStep.SelectTabs
|
||||||
}
|
}
|
||||||
SaveCollectionStep.NameCollection -> {
|
SaveCollectionStep.NameCollection -> if (state.tabCollections.isEmpty()) {
|
||||||
if (viewModel.tabCollections.isEmpty() && viewModel.tabs.size == 1) {
|
stepBack(SaveCollectionStep.SelectCollection)
|
||||||
dismiss()
|
} else {
|
||||||
} else {
|
SaveCollectionStep.SelectCollection
|
||||||
getManagedEmitter<CollectionCreationChange>()
|
|
||||||
.onNext(
|
|
||||||
CollectionCreationChange.StepChanged(
|
|
||||||
viewModel.tabCollections.getBackStepForCollectionsSize()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SaveCollectionStep.RenameCollection -> {
|
|
||||||
dismiss()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun closeTabsIfNecessary(tabs: List<Tab>) {
|
private fun closeTabsIfNecessary(tabs: List<Tab>) {
|
||||||
// Only close the tabs if the user is not on the BrowserFragment
|
// Only close the tabs if the user is not on the BrowserFragment
|
||||||
if (viewModel.previousFragmentId == R.id.browserFragment) { return }
|
if (viewModel.previousFragmentId == R.id.browserFragment) {
|
||||||
|
val components = requireComponents
|
||||||
tabs.forEach {
|
tabs.asSequence()
|
||||||
requireComponents.core.sessionManager.findSessionById(it.sessionId)?.let { session ->
|
.mapNotNull { tab -> components.core.sessionManager.findSessionById(tab.sessionId) }
|
||||||
requireComponents.useCases.tabsUseCases.removeTab.invoke(session)
|
.forEach { session -> components.useCases.tabsUseCases.removeTab(session) }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,26 +4,47 @@
|
|||||||
|
|
||||||
package org.mozilla.fenix.collections
|
package org.mozilla.fenix.collections
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import org.mozilla.fenix.home.sessioncontrol.Tab
|
import org.mozilla.fenix.home.sessioncontrol.Tab
|
||||||
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
||||||
|
|
||||||
class CreateCollectionViewModel : ViewModel() {
|
class CreateCollectionViewModel : ViewModel() {
|
||||||
var selectedTabs = mutableSetOf<Tab>()
|
var state = CollectionCreationState()
|
||||||
var tabs = listOf<Tab>()
|
private set
|
||||||
var saveCollectionStep: SaveCollectionStep = SaveCollectionStep.SelectTabs
|
|
||||||
var tabCollections = listOf<TabCollection>()
|
|
||||||
var selectedTabCollection: TabCollection? = null
|
|
||||||
var snackbarAnchorView: View? = null
|
|
||||||
var previousFragmentId: Int? = null
|
var previousFragmentId: Int? = null
|
||||||
|
|
||||||
fun getStepForTabsAndCollectionSize(): SaveCollectionStep =
|
fun updateCollection(
|
||||||
if (tabs.size > 1) SaveCollectionStep.SelectTabs else tabCollections.getStepForCollectionsSize()
|
tabs: List<Tab>,
|
||||||
|
saveCollectionStep: SaveCollectionStep,
|
||||||
|
selectedTabCollection: TabCollection,
|
||||||
|
cachedTabCollections: List<TabCollection>
|
||||||
|
) {
|
||||||
|
state = CollectionCreationState(
|
||||||
|
tabs = tabs,
|
||||||
|
selectedTabs = if (tabs.size == 1) setOf(tabs.first()) else emptySet(),
|
||||||
|
tabCollections = cachedTabCollections.reversed(),
|
||||||
|
selectedTabCollection = selectedTabCollection,
|
||||||
|
saveCollectionStep = saveCollectionStep
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveTabToCollection(
|
||||||
|
tabs: List<Tab>,
|
||||||
|
selectedTab: Tab?,
|
||||||
|
cachedTabCollections: List<TabCollection>
|
||||||
|
) {
|
||||||
|
val tabCollections = cachedTabCollections.reversed()
|
||||||
|
state = CollectionCreationState(
|
||||||
|
tabs = tabs,
|
||||||
|
selectedTabs = selectedTab?.let { setOf(it) } ?: emptySet(),
|
||||||
|
tabCollections = tabCollections,
|
||||||
|
selectedTabCollection = null,
|
||||||
|
saveCollectionStep = when {
|
||||||
|
tabs.size > 1 -> SaveCollectionStep.SelectTabs
|
||||||
|
tabCollections.isNotEmpty() -> SaveCollectionStep.SelectCollection
|
||||||
|
else -> SaveCollectionStep.NameCollection
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun List<TabCollection>.getStepForCollectionsSize(): SaveCollectionStep =
|
|
||||||
if (isEmpty()) SaveCollectionStep.NameCollection else SaveCollectionStep.SelectCollection
|
|
||||||
|
|
||||||
fun List<TabCollection>.getBackStepForCollectionsSize(): SaveCollectionStep =
|
|
||||||
if (isEmpty()) SaveCollectionStep.SelectTabs else SaveCollectionStep.SelectCollection
|
|
||||||
|
@ -35,10 +35,8 @@ class SaveCollectionListAdapter(
|
|||||||
val collection = tabCollections[position]
|
val collection = tabCollections[position]
|
||||||
holder.bind(collection)
|
holder.bind(collection)
|
||||||
holder.itemView.setOnClickListener {
|
holder.itemView.setOnClickListener {
|
||||||
collection.apply {
|
val action = CollectionCreationAction.SelectCollection(collection, selectedTabs.toList())
|
||||||
val action = CollectionCreationAction.SelectCollection(this, selectedTabs.toList())
|
actionEmitter.onNext(action)
|
||||||
actionEmitter.onNext(action)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,6 @@ import org.mozilla.fenix.R
|
|||||||
import org.mozilla.fenix.browser.BrowserFragment
|
import org.mozilla.fenix.browser.BrowserFragment
|
||||||
import org.mozilla.fenix.browser.BrowserFragmentDirections
|
import org.mozilla.fenix.browser.BrowserFragmentDirections
|
||||||
import org.mozilla.fenix.collections.CreateCollectionViewModel
|
import org.mozilla.fenix.collections.CreateCollectionViewModel
|
||||||
import org.mozilla.fenix.collections.getStepForCollectionsSize
|
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.ext.nav
|
import org.mozilla.fenix.ext.nav
|
||||||
@ -123,14 +122,12 @@ class DefaultBrowserToolbarController(
|
|||||||
context.components.analytics.metrics
|
context.components.analytics.metrics
|
||||||
.track(Event.CollectionSaveButtonPressed(TELEMETRY_BROWSER_IDENTIFIER))
|
.track(Event.CollectionSaveButtonPressed(TELEMETRY_BROWSER_IDENTIFIER))
|
||||||
|
|
||||||
currentSession?.toTab(context)?.let {
|
currentSession?.toTab(context)?.let { currentSessionAsTab ->
|
||||||
viewModel.tabs = listOf(it)
|
viewModel.saveTabToCollection(
|
||||||
val selectedSet = mutableSetOf(it)
|
tabs = listOf(currentSessionAsTab),
|
||||||
viewModel.selectedTabs = selectedSet
|
selectedTab = currentSessionAsTab,
|
||||||
viewModel.tabCollections =
|
cachedTabCollections = context.components.core.tabCollectionStorage.cachedTabCollections
|
||||||
context.components.core.tabCollectionStorage.cachedTabCollections.reversed()
|
)
|
||||||
viewModel.saveCollectionStep = viewModel.tabCollections.getStepForCollectionsSize()
|
|
||||||
viewModel.snackbarAnchorView = nestedScrollQuickActionView
|
|
||||||
viewModel.previousFragmentId = R.id.browserFragment
|
viewModel.previousFragmentId = R.id.browserFragment
|
||||||
|
|
||||||
val directions = BrowserFragmentDirections.actionBrowserFragmentToCreateCollectionFragment()
|
val directions = BrowserFragmentDirections.actionBrowserFragmentToCreateCollectionFragment()
|
||||||
|
@ -25,7 +25,7 @@ import androidx.lifecycle.OnLifecycleEvent
|
|||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.fragment.FragmentNavigator
|
import androidx.navigation.fragment.FragmentNavigator
|
||||||
import androidx.navigation.fragment.NavHostFragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE
|
import androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE
|
||||||
@ -309,7 +309,7 @@ class HomeFragment : Fragment(), AccountObserver {
|
|||||||
is TabAction.SaveTabGroup -> {
|
is TabAction.SaveTabGroup -> {
|
||||||
if ((activity as HomeActivity).browsingModeManager.mode.isPrivate) return
|
if ((activity as HomeActivity).browsingModeManager.mode.isPrivate) return
|
||||||
invokePendingDeleteJobs()
|
invokePendingDeleteJobs()
|
||||||
showCollectionCreationFragment(action.selectedTabSessionId)
|
saveTabToCollection(action.selectedTabSessionId)
|
||||||
}
|
}
|
||||||
is TabAction.Select -> {
|
is TabAction.Select -> {
|
||||||
invokePendingDeleteJobs()
|
invokePendingDeleteJobs()
|
||||||
@ -437,16 +437,10 @@ class HomeFragment : Fragment(), AccountObserver {
|
|||||||
}
|
}
|
||||||
is CollectionAction.AddTab -> {
|
is CollectionAction.AddTab -> {
|
||||||
requireComponents.analytics.metrics.track(Event.CollectionAddTabPressed)
|
requireComponents.analytics.metrics.track(Event.CollectionAddTabPressed)
|
||||||
showCollectionCreationFragment(
|
updateCollection(action.collection, SaveCollectionStep.SelectTabs)
|
||||||
selectedTabCollection = action.collection,
|
|
||||||
step = SaveCollectionStep.SelectTabs
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
is CollectionAction.Rename -> {
|
is CollectionAction.Rename -> {
|
||||||
showCollectionCreationFragment(
|
updateCollection(action.collection, SaveCollectionStep.RenameCollection)
|
||||||
selectedTabCollection = action.collection,
|
|
||||||
step = SaveCollectionStep.RenameCollection
|
|
||||||
)
|
|
||||||
requireComponents.analytics.metrics.track(Event.CollectionRenamePressed)
|
requireComponents.analytics.metrics.track(Event.CollectionRenamePressed)
|
||||||
}
|
}
|
||||||
is CollectionAction.OpenTab -> {
|
is CollectionAction.OpenTab -> {
|
||||||
@ -647,27 +641,18 @@ class HomeFragment : Fragment(), AccountObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun showCollectionCreationFragment(
|
private fun showCollectionCreationFragment(
|
||||||
selectedTabId: String? = null,
|
setupViewModel: (CreateCollectionViewModel, tabs: List<Tab>, cachedTabCollections: List<TabCollection>) -> Unit
|
||||||
selectedTabCollection: TabCollection? = null,
|
|
||||||
step: SaveCollectionStep? = null
|
|
||||||
) {
|
) {
|
||||||
if (findNavController(this).currentDestination?.id == R.id.createCollectionFragment) return
|
if (findNavController().currentDestination?.id == R.id.createCollectionFragment) return
|
||||||
|
|
||||||
val tabs = getListOfSessions().toTabs()
|
|
||||||
|
|
||||||
val viewModel: CreateCollectionViewModel by activityViewModels {
|
val viewModel: CreateCollectionViewModel by activityViewModels {
|
||||||
ViewModelProvider.NewInstanceFactory() // this is a workaround for #4652
|
ViewModelProvider.NewInstanceFactory() // this is a workaround for #4652
|
||||||
}
|
}
|
||||||
viewModel.tabs = tabs
|
|
||||||
val selectedTabs =
|
val tabs = getListOfSessions().toTabs()
|
||||||
tabs.find { tab -> tab.sessionId == selectedTabId }
|
val cachedTabCollections = requireComponents.core.tabCollectionStorage.cachedTabCollections
|
||||||
?: if (tabs.size == 1) tabs[0] else null
|
setupViewModel(viewModel, tabs, cachedTabCollections)
|
||||||
val selectedSet = if (selectedTabs == null) mutableSetOf() else mutableSetOf(selectedTabs)
|
|
||||||
viewModel.selectedTabs = selectedSet
|
|
||||||
viewModel.tabCollections = requireComponents.core.tabCollectionStorage.cachedTabCollections.reversed()
|
|
||||||
viewModel.selectedTabCollection = selectedTabCollection
|
|
||||||
viewModel.saveCollectionStep =
|
|
||||||
step ?: viewModel.getStepForTabsAndCollectionSize()
|
|
||||||
viewModel.previousFragmentId = R.id.homeFragment
|
viewModel.previousFragmentId = R.id.homeFragment
|
||||||
|
|
||||||
// Only register the observer right before moving to collection creation
|
// Only register the observer right before moving to collection creation
|
||||||
@ -679,6 +664,27 @@ class HomeFragment : Fragment(), AccountObserver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun saveTabToCollection(selectedTabId: String?) {
|
||||||
|
showCollectionCreationFragment { viewModel, tabs, cachedTabCollections ->
|
||||||
|
viewModel.saveTabToCollection(
|
||||||
|
tabs = tabs,
|
||||||
|
selectedTab = tabs.find { it.sessionId == selectedTabId } ?: if (tabs.size == 1) tabs[0] else null,
|
||||||
|
cachedTabCollections = cachedTabCollections
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateCollection(selectedTabCollection: TabCollection, step: SaveCollectionStep) {
|
||||||
|
showCollectionCreationFragment { viewModel, tabs, cachedTabCollections ->
|
||||||
|
viewModel.updateCollection(
|
||||||
|
tabs = tabs,
|
||||||
|
saveCollectionStep = step,
|
||||||
|
selectedTabCollection = selectedTabCollection,
|
||||||
|
cachedTabCollections = cachedTabCollections
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun share(url: String? = null, tabs: List<ShareTab>? = null) {
|
private fun share(url: String? = null, tabs: List<ShareTab>? = null) {
|
||||||
val directions =
|
val directions =
|
||||||
HomeFragmentDirections.actionHomeFragmentToShareFragment(
|
HomeFragmentDirections.actionHomeFragmentToShareFragment(
|
||||||
|
@ -0,0 +1,150 @@
|
|||||||
|
/* 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.collections
|
||||||
|
|
||||||
|
import io.mockk.MockKAnnotations
|
||||||
|
import io.mockk.mockk
|
||||||
|
import mozilla.components.feature.tab.collections.TabCollection
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertNull
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.Tab
|
||||||
|
|
||||||
|
class CreateCollectionViewModelTest {
|
||||||
|
|
||||||
|
private lateinit var viewModel: CreateCollectionViewModel
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
MockKAnnotations.init(this)
|
||||||
|
|
||||||
|
viewModel = CreateCollectionViewModel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `initial state defaults`() {
|
||||||
|
assertEquals(
|
||||||
|
CollectionCreationState(
|
||||||
|
tabs = emptyList(),
|
||||||
|
selectedTabs = emptySet(),
|
||||||
|
saveCollectionStep = SaveCollectionStep.SelectTabs,
|
||||||
|
tabCollections = emptyList(),
|
||||||
|
selectedTabCollection = null
|
||||||
|
),
|
||||||
|
viewModel.state
|
||||||
|
)
|
||||||
|
assertNull(viewModel.previousFragmentId)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `updateCollection copies tabs to state`() {
|
||||||
|
val tabs = listOf<Tab>(mockk(), mockk())
|
||||||
|
val tabCollections = listOf<TabCollection>(mockk(), mockk())
|
||||||
|
val selectedCollection: TabCollection = mockk()
|
||||||
|
viewModel.updateCollection(
|
||||||
|
tabs = tabs,
|
||||||
|
saveCollectionStep = SaveCollectionStep.SelectCollection,
|
||||||
|
selectedTabCollection = selectedCollection,
|
||||||
|
cachedTabCollections = tabCollections
|
||||||
|
)
|
||||||
|
assertEquals(tabs, viewModel.state.tabs)
|
||||||
|
assertEquals(SaveCollectionStep.SelectCollection, viewModel.state.saveCollectionStep)
|
||||||
|
assertEquals(selectedCollection, viewModel.state.selectedTabCollection)
|
||||||
|
assertEquals(tabCollections.reversed(), viewModel.state.tabCollections)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `updateCollection selects the only tab`() {
|
||||||
|
val tab: Tab = mockk()
|
||||||
|
viewModel.updateCollection(
|
||||||
|
tabs = listOf(tab),
|
||||||
|
saveCollectionStep = mockk(),
|
||||||
|
selectedTabCollection = mockk(),
|
||||||
|
cachedTabCollections = emptyList()
|
||||||
|
)
|
||||||
|
assertEquals(setOf(tab), viewModel.state.selectedTabs)
|
||||||
|
|
||||||
|
viewModel.updateCollection(
|
||||||
|
tabs = listOf(tab, mockk()),
|
||||||
|
saveCollectionStep = mockk(),
|
||||||
|
selectedTabCollection = mockk(),
|
||||||
|
cachedTabCollections = emptyList()
|
||||||
|
)
|
||||||
|
assertEquals(emptySet<Tab>(), viewModel.state.selectedTabs)
|
||||||
|
|
||||||
|
viewModel.updateCollection(
|
||||||
|
tabs = emptyList(),
|
||||||
|
saveCollectionStep = mockk(),
|
||||||
|
selectedTabCollection = mockk(),
|
||||||
|
cachedTabCollections = emptyList()
|
||||||
|
)
|
||||||
|
assertEquals(emptySet<Tab>(), viewModel.state.selectedTabs)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `saveTabToCollection copies tabs to state`() {
|
||||||
|
val tabs = listOf<Tab>(mockk(), mockk())
|
||||||
|
val tabCollections = listOf<TabCollection>(mockk(), mockk())
|
||||||
|
viewModel.saveTabToCollection(
|
||||||
|
tabs = tabs,
|
||||||
|
selectedTab = null,
|
||||||
|
cachedTabCollections = tabCollections
|
||||||
|
)
|
||||||
|
assertEquals(tabs, viewModel.state.tabs)
|
||||||
|
assertEquals(SaveCollectionStep.SelectTabs, viewModel.state.saveCollectionStep)
|
||||||
|
assertNull(viewModel.state.selectedTabCollection)
|
||||||
|
assertEquals(tabCollections.reversed(), viewModel.state.tabCollections)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `saveTabToCollection selects selectedTab`() {
|
||||||
|
val tab: Tab = mockk()
|
||||||
|
viewModel.saveTabToCollection(
|
||||||
|
tabs = listOf(mockk()),
|
||||||
|
selectedTab = tab,
|
||||||
|
cachedTabCollections = emptyList()
|
||||||
|
)
|
||||||
|
assertEquals(setOf(tab), viewModel.state.selectedTabs)
|
||||||
|
|
||||||
|
viewModel.saveTabToCollection(
|
||||||
|
tabs = listOf(mockk()),
|
||||||
|
selectedTab = null,
|
||||||
|
cachedTabCollections = emptyList()
|
||||||
|
)
|
||||||
|
assertEquals(emptySet<Tab>(), viewModel.state.selectedTabs)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `saveTabToCollection sets saveCollectionStep`() {
|
||||||
|
viewModel.saveTabToCollection(
|
||||||
|
tabs = listOf(mockk(), mockk()),
|
||||||
|
selectedTab = null,
|
||||||
|
cachedTabCollections = listOf(mockk())
|
||||||
|
)
|
||||||
|
assertEquals(SaveCollectionStep.SelectTabs, viewModel.state.saveCollectionStep)
|
||||||
|
|
||||||
|
viewModel.saveTabToCollection(
|
||||||
|
tabs = listOf(mockk()),
|
||||||
|
selectedTab = null,
|
||||||
|
cachedTabCollections = listOf(mockk())
|
||||||
|
)
|
||||||
|
assertEquals(SaveCollectionStep.SelectCollection, viewModel.state.saveCollectionStep)
|
||||||
|
|
||||||
|
viewModel.saveTabToCollection(
|
||||||
|
tabs = emptyList(),
|
||||||
|
selectedTab = null,
|
||||||
|
cachedTabCollections = listOf(mockk())
|
||||||
|
)
|
||||||
|
assertEquals(SaveCollectionStep.SelectCollection, viewModel.state.saveCollectionStep)
|
||||||
|
|
||||||
|
viewModel.saveTabToCollection(
|
||||||
|
tabs = emptyList(),
|
||||||
|
selectedTab = null,
|
||||||
|
cachedTabCollections = emptyList()
|
||||||
|
)
|
||||||
|
assertEquals(SaveCollectionStep.NameCollection, viewModel.state.saveCollectionStep)
|
||||||
|
}
|
||||||
|
}
|
@ -29,7 +29,6 @@ import org.mozilla.fenix.R
|
|||||||
import org.mozilla.fenix.browser.BrowserFragment
|
import org.mozilla.fenix.browser.BrowserFragment
|
||||||
import org.mozilla.fenix.browser.BrowserFragmentDirections
|
import org.mozilla.fenix.browser.BrowserFragmentDirections
|
||||||
import org.mozilla.fenix.collections.CreateCollectionViewModel
|
import org.mozilla.fenix.collections.CreateCollectionViewModel
|
||||||
import org.mozilla.fenix.collections.SaveCollectionStep
|
|
||||||
import org.mozilla.fenix.components.Analytics
|
import org.mozilla.fenix.components.Analytics
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.components.metrics.MetricController
|
import org.mozilla.fenix.components.metrics.MetricController
|
||||||
@ -322,11 +321,13 @@ class DefaultBrowserToolbarControllerTest {
|
|||||||
|
|
||||||
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.SAVE_TO_COLLECTION)) }
|
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.SAVE_TO_COLLECTION)) }
|
||||||
verify { metrics.track(Event.CollectionSaveButtonPressed(DefaultBrowserToolbarController.TELEMETRY_BROWSER_IDENTIFIER)) }
|
verify { metrics.track(Event.CollectionSaveButtonPressed(DefaultBrowserToolbarController.TELEMETRY_BROWSER_IDENTIFIER)) }
|
||||||
verify { viewModel.tabs = listOf(currentSessionAsTab) }
|
verify {
|
||||||
verify { viewModel.selectedTabs = mutableSetOf(currentSessionAsTab) }
|
viewModel.saveTabToCollection(
|
||||||
verify { viewModel.tabCollections = cachedTabCollections.reversed() }
|
listOf(currentSessionAsTab),
|
||||||
verify { viewModel.saveCollectionStep = SaveCollectionStep.SelectCollection }
|
currentSessionAsTab,
|
||||||
verify { viewModel.snackbarAnchorView = nestedScrollQuickActionView }
|
cachedTabCollections
|
||||||
|
)
|
||||||
|
}
|
||||||
verify { viewModel.previousFragmentId = R.id.browserFragment }
|
verify { viewModel.previousFragmentId = R.id.browserFragment }
|
||||||
verify {
|
verify {
|
||||||
val directions = BrowserFragmentDirections
|
val directions = BrowserFragmentDirections
|
||||||
|
Loading…
Reference in New Issue
Block a user