|
|
@ -5,12 +5,17 @@
|
|
|
|
package org.mozilla.fenix.library.bookmarks
|
|
|
|
package org.mozilla.fenix.library.bookmarks
|
|
|
|
|
|
|
|
|
|
|
|
import android.view.ViewGroup
|
|
|
|
import android.view.ViewGroup
|
|
|
|
|
|
|
|
import androidx.fragment.app.Fragment
|
|
|
|
|
|
|
|
import androidx.lifecycle.ViewModel
|
|
|
|
|
|
|
|
import androidx.lifecycle.ViewModelProvider
|
|
|
|
|
|
|
|
import io.reactivex.Observable
|
|
|
|
import mozilla.components.concept.storage.BookmarkNode
|
|
|
|
import mozilla.components.concept.storage.BookmarkNode
|
|
|
|
import org.mozilla.fenix.mvi.Action
|
|
|
|
import org.mozilla.fenix.mvi.Action
|
|
|
|
import org.mozilla.fenix.mvi.ActionBusFactory
|
|
|
|
import org.mozilla.fenix.mvi.ActionBusFactory
|
|
|
|
import org.mozilla.fenix.mvi.Change
|
|
|
|
import org.mozilla.fenix.mvi.Change
|
|
|
|
import org.mozilla.fenix.mvi.Reducer
|
|
|
|
import org.mozilla.fenix.mvi.Reducer
|
|
|
|
import org.mozilla.fenix.mvi.UIComponent
|
|
|
|
import org.mozilla.fenix.mvi.UIComponent
|
|
|
|
|
|
|
|
import org.mozilla.fenix.mvi.UIComponentViewModel
|
|
|
|
import org.mozilla.fenix.mvi.UIView
|
|
|
|
import org.mozilla.fenix.mvi.UIView
|
|
|
|
import org.mozilla.fenix.mvi.ViewState
|
|
|
|
import org.mozilla.fenix.mvi.ViewState
|
|
|
|
import org.mozilla.fenix.test.Mockable
|
|
|
|
import org.mozilla.fenix.test.Mockable
|
|
|
@ -18,51 +23,28 @@ import org.mozilla.fenix.test.Mockable
|
|
|
|
@Mockable
|
|
|
|
@Mockable
|
|
|
|
class BookmarkComponent(
|
|
|
|
class BookmarkComponent(
|
|
|
|
private val container: ViewGroup,
|
|
|
|
private val container: ViewGroup,
|
|
|
|
|
|
|
|
owner: Fragment,
|
|
|
|
bus: ActionBusFactory,
|
|
|
|
bus: ActionBusFactory,
|
|
|
|
override var initialState: BookmarkState =
|
|
|
|
override var initialState: BookmarkState =
|
|
|
|
BookmarkState(null, BookmarkState.Mode.Normal)
|
|
|
|
BookmarkState(null, BookmarkState.Mode.Normal)
|
|
|
|
) :
|
|
|
|
) :
|
|
|
|
UIComponent<BookmarkState, BookmarkAction, BookmarkChange>(
|
|
|
|
UIComponent<BookmarkState, BookmarkAction, BookmarkChange>(
|
|
|
|
|
|
|
|
owner,
|
|
|
|
bus.getManagedEmitter(BookmarkAction::class.java),
|
|
|
|
bus.getManagedEmitter(BookmarkAction::class.java),
|
|
|
|
bus.getSafeManagedObservable(BookmarkChange::class.java)
|
|
|
|
bus.getSafeManagedObservable(BookmarkChange::class.java)
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
|
|
|
|
|
|
|
|
override val reducer: Reducer<BookmarkState, BookmarkChange> = { state, change ->
|
|
|
|
|
|
|
|
when (change) {
|
|
|
|
|
|
|
|
is BookmarkChange.Change -> {
|
|
|
|
|
|
|
|
val mode =
|
|
|
|
|
|
|
|
if (state.mode is BookmarkState.Mode.Selecting) {
|
|
|
|
|
|
|
|
val items = state.mode.selectedItems.filter {
|
|
|
|
|
|
|
|
it in change.tree
|
|
|
|
|
|
|
|
}.toSet()
|
|
|
|
|
|
|
|
if (items.isEmpty()) BookmarkState.Mode.Normal else BookmarkState.Mode.Selecting(items)
|
|
|
|
|
|
|
|
} else state.mode
|
|
|
|
|
|
|
|
state.copy(tree = change.tree, mode = mode)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
is BookmarkChange.IsSelected -> {
|
|
|
|
|
|
|
|
val selectedItems = if (state.mode is BookmarkState.Mode.Selecting) {
|
|
|
|
|
|
|
|
state.mode.selectedItems + change.newlySelectedItem
|
|
|
|
|
|
|
|
} else setOf(change.newlySelectedItem)
|
|
|
|
|
|
|
|
state.copy(mode = BookmarkState.Mode.Selecting(selectedItems))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
is BookmarkChange.IsDeselected -> {
|
|
|
|
|
|
|
|
val selectedItems = if (state.mode is BookmarkState.Mode.Selecting) {
|
|
|
|
|
|
|
|
state.mode.selectedItems - change.newlyDeselectedItem
|
|
|
|
|
|
|
|
} else setOf()
|
|
|
|
|
|
|
|
val mode = if (selectedItems.isEmpty()) BookmarkState.Mode.Normal else BookmarkState.Mode.Selecting(
|
|
|
|
|
|
|
|
selectedItems
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
state.copy(mode = mode)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
is BookmarkChange.ClearSelection -> state.copy(mode = BookmarkState.Mode.Normal)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
override fun initView(): UIView<BookmarkState, BookmarkAction, BookmarkChange> =
|
|
|
|
override fun initView(): UIView<BookmarkState, BookmarkAction, BookmarkChange> =
|
|
|
|
BookmarkUIView(container, actionEmitter, changesObservable)
|
|
|
|
BookmarkUIView(container, actionEmitter, changesObservable)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
override fun render(): Observable<BookmarkState> {
|
|
|
|
|
|
|
|
return ViewModelProvider(
|
|
|
|
|
|
|
|
owner,
|
|
|
|
|
|
|
|
BookmarkViewModel.Factory(initialState, changesObservable)
|
|
|
|
|
|
|
|
).get(BookmarkViewModel::class.java).render(uiView)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
init {
|
|
|
|
init {
|
|
|
|
render(reducer)
|
|
|
|
render()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -98,3 +80,49 @@ sealed class BookmarkChange : Change {
|
|
|
|
operator fun BookmarkNode.contains(item: BookmarkNode): Boolean {
|
|
|
|
operator fun BookmarkNode.contains(item: BookmarkNode): Boolean {
|
|
|
|
return children?.contains(item) ?: false
|
|
|
|
return children?.contains(item) ?: false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BookmarkViewModel(initialState: BookmarkState, changesObservable: Observable<BookmarkChange>) :
|
|
|
|
|
|
|
|
UIComponentViewModel<BookmarkState, BookmarkAction, BookmarkChange>(initialState, changesObservable, reducer) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Factory(
|
|
|
|
|
|
|
|
private val initialState: BookmarkState,
|
|
|
|
|
|
|
|
private val changesObservable: Observable<BookmarkChange>
|
|
|
|
|
|
|
|
) : ViewModelProvider.Factory {
|
|
|
|
|
|
|
|
@Suppress("UNCHECKED_CAST")
|
|
|
|
|
|
|
|
override fun <T : ViewModel?> create(modelClass: Class<T>): T =
|
|
|
|
|
|
|
|
BookmarkViewModel(initialState, changesObservable) as T
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
|
|
|
|
val reducer: Reducer<BookmarkState, BookmarkChange> = { state, change ->
|
|
|
|
|
|
|
|
when (change) {
|
|
|
|
|
|
|
|
is BookmarkChange.Change -> {
|
|
|
|
|
|
|
|
val mode =
|
|
|
|
|
|
|
|
if (state.mode is BookmarkState.Mode.Selecting) {
|
|
|
|
|
|
|
|
val items = state.mode.selectedItems.filter {
|
|
|
|
|
|
|
|
it in change.tree
|
|
|
|
|
|
|
|
}.toSet()
|
|
|
|
|
|
|
|
if (items.isEmpty()) BookmarkState.Mode.Normal else BookmarkState.Mode.Selecting(items)
|
|
|
|
|
|
|
|
} else state.mode
|
|
|
|
|
|
|
|
state.copy(tree = change.tree, mode = mode)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
is BookmarkChange.IsSelected -> {
|
|
|
|
|
|
|
|
val selectedItems = if (state.mode is BookmarkState.Mode.Selecting) {
|
|
|
|
|
|
|
|
state.mode.selectedItems + change.newlySelectedItem
|
|
|
|
|
|
|
|
} else setOf(change.newlySelectedItem)
|
|
|
|
|
|
|
|
state.copy(mode = BookmarkState.Mode.Selecting(selectedItems))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
is BookmarkChange.IsDeselected -> {
|
|
|
|
|
|
|
|
val selectedItems = if (state.mode is BookmarkState.Mode.Selecting) {
|
|
|
|
|
|
|
|
state.mode.selectedItems - change.newlyDeselectedItem
|
|
|
|
|
|
|
|
} else setOf()
|
|
|
|
|
|
|
|
val mode = if (selectedItems.isEmpty()) BookmarkState.Mode.Normal else BookmarkState.Mode.Selecting(
|
|
|
|
|
|
|
|
selectedItems
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
state.copy(mode = mode)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
is BookmarkChange.ClearSelection -> state.copy(mode = BookmarkState.Mode.Normal)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|