Skip to content

Commit 9cc84aa

Browse files
author
Patrick Jackson
committed
create viewUpdater types and functions. before refactor of presenter classes to functions
1 parent 09ad3ba commit 9cc84aa

File tree

3 files changed

+163
-29
lines changed

3 files changed

+163
-29
lines changed

common/src/commonMain/kotlin/com/willowtreeapps/common/builders.kt

Lines changed: 124 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
package com.willowtreeapps.common
22

3+
import com.willowtreeapps.common.ui.SearchView
4+
import com.willowtreeapps.common.ui.View
35
import com.willowtreeapps.common.ui.ViewUpdater
6+
import com.willowtreeapps.common.ui.ViewUpdaterBuilder
47
import org.reduxkotlin.Store
58
import org.reduxkotlin.StoreSubscriber
9+
import org.reduxkotlin.compose
10+
import org.reduxkotlin.createStore
11+
import kotlin.reflect.KClass
12+
import kotlin.reflect.KProperty1
613

714
class SelectorSubscriberBuilder<S : Any, View>(val store: Store) {
15+
//available to lambda with receiver in DSL
816
val state: S
917
get() = store.getState() as S
1018

@@ -15,20 +23,13 @@ class SelectorSubscriberBuilder<S : Any, View>(val store: Store) {
1523
}
1624

1725
val selectorList = mutableMapOf<Selector<S, Any>, (Any) -> Unit>()
18-
val updaterList = mutableMapOf<Selector<S, Any>, Any>()
1926

2027
fun withSingleField(selector: (S) -> Any, action: (Any) -> Unit) {
2128
val selBuilder = SelectorBuilder<S>()
2229
val sel = selBuilder.withSingleField(selector)
2330
selectorList[sel] = action
2431
}
2532

26-
fun withSingleField2(selector: (S) -> Any, action: View.()-> Unit) {
27-
val selBuilder = SelectorBuilder<S>()
28-
val sel = selBuilder.withSingleField(selector)
29-
updaterList[sel] = action
30-
}
31-
3233
infix operator fun SelectorSubscriberBuilder<S, View>.plus(selector: (S) -> Any): AbstractSelector<S, Any> {
3334
val selBuilder = SelectorBuilder<S>()
3435
val sel = selBuilder.withSingleField(selector)
@@ -59,6 +60,7 @@ class SelectorSubscriberBuilder<S : Any, View>(val store: Store) {
5960
* }
6061
*/
6162
fun <S : Any, View> SelectorSubscriberFn(store: Store, selectorSubscriberBuilderInit: SelectorSubscriberBuilder<S, View>.() -> Unit): StoreSubscriber {
63+
6264
val subBuilder = SelectorSubscriberBuilder<S, View>(store)
6365
subBuilder.selectorSubscriberBuilderInit()
6466
return {
@@ -68,3 +70,118 @@ fun <S : Any, View> SelectorSubscriberFn(store: Store, selectorSubscriberBuilder
6870
subBuilder.withAnyChangeFun?.invoke()
6971
}
7072
}
73+
74+
//Class that handles state management of selectors globally. All Subscribed selectors will share
75+
//a selector map and multiple selectors matching selectors will be updated. i.e.
76+
// val selectFoo: SelectorSubscriber = {{ select{it.loading}+{}
77+
// val selectBar: SelectorSubscriber = {{ select{it.loading}+{}
78+
// This class will notify both
79+
class SharedSelector<S : Any, View> {
80+
private val selectorList = mutableMapOf<Selector<S, Any>, (Any) -> Unit>()
81+
82+
fun withSingleField(selector: (S) -> Any, action: (Any) -> Unit) {
83+
val selBuilder = SelectorBuilder<S>()
84+
val sel = selBuilder.withSingleField(selector)
85+
selectorList[sel] = action
86+
}
87+
88+
infix operator fun SelectorSubscriberBuilder<S, View>.plus(selector: (S) -> Any): AbstractSelector<S, Any> {
89+
val selBuilder = SelectorBuilder<S>()
90+
val sel = selBuilder.withSingleField(selector)
91+
return sel
92+
}
93+
94+
infix operator fun AbstractSelector<S, Any>.plus(action: (Any) -> Unit) {
95+
selectorList[this] = action
96+
}
97+
98+
infix operator fun AbstractSelector<S, Any>.invoke(action: (Any) -> Unit) {
99+
selectorList[this] = action
100+
}
101+
}
102+
103+
typealias SelectorSubscriber<State, View> = SelectorSubscriberBuilder<State, View>.() -> View.() -> Unit
104+
105+
typealias SelectorSubscriberB<State, View> = View.() -> (SelectorSubscriberBuilder<State, View>.() -> Unit)
106+
typealias SelectorSubscriberC<State, View> = View.() -> (Store) -> (SelectorSubscriberBuilder<State, View>.() -> Unit)
107+
typealias SelectorSubscriberD<State, View> = View.() -> (Store) -> StoreSubscriber
108+
109+
typealias MySelectorSubscriber<View> = SelectorSubscriber<AppState, View>
110+
111+
//experimental selector using KProps
112+
operator fun KProperty1<AppState, Boolean>.get(pos: Int) {
113+
114+
}
115+
116+
val searchPresenterSubscriber: MySelectorSubscriber<SearchView> =
117+
{
118+
{
119+
plus { AppState::isLoadingItems[0] } + { showLoading() }
120+
plus { it.isLoadingItems } + { showLoading() }
121+
withSingleField({ it.isLoadingItems }) { showLoading() }
122+
}
123+
}
124+
125+
val searchPresenterSubscriberB: SelectorSubscriberB<AppState, SearchView> = {
126+
{
127+
plus { AppState::isLoadingItems[0] } + { showLoading() }
128+
plus { it.isLoadingItems } + { showLoading() }
129+
}
130+
}
131+
132+
133+
val searchPresenterSubscriberC: SelectorSubscriberC<AppState, SearchView> = {
134+
{ store ->
135+
{
136+
plus { AppState::isLoadingItems[0] } + { showLoading() }
137+
plus { it.isLoadingItems } + { showLoading() }
138+
}
139+
}
140+
}
141+
142+
fun <State : Any, View> selectFun(store: Store, actions: (SelectorSubscriberBuilder<State, View>.() -> Unit)): StoreSubscriber {
143+
val sel = SelectorSubscriberFn<State, View>(store, actions)
144+
return sel
145+
}
146+
147+
fun <State : Any, View> viewUpdater(actions: ViewUpdaterBuilder<State, View>): ViewUpdater<View> {
148+
return { view: View ->
149+
{ store: Store ->
150+
val actions2 = actions(view)//(store)
151+
val sel = SelectorSubscriberFn(store, actions2)
152+
sel
153+
}
154+
}
155+
}
156+
157+
val searchPresenterSubscriberD: SelectorSubscriberD<AppState, SearchView> = {
158+
{ store ->
159+
SelectorSubscriberFn<AppState, SearchView>(store) {
160+
plus { AppState::isLoadingItems[0] } + { showLoading() }
161+
plus { it.isLoadingItems } + { showLoading() }
162+
}//(store)
163+
}
164+
}
165+
val searchPresenterSubscriberD2: SelectorSubscriberD<AppState, SearchView> = {
166+
{
167+
selectFun<AppState, SearchView>(it) {
168+
plus { AppState::isLoadingItems[0] } + { showLoading() }
169+
plus { it.isLoadingItems } + { showLoading() }
170+
}//(store)
171+
}
172+
}
173+
val searchPresenterSubscriberD3 = viewUpdater<AppState, SearchView> {
174+
{
175+
plus { it.isLoadingItems } + { showLoading() }
176+
}
177+
}
178+
179+
fun test(view: SearchView) {
180+
val store = createStore()
181+
searchPresenterSubscriber(SelectorSubscriberBuilder(store))(view)
182+
searchPresenterSubscriberB(view)(SelectorSubscriberBuilder(store))
183+
val subscriber = searchPresenterSubscriberC(view)(store)
184+
val subscriberD = searchPresenterSubscriberD(view)(store)
185+
val subscriberD2 = searchPresenterSubscriberD2(view)(store)
186+
val subscriberD3 = searchPresenterSubscriberD3(view)(store)
187+
}

common/src/commonMain/kotlin/com/willowtreeapps/common/ui/PresenterFactory.kt

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -108,25 +108,8 @@ interface SingletonPresenterView<TPresenter>: View<TPresenter> {
108108
}
109109

110110
abstract class Presenter<T : View<*>?> {
111-
var view: T? = null
112111
private var subscriber: StoreSubscriber? = null
113112

114-
fun isAttached() = view != null
115-
116-
open fun attachView(view: T) {
117-
Logger.d("Presenter attachView: $view", Logger.Category.LIFECYCLE)
118-
if (subscriber == null) {
119-
subscriber = makeSubscriber()
120-
}
121-
this.view = view
122-
}
123-
124-
fun detachView(view: T) {
125-
Logger.d("Presenter DetachView: $view", Logger.Category.LIFECYCLE)
126-
if (this.view == view) {
127-
this.view = null
128-
}
129-
}
130113

131114
/**
132115
* @return a StoreSubscriber for the presenter

common/src/commonMain/kotlin/com/willowtreeapps/common/ui/SearchPresenter.kt

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ package com.willowtreeapps.common.ui
33
import com.willowtreeapps.common.*
44
import com.willowtreeapps.common.boundary.toBookListViewState
55
import com.willowtreeapps.common.SelectorSubscriberFn
6+
import org.reduxkotlin.Store
7+
import org.reduxkotlin.StoreSubscriber
68

7-
typealias ViewUpdater<V> = (view: V) -> Unit
9+
typealias ViewUpdater<View> = (View) -> (Store) -> StoreSubscriber
10+
typealias ViewUpdaterBuilder<State, View> = ((View.() -> ((SelectorSubscriberBuilder<State, View>.() -> Unit))))
811

912
class SearchPresenter(private val engine: LibraryApp,
1013
private val networkThunks: NetworkThunks) : Presenter<SearchView>() {
@@ -14,7 +17,7 @@ class SearchPresenter(private val engine: LibraryApp,
1417
}
1518

1619
override fun makeSubscriber() = SelectorSubscriberFn<AppState, SearchView>(engine.appStore) {
17-
this+{it} + {}
20+
this+{it} + { }
1821
plus{}() { }
1922

2023
plus{ it.isLoadingItems} + {
@@ -25,9 +28,6 @@ class SearchPresenter(private val engine: LibraryApp,
2528
}
2629
}
2730

28-
withSingleField2({it.isLoadingItems}) {
29-
showResults(state.searchBooks.toBookListViewState())
30-
}
3131

3232
withSingleField({ it.isLoadingItems }) {
3333
if (state.isLoadingItems) {
@@ -49,4 +49,38 @@ class SearchPresenter(private val engine: LibraryApp,
4949
fun onTextChanged(query: String) {
5050
engine.dispatch(networkThunks.fetchBooks(query))
5151
}
52+
}
53+
fun <View> presenter(actions: ViewUpdaterBuilder<AppState,View>): ViewUpdater<View> {
54+
return viewUpdater(actions)
55+
}
56+
57+
val searchPresenter = presenter<SearchView> {
58+
{
59+
this+{it} + { }
60+
plus{}() { }
61+
62+
plus{ it.isLoadingItems} + {
63+
if (state.isLoadingItems) {
64+
showLoading()
65+
} else {
66+
hideLoading()
67+
}
68+
}
69+
70+
withSingleField({ it.isLoadingItems }) {
71+
if (state.isLoadingItems) {
72+
showLoading()
73+
} else {
74+
hideLoading()
75+
}
76+
}
77+
78+
withSingleField({ it.errorLoadingItems }) {
79+
showError(state.errorMsg)
80+
}
81+
82+
withSingleField({it.searchBooks}) {
83+
showResults(state.searchBooks.toBookListViewState())
84+
}
85+
}
5286
}

0 commit comments

Comments
 (0)