2019-04-23 00:07:03 +02:00
|
|
|
package org.mozilla.fenix.collections
|
|
|
|
|
|
|
|
/* 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/. */
|
|
|
|
|
2019-05-02 17:53:40 +02:00
|
|
|
import android.os.Handler
|
2019-04-30 00:52:55 +02:00
|
|
|
import android.view.KeyEvent
|
2019-04-23 00:07:03 +02:00
|
|
|
import android.view.LayoutInflater
|
2019-04-30 00:52:55 +02:00
|
|
|
import android.view.View
|
2019-04-23 00:07:03 +02:00
|
|
|
import android.view.ViewGroup
|
2019-04-30 00:52:55 +02:00
|
|
|
import android.view.inputmethod.EditorInfo
|
2019-05-02 17:53:40 +02:00
|
|
|
import androidx.constraintlayout.widget.ConstraintSet
|
2019-05-31 19:59:51 +02:00
|
|
|
import androidx.core.content.ContextCompat
|
2019-04-23 04:49:44 +02:00
|
|
|
import androidx.recyclerview.widget.LinearLayoutManager
|
|
|
|
import androidx.recyclerview.widget.RecyclerView
|
2019-05-02 17:53:40 +02:00
|
|
|
import androidx.transition.AutoTransition
|
|
|
|
import androidx.transition.Transition
|
|
|
|
import androidx.transition.TransitionManager
|
2019-04-23 00:07:03 +02:00
|
|
|
import io.reactivex.Observable
|
2019-04-30 00:52:55 +02:00
|
|
|
import io.reactivex.Observer
|
2019-04-23 00:07:03 +02:00
|
|
|
import io.reactivex.functions.Consumer
|
2019-04-30 00:52:55 +02:00
|
|
|
import kotlinx.android.synthetic.main.component_collection_creation.*
|
2019-04-23 04:49:44 +02:00
|
|
|
import kotlinx.android.synthetic.main.component_collection_creation.view.*
|
2019-06-07 18:33:07 +02:00
|
|
|
import kotlinx.coroutines.CoroutineScope
|
|
|
|
import kotlinx.coroutines.Dispatchers
|
|
|
|
import kotlinx.coroutines.Job
|
|
|
|
import kotlinx.coroutines.launch
|
2019-05-02 17:53:40 +02:00
|
|
|
import mozilla.components.support.ktx.android.view.hideKeyboard
|
|
|
|
import mozilla.components.support.ktx.android.view.showKeyboard
|
2019-04-30 00:52:55 +02:00
|
|
|
import org.mozilla.fenix.R
|
2019-04-24 01:30:51 +02:00
|
|
|
import org.mozilla.fenix.ext.increaseTapArea
|
2019-05-20 22:34:58 +02:00
|
|
|
import org.mozilla.fenix.ext.urlToTrimmedHost
|
2019-05-06 20:20:19 +02:00
|
|
|
import org.mozilla.fenix.home.sessioncontrol.Tab
|
2019-05-20 22:34:58 +02:00
|
|
|
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
2019-04-23 00:07:03 +02:00
|
|
|
import org.mozilla.fenix.mvi.UIView
|
2019-06-07 18:33:07 +02:00
|
|
|
import kotlin.coroutines.CoroutineContext
|
2019-04-23 00:07:03 +02:00
|
|
|
|
|
|
|
class CollectionCreationUIView(
|
|
|
|
container: ViewGroup,
|
|
|
|
actionEmitter: Observer<CollectionCreationAction>,
|
|
|
|
changesObservable: Observable<CollectionCreationChange>
|
|
|
|
) : UIView<CollectionCreationState, CollectionCreationAction, CollectionCreationChange>(
|
|
|
|
container,
|
|
|
|
actionEmitter,
|
|
|
|
changesObservable
|
2019-06-07 18:33:07 +02:00
|
|
|
), CoroutineScope {
|
|
|
|
private lateinit var job: Job
|
|
|
|
override val coroutineContext: CoroutineContext
|
|
|
|
get() = Dispatchers.Main + job
|
|
|
|
|
2019-04-23 00:07:03 +02:00
|
|
|
override val view = LayoutInflater.from(container.context)
|
|
|
|
.inflate(R.layout.component_collection_creation, container, true)
|
|
|
|
|
2019-04-30 00:52:55 +02:00
|
|
|
var step: SaveCollectionStep = SaveCollectionStep.SelectTabs
|
|
|
|
private set
|
|
|
|
|
2019-04-23 04:49:44 +02:00
|
|
|
private val collectionCreationTabListAdapter = CollectionCreationTabListAdapter(actionEmitter)
|
2019-04-30 00:52:55 +02:00
|
|
|
private val collectionSaveListAdapter = SaveCollectionListAdapter(actionEmitter)
|
2019-05-20 22:34:58 +02:00
|
|
|
private var selectedCollection: TabCollection? = null
|
2019-04-24 01:40:26 +02:00
|
|
|
private var selectedTabs: Set<Tab> = setOf()
|
2019-05-02 17:53:40 +02:00
|
|
|
private val selectTabsConstraints = ConstraintSet()
|
|
|
|
private val selectCollectionConstraints = ConstraintSet()
|
|
|
|
private val nameCollectionConstraints = ConstraintSet()
|
|
|
|
private val transition = AutoTransition()
|
2019-04-23 04:49:44 +02:00
|
|
|
|
|
|
|
init {
|
2019-06-08 13:05:25 +02:00
|
|
|
job = Job()
|
2019-05-02 17:53:40 +02:00
|
|
|
transition.duration = TRANSITION_DURATION
|
|
|
|
|
|
|
|
selectTabsConstraints.clone(collection_constraint_layout)
|
|
|
|
selectCollectionConstraints.clone(
|
|
|
|
view.context,
|
|
|
|
R.layout.component_collection_creation_select_collection
|
|
|
|
)
|
|
|
|
nameCollectionConstraints.clone(
|
|
|
|
view.context,
|
|
|
|
R.layout.component_collection_creation_name_collection
|
|
|
|
)
|
|
|
|
|
2019-05-31 19:59:51 +02:00
|
|
|
view.bottom_bar_icon_button.apply {
|
2019-04-24 01:30:51 +02:00
|
|
|
increaseTapArea(increaseButtonByDps)
|
|
|
|
}
|
|
|
|
|
2019-05-27 19:04:17 +02:00
|
|
|
view.name_collection_edittext.setOnEditorActionListener { v, actionId, _ ->
|
2019-05-31 19:59:51 +02:00
|
|
|
if (actionId == EditorInfo.IME_ACTION_DONE && v.text.toString().isNotEmpty()) {
|
2019-05-20 22:34:58 +02:00
|
|
|
when (step) {
|
|
|
|
is SaveCollectionStep.NameCollection -> {
|
|
|
|
actionEmitter.onNext(
|
|
|
|
CollectionCreationAction.SaveCollectionName(
|
|
|
|
selectedTabs.toList(),
|
|
|
|
v.text.toString()
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
is SaveCollectionStep.RenameCollection -> {
|
|
|
|
selectedCollection?.let {
|
|
|
|
actionEmitter.onNext(CollectionCreationAction.RenameCollection(it, v.text.toString()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-04-30 00:52:55 +02:00
|
|
|
}
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2019-04-23 04:49:44 +02:00
|
|
|
view.tab_list.run {
|
|
|
|
adapter = collectionCreationTabListAdapter
|
|
|
|
layoutManager = LinearLayoutManager(container.context, RecyclerView.VERTICAL, true)
|
|
|
|
}
|
2019-04-30 00:52:55 +02:00
|
|
|
|
|
|
|
view.collections_list.run {
|
|
|
|
adapter = collectionSaveListAdapter
|
|
|
|
layoutManager = LinearLayoutManager(container.context, RecyclerView.VERTICAL, true)
|
|
|
|
}
|
2019-04-23 04:49:44 +02:00
|
|
|
}
|
|
|
|
|
2019-05-02 17:53:40 +02:00
|
|
|
@Suppress("ComplexMethod")
|
2019-04-23 04:49:44 +02:00
|
|
|
override fun updateView() = Consumer<CollectionCreationState> {
|
2019-04-30 00:52:55 +02:00
|
|
|
step = it.saveCollectionStep
|
2019-05-25 02:06:17 +02:00
|
|
|
selectedTabs = it.selectedTabs
|
2019-05-29 00:43:44 +02:00
|
|
|
selectedCollection = it.selectedTabCollection
|
2019-05-25 02:06:17 +02:00
|
|
|
|
2019-04-30 00:52:55 +02:00
|
|
|
when (it.saveCollectionStep) {
|
|
|
|
is SaveCollectionStep.SelectTabs -> {
|
2019-05-31 19:59:51 +02:00
|
|
|
view.tab_list.isClickable = true
|
|
|
|
|
2019-04-30 00:52:55 +02:00
|
|
|
back_button.setOnClickListener {
|
|
|
|
actionEmitter.onNext(CollectionCreationAction.BackPressed(SaveCollectionStep.SelectTabs))
|
|
|
|
}
|
2019-05-28 22:50:15 +02:00
|
|
|
val allSelected = it.selectedTabs.size == it.tabs.size
|
|
|
|
select_all_button.text =
|
|
|
|
if (allSelected)
|
|
|
|
view.context.getString(R.string.create_collection_deselect_all) else
|
|
|
|
view.context.getString(R.string.create_collection_select_all)
|
|
|
|
|
|
|
|
view.select_all_button.setOnClickListener {
|
|
|
|
if (allSelected) {
|
|
|
|
actionEmitter.onNext(CollectionCreationAction.DeselectAllTapped)
|
|
|
|
} else {
|
|
|
|
actionEmitter.onNext(CollectionCreationAction.SelectAllTapped)
|
|
|
|
}
|
|
|
|
}
|
2019-05-31 19:59:51 +02:00
|
|
|
|
|
|
|
view.bottom_button_bar_layout.setOnClickListener(null)
|
|
|
|
view.bottom_button_bar_layout.isClickable = false
|
|
|
|
|
|
|
|
val drawable = view.context.getDrawable(R.drawable.ic_close)
|
|
|
|
drawable?.setTint(ContextCompat.getColor(view.context, R.color.photonWhite))
|
|
|
|
view.bottom_bar_icon_button.setImageDrawable(drawable)
|
|
|
|
|
|
|
|
view.bottom_bar_icon_button.setOnClickListener {
|
|
|
|
actionEmitter.onNext(CollectionCreationAction.Close)
|
|
|
|
}
|
|
|
|
|
2019-05-02 17:53:40 +02:00
|
|
|
TransitionManager.beginDelayedTransition(
|
|
|
|
view.collection_constraint_layout,
|
|
|
|
transition
|
|
|
|
)
|
|
|
|
val constraint = selectTabsConstraints
|
|
|
|
constraint.applyTo(view.collection_constraint_layout)
|
2019-04-30 00:52:55 +02:00
|
|
|
|
|
|
|
collectionCreationTabListAdapter.updateData(it.tabs, it.selectedTabs)
|
|
|
|
|
|
|
|
back_button.text = view.context.getString(R.string.create_collection_select_tabs)
|
|
|
|
|
2019-05-02 17:53:40 +02:00
|
|
|
val selectTabsText = if (it.selectedTabs.isEmpty()) {
|
2019-04-30 00:52:55 +02:00
|
|
|
view.context.getString(R.string.create_collection_save_to_collection_empty)
|
|
|
|
} else {
|
2019-05-02 21:32:49 +02:00
|
|
|
view.context.getString(
|
|
|
|
if (it.selectedTabs.size == 1)
|
|
|
|
R.string.create_collection_save_to_collection_tab_selected else
|
|
|
|
R.string.create_collection_save_to_collection_tabs_selected,
|
2019-04-30 00:52:55 +02:00
|
|
|
it.selectedTabs.size
|
|
|
|
)
|
|
|
|
}
|
2019-05-29 00:43:44 +02:00
|
|
|
|
2019-05-31 19:59:51 +02:00
|
|
|
view.bottom_bar_text.text = selectTabsText
|
2019-04-24 01:18:59 +02:00
|
|
|
|
2019-05-29 00:43:44 +02:00
|
|
|
save_button.setOnClickListener { _ ->
|
|
|
|
if (selectedCollection != null) {
|
|
|
|
actionEmitter.onNext(
|
|
|
|
CollectionCreationAction.SelectCollection(
|
|
|
|
selectedCollection!!,
|
|
|
|
it.selectedTabs.toList()
|
|
|
|
)
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
actionEmitter.onNext(CollectionCreationAction.SaveTabsToCollection(selectedTabs.toList()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-02 17:53:40 +02:00
|
|
|
save_button.visibility = if (it.selectedTabs.isEmpty()) {
|
|
|
|
View.GONE
|
|
|
|
} else {
|
|
|
|
View.VISIBLE
|
|
|
|
}
|
2019-04-30 00:52:55 +02:00
|
|
|
}
|
|
|
|
is SaveCollectionStep.SelectCollection -> {
|
2019-05-31 19:59:51 +02:00
|
|
|
view.tab_list.isClickable = false
|
|
|
|
|
|
|
|
save_button.visibility = View.GONE
|
|
|
|
|
|
|
|
view.bottom_bar_text.text =
|
|
|
|
view.context.getString(R.string.create_collection_add_new_collection)
|
|
|
|
|
|
|
|
val drawable = view.context.getDrawable(R.drawable.ic_new)
|
|
|
|
drawable?.setTint(ContextCompat.getColor(view.context, R.color.photonWhite))
|
|
|
|
view.bottom_bar_icon_button.setImageDrawable(drawable)
|
|
|
|
view.bottom_bar_icon_button.setOnClickListener(null)
|
|
|
|
|
|
|
|
view.bottom_button_bar_layout.isClickable = true
|
|
|
|
view.bottom_button_bar_layout.setOnClickListener {
|
|
|
|
actionEmitter.onNext(CollectionCreationAction.AddNewCollection)
|
|
|
|
}
|
2019-05-02 17:53:40 +02:00
|
|
|
|
2019-04-30 00:52:55 +02:00
|
|
|
back_button.setOnClickListener {
|
|
|
|
actionEmitter.onNext(CollectionCreationAction.BackPressed(SaveCollectionStep.SelectCollection))
|
|
|
|
}
|
2019-05-02 17:53:40 +02:00
|
|
|
TransitionManager.beginDelayedTransition(
|
|
|
|
view.collection_constraint_layout,
|
|
|
|
transition
|
|
|
|
)
|
|
|
|
val constraint = selectCollectionConstraints
|
|
|
|
constraint.applyTo(view.collection_constraint_layout)
|
2019-04-30 00:52:55 +02:00
|
|
|
back_button.text =
|
|
|
|
view.context.getString(R.string.create_collection_select_collection)
|
|
|
|
}
|
|
|
|
is SaveCollectionStep.NameCollection -> {
|
2019-05-31 19:59:51 +02:00
|
|
|
view.tab_list.isClickable = false
|
|
|
|
|
|
|
|
collectionCreationTabListAdapter.updateData(it.selectedTabs.toList(), it.selectedTabs, true)
|
2019-04-30 00:52:55 +02:00
|
|
|
back_button.setOnClickListener {
|
2019-05-02 17:53:40 +02:00
|
|
|
name_collection_edittext.hideKeyboard()
|
|
|
|
val handler = Handler()
|
|
|
|
handler.postDelayed({
|
|
|
|
actionEmitter.onNext(CollectionCreationAction.BackPressed(SaveCollectionStep.NameCollection))
|
|
|
|
}, TRANSITION_DURATION)
|
2019-04-30 00:52:55 +02:00
|
|
|
}
|
2019-05-02 17:53:40 +02:00
|
|
|
transition.addListener(object : Transition.TransitionListener {
|
|
|
|
override fun onTransitionStart(transition: Transition) {
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onTransitionEnd(transition: Transition) {
|
|
|
|
view.name_collection_edittext.showKeyboard()
|
|
|
|
transition.removeListener(this)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onTransitionCancel(transition: Transition) {}
|
|
|
|
override fun onTransitionPause(transition: Transition) {}
|
|
|
|
override fun onTransitionResume(transition: Transition) {}
|
|
|
|
})
|
|
|
|
TransitionManager.beginDelayedTransition(
|
|
|
|
view.collection_constraint_layout,
|
|
|
|
transition
|
|
|
|
)
|
|
|
|
val constraint = nameCollectionConstraints
|
|
|
|
constraint.applyTo(view.collection_constraint_layout)
|
|
|
|
name_collection_edittext.setText(
|
|
|
|
view.context.getString(
|
|
|
|
R.string.create_collection_default_name,
|
2019-05-16 23:35:15 +02:00
|
|
|
it.tabCollections.size + 1
|
2019-05-02 17:53:40 +02:00
|
|
|
)
|
|
|
|
)
|
2019-05-16 23:07:19 +02:00
|
|
|
name_collection_edittext.setSelection(0, name_collection_edittext.text.length)
|
2019-04-30 00:52:55 +02:00
|
|
|
back_button.text =
|
|
|
|
view.context.getString(R.string.create_collection_name_collection)
|
|
|
|
}
|
2019-05-20 22:34:58 +02:00
|
|
|
is SaveCollectionStep.RenameCollection -> {
|
2019-05-31 19:59:51 +02:00
|
|
|
view.tab_list.isClickable = false
|
|
|
|
|
2019-06-07 18:33:07 +02:00
|
|
|
launch(Dispatchers.Main) {
|
|
|
|
it.selectedTabCollection?.let { tabCollection ->
|
|
|
|
tabCollection.tabs.map { tab ->
|
|
|
|
Tab(
|
|
|
|
tab.id.toString(),
|
|
|
|
tab.url,
|
|
|
|
tab.url.urlToTrimmedHost(view.context),
|
|
|
|
tab.title
|
|
|
|
)
|
|
|
|
}.let { tabs ->
|
|
|
|
collectionCreationTabListAdapter.updateData(tabs, tabs.toSet(), true)
|
|
|
|
}
|
2019-05-20 22:34:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
back_button.setOnClickListener {
|
|
|
|
name_collection_edittext.hideKeyboard()
|
|
|
|
val handler = Handler()
|
|
|
|
handler.postDelayed({
|
|
|
|
actionEmitter.onNext(CollectionCreationAction.BackPressed(SaveCollectionStep.RenameCollection))
|
|
|
|
}, TRANSITION_DURATION)
|
|
|
|
}
|
|
|
|
transition.addListener(object : Transition.TransitionListener {
|
|
|
|
override fun onTransitionStart(transition: Transition) {
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onTransitionEnd(transition: Transition) {
|
|
|
|
view.name_collection_edittext.showKeyboard()
|
|
|
|
transition.removeListener(this)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onTransitionCancel(transition: Transition) {}
|
|
|
|
override fun onTransitionPause(transition: Transition) {}
|
|
|
|
override fun onTransitionResume(transition: Transition) {}
|
|
|
|
})
|
|
|
|
TransitionManager.beginDelayedTransition(
|
|
|
|
view.collection_constraint_layout,
|
|
|
|
transition
|
|
|
|
)
|
|
|
|
val constraint = nameCollectionConstraints
|
|
|
|
constraint.applyTo(view.collection_constraint_layout)
|
|
|
|
name_collection_edittext.setText(it.selectedTabCollection?.title)
|
|
|
|
name_collection_edittext.setSelection(0, name_collection_edittext.text.length)
|
|
|
|
back_button.text =
|
|
|
|
view.context.getString(R.string.create_collection_name_collection)
|
|
|
|
}
|
2019-04-30 00:52:55 +02:00
|
|
|
}
|
2019-05-23 19:11:22 +02:00
|
|
|
collectionSaveListAdapter.updateData(it.tabCollections, it.selectedTabs)
|
2019-04-30 00:52:55 +02:00
|
|
|
}
|
|
|
|
|
2019-05-02 17:53:40 +02:00
|
|
|
fun onResumed() {
|
|
|
|
if (step == SaveCollectionStep.NameCollection) {
|
|
|
|
view.name_collection_edittext.showKeyboard()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-30 00:52:55 +02:00
|
|
|
fun onKey(keyCode: Int, event: KeyEvent?): Boolean {
|
|
|
|
if (event?.action == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
|
|
|
when (step) {
|
|
|
|
SaveCollectionStep.SelectTabs -> {
|
|
|
|
actionEmitter.onNext(CollectionCreationAction.BackPressed(SaveCollectionStep.SelectTabs))
|
|
|
|
}
|
|
|
|
SaveCollectionStep.SelectCollection -> {
|
|
|
|
actionEmitter.onNext(CollectionCreationAction.BackPressed(SaveCollectionStep.SelectCollection))
|
|
|
|
}
|
|
|
|
SaveCollectionStep.NameCollection -> {
|
|
|
|
actionEmitter.onNext(CollectionCreationAction.BackPressed(SaveCollectionStep.NameCollection))
|
|
|
|
}
|
2019-05-20 22:34:58 +02:00
|
|
|
SaveCollectionStep.RenameCollection -> {
|
|
|
|
actionEmitter.onNext(CollectionCreationAction.BackPressed(SaveCollectionStep.RenameCollection))
|
|
|
|
}
|
2019-04-30 00:52:55 +02:00
|
|
|
}
|
2019-05-16 23:12:56 +02:00
|
|
|
return true
|
|
|
|
} else {
|
|
|
|
return false
|
2019-04-30 00:52:55 +02:00
|
|
|
}
|
2019-04-23 00:07:03 +02:00
|
|
|
}
|
2019-04-24 01:30:51 +02:00
|
|
|
|
|
|
|
companion object {
|
2019-05-02 17:53:40 +02:00
|
|
|
private const val TRANSITION_DURATION = 200L
|
2019-04-24 01:30:51 +02:00
|
|
|
private const val increaseButtonByDps = 16
|
|
|
|
}
|
2019-04-24 01:40:26 +02:00
|
|
|
}
|