Skip to content

Commit

Permalink
Initial setup for Navigation and Store
Browse files Browse the repository at this point in the history
  • Loading branch information
stslex committed Nov 25, 2023
1 parent 325c6c7 commit b18d407
Show file tree
Hide file tree
Showing 23 changed files with 253 additions and 50 deletions.
10 changes: 9 additions & 1 deletion composeApp/src/commonMain/kotlin/App.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import androidx.compose.runtime.Composable
import com.stslex.core.core.coreModule
import com.stslex.core.ui.theme.AppTheme
import com.stslex.feature.home.di.homeModule
import di.appModule
import org.koin.compose.KoinApplication
import org.koin.dsl.KoinAppDeclaration

Expand All @@ -24,5 +26,11 @@ fun SetupKoin(
}

private fun setupModules(): KoinAppDeclaration = {
modules(listOf(homeModule))
modules(
listOf(
appModule,
coreModule,
homeModule,
)
)
}
19 changes: 19 additions & 0 deletions composeApp/src/commonMain/kotlin/AppNavigatorImpl.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import cafe.adriel.voyager.navigator.Navigator
import com.stslex.core.ui.navigation.AppNavigator
import com.stslex.core.ui.navigation.AppScreen
import com.stslex.feature.home.ui.HomeScreen
import com.stslex.feature.home.ui.SecondScreen

class AppNavigatorImpl(
private val navigator: Lazy<Navigator>
) : AppNavigator {

override fun navigate(
screen: AppScreen
) {
when (screen) {
AppScreen.Home -> navigator.value.push(HomeScreen)
is AppScreen.SecondScreen -> navigator.value.push(SecondScreen(screen.text))
}
}
}
20 changes: 14 additions & 6 deletions composeApp/src/commonMain/kotlin/InitialApp.kt
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.stslex.feature.home.HomeScreen
import com.stslex.feature.home.di.homeModule
import org.koin.core.context.startKoin
import cafe.adriel.voyager.navigator.Navigator
import com.stslex.feature.home.ui.HomeScreen

