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

Store, Navigation #3

Merged
merged 4 commits into from
Nov 25, 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
22 changes: 5 additions & 17 deletions composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
import org.jetbrains.compose.ExperimentalComposeLibrary

plugins {
alias(libs.plugins.kotlinMultiplatform)
Expand All @@ -15,9 +14,9 @@ kotlin {
}
}
}

jvm("desktop")

listOf(
iosX64(),
iosArm64(),
Expand All @@ -28,29 +27,18 @@ kotlin {
isStatic = true
}
}

sourceSets {
val desktopMain by getting

androidMain.dependencies {
implementation(libs.compose.ui)
implementation(libs.compose.ui.tooling.preview)
implementation(libs.androidx.activity.compose)
}

desktopMain.dependencies {
implementation(compose.desktop.currentOs)
}

commonMain.dependencies {
implementation(project(":core:core"))
implementation(project(":core:ui"))
implementation(project(":feature:home"))

implementation(projects.shared)
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
@OptIn(ExperimentalComposeLibrary::class)
implementation(compose.components.resources)
}
}
}
Expand Down
31 changes: 29 additions & 2 deletions composeApp/src/commonMain/kotlin/App.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,36 @@
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

@Composable
fun App() {
AppTheme {
InitialApp()
SetupKoin {
AppTheme {
InitialApp()
}
}
}

@Composable
fun SetupKoin(
content: @Composable () -> Unit
) {
KoinApplication(
application = setupModules(),
content = content
)
}

private fun setupModules(): KoinAppDeclaration = {
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))
}
}
}
29 changes: 25 additions & 4 deletions composeApp/src/commonMain/kotlin/InitialApp.kt
Original file line number Diff line number Diff line change
@@ -1,7 +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 com.stslex.feature.home.HomeScreen
import androidx.compose.ui.Modifier
import cafe.adriel.voyager.navigator.Navigator
import com.stslex.feature.home.ui.HomeScreen

@Composable
fun InitialApp() {
HomeScreen()
}
fun InitialApp(
modifier: Modifier = Modifier
) {
Scaffold(
modifier = modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
) { paddingValues ->
Box(
modifier = Modifier.fillMaxSize()
.padding(paddingValues)
) {
Navigator(HomeScreen)
}
}
}
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())
)
}
}
10 changes: 3 additions & 7 deletions core/core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ kotlin {
}

jvm("desktop")

listOf(
iosX64(),
iosArm64(),
Expand All @@ -27,20 +27,16 @@ kotlin {
}

sourceSets {
val desktopMain by getting

commonMain.dependencies {
implementation(libs.kermit)
implementation(projects.shared)
implementation(compose.runtime)
implementation(compose.foundation)
api(libs.koin.core)
api(libs.koin.compose)
}
commonTest.dependencies {
implementation(libs.kotlin.test)
}
desktopMain.dependencies {
implementation(compose.desktop.currentOs)
}
}
}

Expand Down
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)
}
21 changes: 15 additions & 6 deletions core/ui/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,30 @@ kotlin {
sourceSets {
val desktopMain by getting

desktopMain.dependencies {
implementation(compose.desktop.currentOs)
}

commonMain.dependencies {
implementation(project(":core:core"))

implementation(projects.shared)
implementation(compose.runtime)
implementation(compose.foundation)
api(compose.runtime)
api(compose.foundation)
implementation(compose.material)
api(compose.material3)
@OptIn(ExperimentalComposeLibrary::class)
implementation(compose.components.resources)
api(compose.components.resources)
api(libs.bundles.voyager)
}
commonTest.dependencies {
implementation(libs.kotlin.test)
}
desktopMain.dependencies {
implementation(compose.desktop.currentOs)
androidMain.dependencies {
api(libs.compose.ui)
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
@@ -0,0 +1,27 @@
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 open class ViewModel : ViewModel() {

actual val scope: CoroutineScope
get() = viewModelScope
}

actual inline fun <reified T : VM> Module.viewModelDefinition(
qualifier: Qualifier?,
noinline definition: Definition<T>,
): KoinDefinition<T> = viewModel(qualifier = qualifier, definition = definition)

@Composable
actual inline fun <reified T : VM> getViewModel(): T = koinViewModel()
36 changes: 36 additions & 0 deletions core/ui/src/commonMain/kotlin/com/stslex/core/ui/base/ViewModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +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 open class ViewModel() {

val scope: CoroutineScope
}

expect inline fun <reified T : ViewModel> Module.viewModelDefinition(
qualifier: Qualifier? = null,
noinline definition: Definition<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,9 +1,9 @@
package com.stslex.core.ui.theme

import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material.MaterialTheme
import androidx.compose.material.darkColors
import androidx.compose.material.lightColors
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable

@Composable
Expand All @@ -12,12 +12,12 @@ fun AppTheme(
content: @Composable () -> Unit,
) {
val colors = if (isDarkTheme) {
darkColors()
darkColorScheme()
} else {
lightColors()
lightColorScheme()
}
MaterialTheme(
colors = colors,
colorScheme = colors,
content = content
)
}
Loading
Loading