Skip to content

Commit

Permalink
refactor handlers to match option
Browse files Browse the repository at this point in the history
  • Loading branch information
stslex committed Dec 14, 2024
1 parent 1bfba22 commit 5ea63d9
Show file tree
Hide file tree
Showing 14 changed files with 93 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,32 @@ import org.koin.core.definition.BeanDefinition
import org.koin.core.definition.KoinDefinition
import org.koin.core.module.Module

inline fun <reified R : BaseStore<*, *, *>> Module.storeOf(
inline fun <reified R : BaseStore<*, *, *, *>> Module.storeOf(
crossinline constructor: () -> R,
noinline options: (BeanDefinition<R>.() -> Unit)? = null,
): KoinDefinition<R> = viewModelOf(constructor, options)

inline fun <reified R : BaseStore<*, *, *>, reified T1> Module.storeOf(
inline fun <reified R : BaseStore<*, *, *, *>, reified T1> Module.storeOf(
crossinline constructor: (T1) -> R,
noinline options: (BeanDefinition<R>.() -> Unit)? = null,
): KoinDefinition<R> = viewModelOf(constructor, options)

inline fun <reified R : BaseStore<*, *, *>, reified T1, reified T2> Module.storeOf(
inline fun <reified R : BaseStore<*, *, *, *>, reified T1, reified T2> Module.storeOf(
crossinline constructor: (T1, T2) -> R,
noinline options: (BeanDefinition<R>.() -> Unit)? = null,
): KoinDefinition<R> = viewModelOf(constructor, options)

inline fun <reified R : BaseStore<*, *, *>, reified T1, reified T2, reified T3> Module.storeOf(
inline fun <reified R : BaseStore<*, *, *, *>, reified T1, reified T2, reified T3> Module.storeOf(
crossinline constructor: (T1, T2, T3) -> R,
noinline options: (BeanDefinition<R>.() -> Unit)? = null,
): KoinDefinition<R> = viewModelOf(constructor, options)

inline fun <reified R : BaseStore<*, *, *>, reified T1, reified T2, reified T3, reified T4> Module.storeOf(
inline fun <reified R : BaseStore<*, *, *, *>, reified T1, reified T2, reified T3, reified T4> Module.storeOf(
crossinline constructor: (T1, T2, T3, T4) -> R,
noinline options: (BeanDefinition<R>.() -> Unit)? = null,
): KoinDefinition<R> = viewModelOf(constructor, options)

inline fun <reified R : BaseStore<*, *, *>, reified T1, reified T2, reified T3, reified T4, reified T5> Module.storeOf(
inline fun <reified R : BaseStore<*, *, *, *>, reified T1, reified T2, reified T3, reified T4, reified T5> Module.storeOf(
crossinline constructor: (T1, T2, T3, T4, T5) -> R,
noinline options: (BeanDefinition<R>.() -> Unit)? = null,
): KoinDefinition<R> = viewModelOf(constructor, options)
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

open class BaseStore<S : State, A : Action, E : Event>(
open class BaseStore<S : State, A : Action, E : Event, HStore : HandlerStore<S, A, E>>(
initialState: S,
private val handlers: Set<Handler<S, *, E, A>>
private val handlerCreator: HandlerCreator<S, A, E, HStore>,
) : ViewModel(), Store<S, A, E>, HandlerStore<S, A, E> {

private val _event: MutableSharedFlow<E> = MutableSharedFlow()
Expand All @@ -44,9 +44,8 @@ open class BaseStore<S : State, A : Action, E : Event>(
if (lastAction != action && action !is Action.RepeatLast) {
_lastAction = action
}
val handler = handlers.firstOrNull { it.checkAction(action) } as? Handler<S, A, E, A>
?: throw IllegalStateException("Handler not found for action: ${action::class.simpleName}")
handler.invoke(this, action)
val handler = handlerCreator(action) as Handler<A, HStore>
handler.invoke(this as HStore, action)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import com.stslex.wizard.core.ui.mvi.Store.Action
import com.stslex.wizard.core.ui.mvi.Store.Event
import com.stslex.wizard.core.ui.mvi.Store.State

internal class BaseStoreImpl<S : State, A : Action, E : Event>(
internal class BaseStoreImpl<S : State, A : Action, E : Event, HStore : HandlerStore<S, A, E>>(
initialState: S,
handlers: Set<Handler<S, *, E, A>>
) : BaseStore<S, A, E>(
handlerCreator: HandlerCreator<S, A, E, HStore>,
) : BaseStore<S, A, E, HStore>(
initialState = initialState,
handlers = handlers
handlerCreator = handlerCreator
)
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
package com.stslex.wizard.core.ui.mvi.v2

import com.stslex.wizard.core.ui.mvi.Store.Action
import com.stslex.wizard.core.ui.mvi.Store.Event
import com.stslex.wizard.core.ui.mvi.Store.State
import kotlin.reflect.KClass

abstract class Handler<S : State, A : StoreAction, E : Event, StoreAction : Action>(val actionKClass: KClass<*>) {
fun interface Handler<A : Action, TStore : HandlerStore<*, *, *>> {

inline fun checkAction(action: StoreAction): Boolean = actionKClass.isInstance(action)

abstract fun HandlerStore<S, StoreAction, E>.invoke(action: A)
fun TStore.invoke(action: A)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.stslex.wizard.core.ui.mvi.v2

import com.stslex.wizard.core.ui.mvi.Store.Action
import com.stslex.wizard.core.ui.mvi.Store.Event
import com.stslex.wizard.core.ui.mvi.Store.State

fun interface HandlerCreator<S : State, A : Action, E : Event, HStore : HandlerStore<S, A, E>> {

operator fun invoke(action: A): Handler<*, HStore>
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,20 @@ import com.stslex.wizard.core.ui.mvi.Store.Event
import com.stslex.wizard.core.ui.mvi.Store.State

@Suppress("UNCHECKED_CAST")
fun <S : State, A : Action, E : Event, TStore : Store<S, A, E>> store(
fun <S : State, A : Action, E : Event, TStore : Store<S, A, E>, HStore : HandlerStore<S, A, E>> store(
initialState: S,
handlers: Set<Handler<S, *, E, A>>
): TStore = BaseStoreImpl(initialState, handlers) as TStore
handlerCreator: HandlerCreator<S, A, E, HStore>
): TStore = BaseStoreImpl(initialState, handlerCreator) as TStore

fun <S : State, A : StoreAction, E : Event, StoreAction : Action> Handler<S, A, E, StoreAction>.invoke(
store: HandlerStore<S, StoreAction, E>,
fun <S : State, A : Action, E : Event, HStore : HandlerStore<S, A, E>> Handler<A, HStore>.invoke(
store: HStore,
action: A
) {
with(store) {
this.invoke(action)
}
}

inline fun <S : State, reified A : StoreAction, E : Event, StoreAction : Action> handler(
crossinline block: HandlerStore<S, StoreAction, E>.(action: A) -> Unit
) = object : Handler<S, A, E, StoreAction>(A::class) {

override fun HandlerStore<S, StoreAction, E>.invoke(action: A) {
block(action)
}
}
inline fun <S : State, A : Action, E : Event, HStore : HandlerStore<S, A, E>> handler(
crossinline block: HandlerStore<S, A, E>.(action: A) -> Unit
) = Handler<A, HStore> { block(it) }
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import com.stslex.wizard.feature.profile.data.repository.ProfileRepository
import com.stslex.wizard.feature.profile.data.repository.ProfileRepositoryImpl
import com.stslex.wizard.feature.profile.domain.interactor.ProfileInteractor
import com.stslex.wizard.feature.profile.domain.interactor.ProfileInteractorImpl
import com.stslex.wizard.feature.profile.mvi.ClickersHandler
import com.stslex.wizard.feature.profile.mvi.InitStorageHandler
import com.stslex.wizard.feature.profile.mvi.LogoutHandler
import com.stslex.wizard.feature.profile.mvi.NavigationHandler
import com.stslex.wizard.feature.profile.mvi.RepeatLastActionHandler
import com.stslex.wizard.feature.profile.ui.store.ProfileStore
import com.stslex.wizard.feature.profile.ui.store.ProfileStoreImpl
import org.koin.core.annotation.Module
Expand All @@ -17,7 +22,14 @@ import org.koin.dsl.ModuleDeclaration
class ModuleFeatureProfile : AppModule() {

override fun declaration(): ModuleDeclaration = {
factoryOf(::InitStorageHandler)
factoryOf(::LogoutHandler)
factoryOf(::RepeatLastActionHandler)
factoryOf(::ClickersHandler)
factoryOf(::NavigationHandler)

storeOf(::ProfileStoreImpl) { bind<ProfileStore>() }

factoryOf(::ProfileInteractorImpl) { bind<ProfileInteractor>() }
factoryOf(::ProfileRepositoryImpl) { bind<ProfileRepository>() }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
package com.stslex.wizard.feature.profile.mvi

import com.stslex.wizard.core.ui.mvi.v2.Handler
import com.stslex.wizard.core.ui.mvi.v2.handler
import com.stslex.wizard.feature.profile.ui.store.ProfileHandlerStore
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.Action
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.Action.Click
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.Event
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.State

fun clickersHandler(): Handler<State, Click, Event, Action> = handler { action ->
when (action) {
Click.BackButtonClick -> sendAction(Action.Navigation.Back)
Click.FavouriteClick -> sendAction(Action.Navigation.Favourite(state.value.uuid))
Click.FollowersClick -> sendAction(Action.Navigation.Followers(state.value.uuid))
Click.FollowingClick -> sendAction(Action.Navigation.Following(state.value.uuid))
Click.SettingsClick -> sendAction(Action.Navigation.Settings)
class ClickersHandler : Handler<Action.Click, ProfileHandlerStore> {

override fun ProfileHandlerStore.invoke(action: Action.Click) {
when (action) {
Action.Click.BackButtonClick -> sendAction(Action.Navigation.Back)
Action.Click.FavouriteClick -> sendAction(Action.Navigation.Favourite(state.value.uuid))
Action.Click.FollowersClick -> sendAction(Action.Navigation.Followers(state.value.uuid))
Action.Click.FollowingClick -> sendAction(Action.Navigation.Following(state.value.uuid))
Action.Click.SettingsClick -> sendAction(Action.Navigation.Settings)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,19 @@ import androidx.compose.ui.graphics.Color
import com.stslex.wizard.core.database.store.UserStore
import com.stslex.wizard.core.navigation.Screen
import com.stslex.wizard.core.ui.mvi.v2.Handler
import com.stslex.wizard.core.ui.mvi.v2.HandlerStore
import com.stslex.wizard.feature.profile.domain.interactor.ProfileInteractor
import com.stslex.wizard.feature.profile.ui.model.ProfileAvatarModel
import com.stslex.wizard.feature.profile.ui.model.toUi
import com.stslex.wizard.feature.profile.ui.store.ProfileHandlerStore
import com.stslex.wizard.feature.profile.ui.store.ProfileScreenState
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.Action
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.Action.Init
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.Event
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.State

class InitStorageHandler(
private val interactor: ProfileInteractor,
private val userStore: UserStore,
) : Handler<State, Init, Event, Action>(Init::class) {
) : Handler<Action.Init, ProfileHandlerStore> {

override fun HandlerStore<State, Action, Event>.invoke(action: Init) {
override fun ProfileHandlerStore.invoke(action: Action.Init) {
val uuid = action.uuid.ifBlank { userStore.uuid }

updateState { currentState ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,17 @@ package com.stslex.wizard.feature.profile.mvi

import com.stslex.wizard.core.ui.mvi.CommonEvents.Snackbar
import com.stslex.wizard.core.ui.mvi.v2.Handler
import com.stslex.wizard.core.ui.mvi.v2.HandlerStore
import com.stslex.wizard.feature.profile.domain.interactor.ProfileInteractor
import com.stslex.wizard.feature.profile.ui.store.ProfileHandlerStore
import com.stslex.wizard.feature.profile.ui.store.ProfileScreenState
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.Action
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.Event
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.State

class LogoutHandler(
private val interactor: ProfileInteractor,
) : Handler<State, Action.Logout, Event, Action>(Action.Logout::class) {
) : Handler<Action.Logout, ProfileHandlerStore> {

override fun HandlerStore<State, Action, Event>.invoke(action: Action.Logout) {
override fun ProfileHandlerStore.invoke(action: Action.Logout) {
val currentScreen = state.value.screen

if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,14 @@ import com.stslex.wizard.core.navigation.Screen.Follower.FollowerType.FOLLOWER
import com.stslex.wizard.core.navigation.Screen.Follower.FollowerType.FOLLOWING
import com.stslex.wizard.core.navigation.navigator.Navigator
import com.stslex.wizard.core.ui.mvi.v2.Handler
import com.stslex.wizard.core.ui.mvi.v2.HandlerStore
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.Action
import com.stslex.wizard.feature.profile.ui.store.ProfileHandlerStore
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.Action.Navigation
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.Event
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.State

class NavigationHandler(
private val navigator: Navigator
) : Handler<State, Navigation, Event, Action>(Navigation::class) {
) : Handler<Navigation, ProfileHandlerStore> {

override fun HandlerStore<State, Action, Event>.invoke(action: Navigation) {
override fun ProfileHandlerStore.invoke(action: Navigation) {
when (action) {
Navigation.LogIn -> navigator.navTo(Screen.Auth)
Navigation.Back -> navigator.popBack()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,13 @@ package com.stslex.wizard.feature.profile.mvi


import com.stslex.wizard.core.ui.mvi.v2.Handler
import com.stslex.wizard.core.ui.mvi.v2.HandlerStore
import com.stslex.wizard.feature.profile.ui.store.ProfileHandlerStore
import com.stslex.wizard.feature.profile.ui.store.ProfileScreenState
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.Action
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.Action.RepeatLastAction
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.Event
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.State

class RepeatLastActionHandler :
Handler<State, RepeatLastAction, Event, Action>(RepeatLastAction::class) {
class RepeatLastActionHandler : Handler<Action.RepeatLastAction, ProfileHandlerStore> {

override fun HandlerStore<State, Action, Event>.invoke(action: RepeatLastAction) {
override fun ProfileHandlerStore.invoke(action: Action.RepeatLastAction) {
val lastAction = lastAction ?: return
updateState { currentState ->
val screen = when (val screen = currentState.screen) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.stslex.wizard.feature.profile.ui.store

import com.stslex.wizard.core.ui.mvi.v2.HandlerStore
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.Action
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.Event
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.State

interface ProfileHandlerStore : ProfileStore, HandlerStore<State, Action, Event>
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
package com.stslex.wizard.feature.profile.ui.store

import com.stslex.wizard.core.database.store.UserStore
import com.stslex.wizard.core.navigation.navigator.Navigator
import com.stslex.wizard.core.ui.mvi.v2.BaseStore
import com.stslex.wizard.feature.profile.domain.interactor.ProfileInteractor
import com.stslex.wizard.feature.profile.mvi.ClickersHandler
import com.stslex.wizard.feature.profile.mvi.InitStorageHandler
import com.stslex.wizard.feature.profile.mvi.LogoutHandler
import com.stslex.wizard.feature.profile.mvi.NavigationHandler
import com.stslex.wizard.feature.profile.mvi.RepeatLastActionHandler
import com.stslex.wizard.feature.profile.mvi.clickersHandler
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.Action
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.Event
import com.stslex.wizard.feature.profile.ui.store.ProfileStore.State

class ProfileStoreImpl(
interactor: ProfileInteractor,
userStore: UserStore,
navigator: Navigator
) : ProfileStore, BaseStore<State, Action, Event>(
initStorageHandler: InitStorageHandler,
logoutHandler: LogoutHandler,
repeatLastActionHandler: RepeatLastActionHandler,
clickersHandler: ClickersHandler,
navigationHandler: NavigationHandler
) : ProfileHandlerStore, BaseStore<State, Action, Event, ProfileHandlerStore>(
initialState = State.INITIAL,
handlers = setOf(
InitStorageHandler(interactor, userStore),
LogoutHandler(interactor),
RepeatLastActionHandler(),
clickersHandler(),
NavigationHandler(navigator)
)
handlerCreator = { action ->
when (action) {
is Action.Init -> initStorageHandler
is Action.Logout -> logoutHandler
is Action.RepeatLastAction -> repeatLastActionHandler
is Action.Click -> clickersHandler
is Action.Navigation -> navigationHandler
}
}
)

0 comments on commit 5ea63d9

Please sign in to comment.