Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor arch #63

Merged
merged 6 commits into from
Oct 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import st.slex.csplashscreen.core.ui.mvi.Router
import st.slex.csplashscreen.core.ui.mvi.Store
import st.slex.csplashscreen.core.ui.mvi.Store.Action
import st.slex.csplashscreen.core.ui.mvi.Store.Event
import st.slex.csplashscreen.core.ui.mvi.Store.State

open class BaseViewModel<out S : State, out E : Event, in A : Action, in N : Event.Navigation>(
open class BaseViewModel<out S : State, out E : Event, in A : Action>(
private val store: Store<S, E, A>,
private val router: Router<N>
) : ViewModel() {

val state: StateFlow<S> = store.state
Expand All @@ -26,10 +24,6 @@ open class BaseViewModel<out S : State, out E : Event, in A : Action, in N : Eve
store.processAction(action)
}

fun navigate(event: N) {
router(event)
}

override fun onCleared() {
super.onCleared()
store.destroy()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package st.slex.csplashscreen.core.ui.base

import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.compose.viewModel
import st.slex.csplashscreen.core.ui.di.builder.Feature
import st.slex.csplashscreen.core.ui.di.builder.FeatureBuilder

@Composable
inline fun <reified T : ViewModel> daggerViewModel(
Expand All @@ -13,4 +17,25 @@ inline fun <reified T : ViewModel> daggerViewModel(
modelClass = T::class.java,
key = key,
factory = factory()
)
)

@Composable
inline fun <reified VM : ViewModel, F : Feature> setupComponent(
builder: FeatureBuilder<F>,
key: String? = null,
): VM {
val context = LocalContext.current

DisposableEffect(Unit) {
builder.create(context)
onDispose {
builder.clear()
}
}

return daggerViewModel(key) {
builder
.build(context)
.viewModelFactory
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package st.slex.csplashscreen.core.ui.di.builder

import androidx.lifecycle.ViewModelProvider

interface Feature {

val viewModelFactory: ViewModelProvider.Factory
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package st.slex.csplashscreen.core.ui.di.builder

import android.content.Context

interface FeatureBuilder<F : Feature> {

var feature: F?

fun create(context: Context): F

fun build(
context: Context
): F = feature ?: create(context)
.also { createdFeature ->
feature = createdFeature
}

fun clear() {
feature = null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,38 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import st.slex.csplashscreen.core.ui.mvi.Store.Action
import st.slex.csplashscreen.core.ui.mvi.Store.Event
import st.slex.csplashscreen.core.ui.mvi.Store.Navigation
import st.slex.csplashscreen.core.ui.mvi.Store.State

abstract class BaseStoreImpl<S : State, E : Event, A : Action> :
Store<S, E, A>,
StoreImpl<S, E, A> {
abstract class BaseStore<S : State, E : Event, A : Action, N : Navigation>(
private val router: Router<N>
) : Store<S, E, A> {

abstract val initialState: S

private var _scope: CoroutineScope? = null
val scope: CoroutineScope
get() = requireNotNull(_scope)

@Suppress("LeakingThis")
override val state: MutableStateFlow<S> = MutableStateFlow(initialState)
override val state: MutableStateFlow<S>
get() = MutableStateFlow(initialState)

override val event: MutableSharedFlow<E> = MutableSharedFlow()

override fun updateState(update: (S) -> S) {
fun updateState(update: (S) -> S) {
state.update(update)
}

override fun sendEvent(event: E) {
fun sendEvent(event: E) {
scope.launch {
this@BaseStoreImpl.event.emit(event)
this@BaseStore.event.emit(event)
}
}

fun navigate(event: N) {
router(event)
}

override fun init(scope: CoroutineScope) {
_scope = scope
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package st.slex.csplashscreen.core.ui.mvi

fun interface Router<in E : Store.Event.Navigation> {
fun interface Router<in E : Store.Navigation> {
operator fun invoke(event: E)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ interface Store<out S : State, out E : Event, in A : Action> {

interface State

interface Event {
interface Navigation : Event
}
interface Event

interface Navigation

interface Action
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,36 +1,23 @@
package st.slex.csplashscreen.feature.collection.di

import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import android.content.Context
import st.slex.csplashscreen.core.network.di.NetworkApiBuilder
import st.slex.csplashscreen.core.ui.base.daggerViewModel
import st.slex.csplashscreen.core.ui.di.NavigationApi
import st.slex.csplashscreen.core.ui.di.builder.FeatureBuilder
import st.slex.csplashscreen.core.ui.di.navigationApi
import st.slex.csplashscreen.feature.collection.ui.SingleCollectionViewModel

object SingleCollectionBuilder {
object SingleCollectionBuilder : FeatureBuilder<SingleCollectionComponent> {

fun build(
navigationApi: NavigationApi
): SingleCollectionComponent = DaggerSingleCollectionComponent
.factory()
.create(
dependencies = DaggerSingleCollectionComponent_SingleCollectionDependenciesComponent
.factory()
.create(
networkClientApi = NetworkApiBuilder.build(),
navigationApi = navigationApi
)
override var feature: SingleCollectionComponent? = null

)
}

@Composable
fun setupComponent(key: String): SingleCollectionViewModel {
val context = LocalContext.current
return daggerViewModel(key) {
SingleCollectionBuilder
.build(context.navigationApi)
.viewModelFactory
}
override fun create(context: Context): SingleCollectionComponent =
DaggerSingleCollectionComponent
.factory()
.create(
dependencies = DaggerSingleCollectionComponent_SingleCollectionDependenciesComponent
.factory()
.create(
networkClientApi = NetworkApiBuilder.build(),
navigationApi = context.navigationApi
)
)
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package st.slex.csplashscreen.feature.collection.di

import androidx.lifecycle.ViewModelProvider
import dagger.Component
import st.slex.csplashscreen.core.network.di.NetworkClientApi
import st.slex.csplashscreen.core.ui.di.NavigationApi
import st.slex.csplashscreen.core.ui.di.builder.Feature

@Component(
dependencies = [SingleCollectionDependencies::class],
modules = [SingleCollectionModule::class]
)
@SingleCollectionScope
interface SingleCollectionComponent {
interface SingleCollectionComponent : Feature {

@Component.Factory
interface Factory {
Expand All @@ -32,6 +32,4 @@ interface SingleCollectionComponent {
): SingleCollectionDependencies
}
}

val viewModelFactory: ViewModelProvider.Factory
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import st.slex.csplashscreen.core.navigation.AppArguments
import st.slex.csplashscreen.core.navigation.AppDestination
import st.slex.csplashscreen.core.navigation.NavExt.composableArguments
import st.slex.csplashscreen.core.navigation.NavExt.parseArguments
import st.slex.csplashscreen.core.ui.base.setupComponent
import st.slex.csplashscreen.core.ui.utils.CollectAsEvent
import st.slex.csplashscreen.feature.collection.di.setupComponent
import st.slex.csplashscreen.feature.collection.di.SingleCollectionBuilder
import st.slex.csplashscreen.feature.collection.ui.CollectionScreen
import st.slex.csplashscreen.feature.collection.ui.SingleCollectionViewModel
import st.slex.csplashscreen.feature.collection.ui.store.SingleCollectionStore.Action
import st.slex.csplashscreen.feature.collection.ui.store.SingleCollectionStore.Event

fun NavGraphBuilder.singleCollectionGraph(
modifier: Modifier = Modifier,
Expand All @@ -28,7 +29,10 @@ fun NavGraphBuilder.singleCollectionGraph(
val arguments = AppDestination.COLLECTION.parseArguments(navBackStackEntry).let { args ->
AppArguments.CollectionScreen(args[0])
}
val viewModel = setupComponent(key = arguments.collectionId)
val viewModel: SingleCollectionViewModel = setupComponent(
key = arguments.collectionId,
builder = SingleCollectionBuilder
)

val state by remember {
viewModel.state
Expand All @@ -43,9 +47,7 @@ fun NavGraphBuilder.singleCollectionGraph(
}

viewModel.event.CollectAsEvent { event ->
when (event) {
is Event.Navigation -> viewModel.navigate(event)
}
// TODO NOT IMPLEMENTED YET
}

CollectionScreen(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package st.slex.csplashscreen.feature.collection.navigation

import st.slex.csplashscreen.core.ui.mvi.Router
import st.slex.csplashscreen.feature.collection.ui.store.SingleCollectionStore.Event.Navigation
import st.slex.csplashscreen.feature.collection.ui.store.SingleCollectionStore.Navigation

interface SingleCollectionRouter : Router<Navigation>
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package st.slex.csplashscreen.feature.collection.navigation

import st.slex.csplashscreen.core.navigation.NavigationScreen
import st.slex.csplashscreen.core.ui.di.Navigator
import st.slex.csplashscreen.feature.collection.ui.store.SingleCollectionStore.Event.Navigation
import st.slex.csplashscreen.feature.collection.ui.store.SingleCollectionStore.Navigation
import javax.inject.Inject

class SingleCollectionRouterImpl @Inject constructor(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package st.slex.csplashscreen.feature.collection.ui

import st.slex.csplashscreen.core.ui.base.BaseViewModel
import st.slex.csplashscreen.feature.collection.navigation.SingleCollectionRouter
import st.slex.csplashscreen.feature.collection.ui.store.SingleCollectionStore
import st.slex.csplashscreen.feature.collection.ui.store.SingleCollectionStore.Action
import st.slex.csplashscreen.feature.collection.ui.store.SingleCollectionStore.Event
import st.slex.csplashscreen.feature.collection.ui.store.SingleCollectionStore.Event.Navigation
import st.slex.csplashscreen.feature.collection.ui.store.SingleCollectionStore.State
import javax.inject.Inject

class SingleCollectionViewModel @Inject constructor(
store: SingleCollectionStore,
router: SingleCollectionRouter
) : BaseViewModel<State, Event, Action, Navigation>(store, router)
) : BaseViewModel<State, Event, Action>(store)
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,20 @@ interface SingleCollectionStore : Store<State, Event, Action> {
) : Store.State

@Stable
sealed interface Event : Store.Event {
sealed interface Event : Store.Event

@Stable
sealed interface Navigation : Store.Navigation {

@Stable
data class Profile(
val username: String
) : Navigation

@Stable
sealed interface Navigation : Event, Store.Event.Navigation {

@Stable
data class Profile(
val username: String
) : Navigation

@Stable
data class ImageDetail(
val uuid: String
) : Navigation
}
data class ImageDetail(
val uuid: String
) : Navigation
}

@Stable
Expand Down
Loading
Loading