-
Notifications
You must be signed in to change notification settings - Fork 17
/
ListExampleInteractor.kt
141 lines (131 loc) · 6.66 KB
/
ListExampleInteractor.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
* Copyright (c) pakoito 2016
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.pacoworks.dereference.features.list
import com.pacoworks.dereference.architecture.ui.StateHolder
import com.pacoworks.dereference.core.functional.None
import com.pacoworks.dereference.features.list.model.EditMode
import com.pacoworks.dereference.features.list.model.createEditModeDelete
import com.pacoworks.dereference.features.list.model.createEditModeNormal
import com.pacoworks.rxcomprehensions.RxComprehensions.doFM
import com.pacoworks.rxcomprehensions.RxComprehensions.doSM
import com.pacoworks.rxtuples.RxTuples
import org.javatuples.Pair
import rx.Observable
import rx.Subscription
import rx.subscriptions.CompositeSubscription
import java.util.*
/**
* Binds the state of this use case to a [com.pacoworks.dereference.architecture.ui.BoundView]
*
* @see [com.pacoworks.dereference.architecture.ui.bind]
*/
fun bindListExample(viewInput: ListExampleInputView, state: ListExampleState) {
viewInput.createBinder<List<String>>().call(state.elements, { viewInput.updateElements(it) })
viewInput.createBinder<Set<String>>().call(state.selected, { viewInput.updateSelected(it) })
viewInput.createBinder<EditMode>().call(state.editMode, { viewInput.updateEditMode(it) })
}
/**
* Subscribes all use cases in the file
*/
fun subscribeListExampleInteractor(viewOutput: ListExampleOutputView, state: ListExampleState): Subscription =
CompositeSubscription(
handleAdd(state.elements, viewOutput.addClick()),
handleEnterEditState(viewOutput.listLongClicks(), state.editMode),
handleExitEditState(viewOutput.deleteClick(), state.editMode),
handleOnCommitDelete(state.editMode, state.elements, state.selected),
/* FIXME: Must be after handleOnCommitDelete to assure that selections are not cleared before they're deleted */
handleOnSwitchEditState(state.editMode, state.selected),
handleSelect(state.editMode, state.selected, viewOutput.listClicks()))
fun handleAdd(elementsState: StateHolder<List<String>>, addClick: Observable<None>): Subscription =
doSM(
/* For the current list of elements */
{ elementsState },
/* When the user clicks add */
{ addClick.first() },
{ elements, click ->
/* Insert random number at end of the list */
Observable.just(elements.plus((Math.abs(Random().nextInt()) + elements.size).toString()))
}
)
.subscribe(elementsState)
fun handleEnterEditState(listLongClicks: Observable<Pair<Int, String>>, editMode: StateHolder<EditMode>): Subscription =
doFM(
/* When the user clicks on the list with a long press */
{ listLongClicks },
/* And the mode is not edit */
{ editMode.first() },
{ click, editMode ->
editMode.join(
/* Push edit mode with the position pressed */
{ normal -> Observable.just(createEditModeDelete(click.value1)) },
/* Else ignore */
{ delete -> Observable.empty<EditMode>() }) }
).subscribe(editMode)
fun handleExitEditState(deleteClick: Observable<None>, editMode: StateHolder<EditMode>): Subscription =
doFM(
/* When the user clicks onthe delete button*/
{ deleteClick },
/* And the mode is editing */
{ editMode.first() },
{ click, editMode ->
editMode.join(
/* Ignore not editing */
{ normal -> Observable.empty<EditMode>() },
/* Push exiting edit mode */
{ delete -> Observable.just(createEditModeNormal()) })
}
).subscribe(editMode)
fun handleOnSwitchEditState(editMode: StateHolder<EditMode>, selected: StateHolder<Set<String>>): Subscription =
/* When edit mode changes */
editMode
.map { it.join(
/* If exiting delete mode, remove elements from selected */
{ normal -> setOf<String>() },
/* If entering delete mode, add the long pressed value element to selected */
{ delete -> setOf(delete.id) }) }
.subscribe(selected)
fun handleOnCommitDelete(editMode: StateHolder<EditMode>, elementsState: StateHolder<List<String>>, selected: StateHolder<Set<String>>): Subscription =
doSM(
/* When the mode changes from delete to normal */
{ editMode.filter { it.join({ normal -> true }, { delete -> false }) } },
/* Get all elements, and the set of selected ones */
{ Observable.zip(elementsState, selected, RxTuples.toPair<List<String>, Set<String>>()).first() },
/* Delete selected elements */
{ exitEditMode, statePair ->
Observable.from(statePair.value0).filter { !statePair.value1.contains(it) }.toList()
}
)
.subscribe(elementsState)
fun handleSelect(editMode: StateHolder<EditMode>, selected: StateHolder<Set<String>>, listClicks: Observable<Pair<Int, String>>): Subscription =
/* When the edit mode is delete */
editMode.
switchMap {
it.join(
/* Ignore clicks if not editing */
{ normal -> Observable.empty<String>() },
/* Else pass them through */
{ delete -> listClicks.map { it.value1 } })
}
.flatMap { value ->
/* Add or remove the clicked from the selected list */
selected.first().map {
if (it.contains(value)) {
it.minus(value)
} else {
it.plus(value)
}
}
}.subscribe(selected)