@Composable
fun InitialApp() {
fun InitialApp(
modifier: Modifier = Modifier
) {
Scaffold(
modifier = Modifier
modifier = modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
) { paddingValues ->
HomeScreen()
Box(
modifier = Modifier.fillMaxSize()
.padding(paddingValues)
) {
Navigator(HomeScreen)
}
}
}
6 changes: 0 additions & 6 deletions composeApp/src/commonMain/kotlin/NavigationHost.kt

This file was deleted.

13 changes: 13 additions & 0 deletions composeApp/src/commonMain/kotlin/di/appModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package di

import AppNavigatorImpl
import com.stslex.core.ui.navigation.AppNavigator
import org.koin.dsl.module

val appModule = module {
single<AppNavigator> {
AppNavigatorImpl(
lazyOf(get())
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.stslex.core.core

import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module

val coreModule = module {
singleOf<AppDispatcher>(::AppDispatcherImpl)
}
1 change: 1 addition & 0 deletions core/ui/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ kotlin {
api(libs.compose.ui.tooling.preview)
api(libs.androidx.activity.compose)
api(libs.koin.android)
api(libs.koin.androidx.compose)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package com.stslex.core.ui.base

import androidx.compose.runtime.Composable
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.CoroutineScope
import org.koin.androidx.compose.koinViewModel
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.core.definition.Definition
import org.koin.core.definition.KoinDefinition
import org.koin.core.module.Module
import org.koin.core.qualifier.Qualifier
import com.stslex.core.ui.base.ViewModel as VM

actual class ViewModel : ViewModel() {
actual open class ViewModel : ViewModel() {

actual val scope: CoroutineScope
get() = viewModelScope
Expand All @@ -19,4 +21,7 @@ actual class ViewModel : ViewModel() {
actual inline fun <reified T : VM> Module.viewModelDefinition(
qualifier: Qualifier?,
noinline definition: Definition<T>,
): KoinDefinition<T> = viewModel(qualifier = qualifier, definition = definition)
): KoinDefinition<T> = viewModel(qualifier = qualifier, definition = definition)

@Composable
actual inline fun <reified T : VM> getViewModel(): T = koinViewModel()
23 changes: 21 additions & 2 deletions core/ui/src/commonMain/kotlin/com/stslex/core/ui/base/ViewModel.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,36 @@
package com.stslex.core.ui.base

import androidx.compose.runtime.Composable
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import kotlinx.coroutines.CoroutineScope
import org.koin.compose.getKoin
import org.koin.core.definition.Definition
import org.koin.core.definition.KoinDefinition
import org.koin.core.module.Module
import org.koin.core.qualifier.Qualifier
import org.koin.dsl.module

expect class ViewModel {
expect open class ViewModel() {

val scope: CoroutineScope
}

expect inline fun <reified T : ViewModel> Module.viewModelDefinition(
qualifier: Qualifier? = null,
noinline definition: Definition<T>
): KoinDefinition<T>
): KoinDefinition<T>

@Composable
expect inline fun <reified T : ViewModel> getViewModel(): T

@Composable
inline fun <reified VM : ViewModel> rememberStore(): VM {
val navigator = LocalNavigator.currentOrThrow
val module = module { single { navigator } }
getKoin().loadModules(
modules = listOf(module),
allowOverride = true,
)
return getViewModel()
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ package com.stslex.core.ui.mvi
import com.stslex.core.core.AppDispatcher
import com.stslex.core.core.Logger
import com.stslex.core.core.coroutineExceptionHandler
import com.stslex.core.ui.navigation.Router
import com.stslex.core.ui.base.ViewModel
import com.stslex.core.ui.mvi.Store.Action
import com.stslex.core.ui.mvi.Store.Event
import com.stslex.core.ui.mvi.Store.Navigation
import com.stslex.core.ui.mvi.Store.State
import com.stslex.core.ui.navigation.Router
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
Expand All @@ -26,15 +27,13 @@ abstract class BaseStore<S : State, E : Event, A : Action, N : Navigation>(
private val router: Router<N>,
private val appDispatcher: AppDispatcher,
initialState: S
) {
) : Store, ViewModel() {

abstract fun sendAction(action: A)

private val _state: MutableStateFlow<S> = MutableStateFlow(initialState)
val state: StateFlow<S> = _state.asStateFlow()

private val scope: CoroutineScope = CoroutineScope(appDispatcher.default)

private fun exceptionHandler(
onError: suspend (cause: Throwable) -> Unit = {},
) = CoroutineExceptionHandler { coroutineContext, throwable ->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.stslex.core.ui.navigation

interface AppNavigator {

fun navigate(screen: AppScreen)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.stslex.core.ui.navigation

sealed interface AppScreen {

data object Home : AppScreen

data class SecondScreen(val text: String) : AppScreen
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ import com.stslex.core.ui.mvi.Store

fun interface Router<in E : Store.Navigation> {
operator fun invoke(event: E)
}
}

Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package com.stslex.core.ui.base

import androidx.compose.runtime.Composable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import org.koin.compose.koinInject
import org.koin.core.definition.Definition
import org.koin.core.definition.KoinDefinition
import org.koin.core.module.Module
import org.koin.core.qualifier.Qualifier

actual class ViewModel {
actual open class ViewModel {

actual val scope: CoroutineScope
get() = CoroutineScope(Dispatchers.Default)
Expand All @@ -16,4 +18,7 @@ actual class ViewModel {
actual inline fun <reified T : ViewModel> Module.viewModelDefinition(
qualifier: Qualifier?,
noinline definition: Definition<T>,
): KoinDefinition<T> = factory(qualifier = qualifier, definition = definition)
): KoinDefinition<T> = factory(qualifier = qualifier, definition = definition)

@Composable
actual inline fun <reified T : ViewModel> getViewModel(): T = koinInject()
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package com.stslex.core.ui.base

import androidx.compose.runtime.Composable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import org.koin.compose.koinInject
import org.koin.core.definition.Definition
import org.koin.core.definition.KoinDefinition
import org.koin.core.module.Module
import org.koin.core.qualifier.Qualifier

actual class ViewModel {
actual open class ViewModel {

actual val scope: CoroutineScope
get() = CoroutineScope(Dispatchers.Default)
Expand All @@ -16,4 +18,7 @@ actual class ViewModel {
actual inline fun <reified T : ViewModel> Module.viewModelDefinition(
qualifier: Qualifier?,
noinline definition: Definition<T>,
): KoinDefinition<T> = factory(qualifier = qualifier, definition = definition)
): KoinDefinition<T> = factory(qualifier = qualifier, definition = definition)

@Composable
actual inline fun <reified T : ViewModel> getViewModel(): T = koinInject()
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package com.stslex.feature.home.di

import com.stslex.feature.home.domain.HomeInteractor
import com.stslex.feature.home.domain.HomeInteractorImpl
import com.stslex.core.ui.base.viewModelDefinition
import com.stslex.feature.home.navigation.HomeScreenRouter
import com.stslex.feature.home.navigation.HomeScreenRouterImpl
import com.stslex.feature.home.ui.store.HomeScreenStore
import org.koin.dsl.module

val homeModule = module {
single<HomeInteractor> { HomeInteractorImpl() }
}
viewModelDefinition { HomeScreenStore(get(), get()) }
factory<HomeScreenRouter> {
HomeScreenRouterImpl(get())
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.stslex.feature.home.navigation

import com.stslex.core.ui.navigation.AppNavigator
import com.stslex.core.ui.navigation.AppScreen
import com.stslex.core.ui.navigation.Router
import com.stslex.feature.home.ui.store.HomeScreenStoreComponent.Navigation

interface HomeScreenRouter : Router<Navigation>

class HomeScreenRouterImpl(
private val navigator: AppNavigator
) : HomeScreenRouter {

override fun invoke(event: Navigation) {
when (event) {
is Navigation.SecondScreen -> navigator.navigate(AppScreen.SecondScreen(event.text))
}
}
}
Loading

0 comments on commit b18d407

Please sign in to comment.