Skip to content

Commit

Permalink
Introduce StoreModel.
Browse files Browse the repository at this point in the history
  • Loading branch information
pardom committed Aug 2, 2016
1 parent a1cf860 commit 6563169
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 134 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,14 @@ class ItemDetailView : RelativeLayout, Store.Subscriber {
super.onAttachedToWindow()

toolbar.navigationClicks()
.subscribe { model.store.dispatch(Action.GoBack()) }
.subscribe { model.dispatch(Action.GoBack()) }
.addTo(subscriptions)

toolbar.itemClicks().filter { it.itemId == R.id.item_share }
.subscribe { model.store.dispatch(Action.Share()) }
.subscribe { model.dispatch(Action.Share()) }
.addTo(subscriptions)

subscription = model.store.subscribe(this)
subscription = model.subscribe(this)
onStateChanged()
}

Expand All @@ -91,7 +91,7 @@ class ItemDetailView : RelativeLayout, Store.Subscriber {
}

override fun onStateChanged() {
val state = model.store.getState()
val state = model.getState()
toolbar.title = state.item.title
titleTextView.text = state.item.title
adapter.setItems(state.children)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ class ItemListView : RecyclerView, Store.Subscriber {
override fun onFinishInflate() {
super.onFinishInflate()

adapter.itemUrlClickListener = { model.store.dispatch(Action.GoToUrl(it)) }
adapter.itemDetailClickListener = { model.store.dispatch(Action.GoToDetail(it)) }
adapter.itemUrlClickListener = { model.dispatch(Action.GoToUrl(it)) }
adapter.itemDetailClickListener = { model.dispatch(Action.GoToDetail(it)) }

setAdapter(adapter)
}

override fun onAttachedToWindow() {
super.onAttachedToWindow()
subscription = model.store.subscribe(this)
subscription = model.subscribe(this)
onStateChanged()
}

Expand All @@ -54,7 +54,7 @@ class ItemListView : RecyclerView, Store.Subscriber {
}

override fun onStateChanged() {
val state = model.store.getState()
val state = model.getState()
adapter.setItems(state.items)
}

Expand Down
10 changes: 5 additions & 5 deletions android/src/main/kotlin/clean/news/ui/item/url/ItemUrlView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -59,22 +59,22 @@ class ItemUrlView : RelativeLayout, Store.Subscriber {
super.onAttachedToWindow()

toolbar.navigationClicks()
.subscribe { model.store.dispatch(Action.GoBack()) }
.subscribe { model.dispatch(Action.GoBack()) }
.addTo(subscriptions)

val toolbarItemClicks = toolbar.itemClicks()
.publish()
.autoConnect()

toolbarItemClicks.filter { it.itemId == R.id.item_details }
.subscribe { model.store.dispatch(Action.GoToDetails()) }
.subscribe { model.dispatch(Action.GoToDetails()) }
.addTo(subscriptions)

toolbarItemClicks.filter { it.itemId == R.id.item_share }
.subscribe { model.store.dispatch(Action.Share()) }
.subscribe { model.dispatch(Action.Share()) }
.addTo(subscriptions)

subscription = model.store.subscribe(this)
subscription = model.subscribe(this)
onStateChanged()
}

Expand All @@ -85,7 +85,7 @@ class ItemUrlView : RelativeLayout, Store.Subscriber {
}

override fun onStateChanged() {
val state = model.store.getState()
val state = model.getState()
val item = state.item

toolbar.menu.findItem(R.id.item_details).isVisible = item.type.canComment
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package clean.news.presentation.model

import redux.Reducer
import redux.Store
import redux.Store.Subscriber

abstract class StoreModel<S : Any> : Store<S> {

private val store by lazy { createStore() }

abstract fun createStore(): Store<S>

override fun getState() = store.getState()

override fun replaceReducer(reducer: Reducer<S>) = store.replaceReducer(reducer)

override fun subscribe(subscriber: Subscriber) = store.subscribe(subscriber)

override fun dispatch(action: Any) = store.dispatch(action)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package clean.news.presentation.model.item
import clean.news.app.usecase.item.GetChildren
import clean.news.core.entity.Item
import clean.news.presentation.inject.ScreenScope
import clean.news.presentation.model.StoreModel
import clean.news.presentation.model.item.ItemDetailViewModel.Action.GoBack
import clean.news.presentation.model.item.ItemDetailViewModel.Action.GoToUrl
import clean.news.presentation.model.item.ItemDetailViewModel.Action.Share
import clean.news.presentation.model.item.ItemDetailViewModel.Action.ShowChildren
import clean.news.presentation.model.item.ItemDetailViewModel.State
import clean.news.presentation.navigation.NavigationFactory
import clean.news.presentation.navigation.NavigationFactory.ItemDetailScreen
import clean.news.presentation.navigation.NavigationService
Expand All @@ -29,7 +31,7 @@ class ItemDetailViewModel @Inject constructor(
private val navService: NavigationService,
private val navFactory: NavigationFactory,
private val getChildren: GetChildren,
item: Item) {
private val item: Item) : StoreModel<State>() {

// State

Expand All @@ -48,66 +50,66 @@ class ItemDetailViewModel @Inject constructor(
class Share() : Action()
}

// Reducer
override fun createStore(): Store<State> {
// Reducer

private val reducer = object : Reducer<State> {
override fun reduce(state: State, action: Any): State {
return when (action) {
is ShowChildren -> state.copy(children = action.children)
else -> state
val reducer = object : Reducer<State> {
override fun reduce(state: State, action: Any): State {
return when (action) {
is ShowChildren -> state.copy(children = action.children)
else -> state
}
}
}
}

// Middleware
// Middleware

private val logger = object : Logger<State> {
override fun log(event: Event, action: Any, state: State) {
val logger = object : Logger<State> {
override fun log(event: Event, action: Any, state: State) {
}
}
}
private val epic = object : Epic<State> {
override fun map(actions: Observable<out Any>, store: Store<State>): Observable<out Any> {
return actions.ofType(Action.GetChildren::class.java)
.flatMap {
getChildren.execute(GetChildren.Request(it.item))
.observeOn(observeScheduler)
}
.map { Action.ShowChildren(it.items) }
val epic = object : Epic<State> {
override fun map(actions: Observable<out Any>, store: Store<State>): Observable<out Any> {
return actions.ofType(Action.GetChildren::class.java)
.flatMap {
getChildren.execute(GetChildren.Request(it.item))
.observeOn(observeScheduler)
}
.map { Action.ShowChildren(it.items) }
}
}
}

private val loggerMiddleware = LoggerMiddleware.create(logger)
private val epicMiddleware = EpicMiddleware.create(epic)
private val navigationMiddleware = object : Middleware<State> {
override fun dispatch(store: Store<State>, action: Any, next: Dispatcher): Any {
when (action) {
is GoBack -> navService.goBack()
is GoToUrl -> navService.goTo(navFactory.url(item))
is Share -> navService.goTo(navFactory.shareDetail(item))
val loggerMiddleware = LoggerMiddleware.create(logger)
val epicMiddleware = EpicMiddleware.create(epic)
val navigationMiddleware = object : Middleware<State> {
override fun dispatch(store: Store<State>, action: Any, next: Dispatcher): Any {
when (action) {
is GoBack -> navService.goBack()
is GoToUrl -> navService.goTo(navFactory.url(item))
is Share -> navService.goTo(navFactory.shareDetail(item))
}
return action
}
return action

}

return Store.create(
reducer,
State(
item,
listOf(item),
false
),
Middleware.apply(
loggerMiddleware,
epicMiddleware,
navigationMiddleware
)
)
}

// Store

val store = Store.create(
reducer,
State(
item,
listOf(item),
false
),
Middleware.apply(
loggerMiddleware,
epicMiddleware,
navigationMiddleware
)
)

init {
store.dispatch(Action.GetChildren(item))
dispatch(Action.GetChildren(item))
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package clean.news.presentation.model.item

import clean.news.app.usecase.item.GetItemsByListType
import clean.news.core.entity.Item
import clean.news.presentation.model.StoreModel
import clean.news.presentation.model.item.ItemListViewModel.Action.GoToDetail
import clean.news.presentation.model.item.ItemListViewModel.Action.GoToUrl
import clean.news.presentation.model.item.ItemListViewModel.Action.ShowItems
import clean.news.presentation.model.item.ItemListViewModel.State
import clean.news.presentation.navigation.NavigationFactory
import clean.news.presentation.navigation.NavigationService
import redux.Dispatcher
Expand All @@ -25,7 +27,7 @@ class ItemListViewModel @Inject constructor(
private val navService: NavigationService,
private val navFactory: NavigationFactory,
private val listType: Item.ListType,
private val getItemsByListType: GetItemsByListType) {
private val getItemsByListType: GetItemsByListType) : StoreModel<State>() {

// State

Expand All @@ -42,63 +44,63 @@ class ItemListViewModel @Inject constructor(
class GoToUrl(val item: Item) : Action()
}

// Reducer
override fun createStore(): Store<State> {
// Reducer

private val reducer = object : Reducer<State> {
override fun reduce(state: State, action: Any): State {
return when (action) {
is ShowItems -> state.copy(items = action.items)
else -> state
val reducer = object : Reducer<State> {
override fun reduce(state: State, action: Any): State {
return when (action) {
is ShowItems -> state.copy(items = action.items)
else -> state
}
}
}
}

// Middleware
// Middleware

private val logger = object : Logger<State> {
override fun log(event: Event, action: Any, state: State) {
val logger = object : Logger<State> {
override fun log(event: Event, action: Any, state: State) {
}
}
}
private val epic = object : Epic<State> {
override fun map(actions: Observable<out Any>, store: Store<State>): Observable<out Any> {
return actions.ofType(Action.GetItems::class.java)
.flatMap {
getItemsByListType.execute(GetItemsByListType.Request(listType))
.observeOn(observeScheduler)
}
.map { Action.ShowItems(it.items) }
val epic = object : Epic<State> {
override fun map(actions: Observable<out Any>, store: Store<State>): Observable<out Any> {
return actions.ofType(Action.GetItems::class.java)
.flatMap {
getItemsByListType.execute(GetItemsByListType.Request(listType))
.observeOn(observeScheduler)
}
.map { Action.ShowItems(it.items) }
}
}
}

private val loggerMiddleware = LoggerMiddleware.create(logger)
private val epicMiddleware = EpicMiddleware.create(epic)
private val navigationMiddleware = object : Middleware<State> {
override fun dispatch(store: Store<State>, action: Any, next: Dispatcher): Any {
when (action) {
is GoToUrl -> navService.goTo(navFactory.url(action.item))
is GoToDetail -> navService.goTo(navFactory.detail(action.item))
val loggerMiddleware = LoggerMiddleware.create(logger)
val epicMiddleware = EpicMiddleware.create(epic)
val navigationMiddleware = object : Middleware<State> {
override fun dispatch(store: Store<State>, action: Any, next: Dispatcher): Any {
when (action) {
is GoToUrl -> navService.goTo(navFactory.url(action.item))
is GoToDetail -> navService.goTo(navFactory.detail(action.item))
}
return action
}
return action

}

return Store.create(
reducer,
State(
emptyList(),
false
),
Middleware.apply(
loggerMiddleware,
epicMiddleware,
navigationMiddleware
)
)
}

// Store

val store = Store.create(
reducer,
State(
emptyList(),
false
),
Middleware.apply(
loggerMiddleware,
epicMiddleware,
navigationMiddleware
)
)

init {
store.dispatch(Action.GetItems())
dispatch(Action.GetItems())
}
}
Loading

0 comments on commit 6563169

Please sign in to comment.