Skip to content

Commit

Permalink
Merge pull request #28 from 2rabs/rt/top-feature-compose
Browse files Browse the repository at this point in the history
👍 トップ機能モジュールを KMP で再構成
  • Loading branch information
tatsutakein authored Nov 21, 2023
2 parents 41a0aa8 + 3d8ae8e commit 8f7f5c9
Show file tree
Hide file tree
Showing 19 changed files with 222 additions and 106 deletions.
5 changes: 5 additions & 0 deletions app/android/src/main/java/club/nito/app/NitoApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.compose.material3.Surface
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import club.nito.app.di.featureModules
import club.nito.app.di.nitoDateTimeFormatterModule
import club.nito.app.di.userMessageStateHolderModule
import club.nito.core.data.di.dataModule
Expand All @@ -14,6 +15,7 @@ import club.nito.core.domain.di.useCaseModule
import club.nito.core.model.AuthStatus
import club.nito.core.network.di.remoteDataSourceModule
import club.nito.core.network.di.supabaseClientModule
import club.nito.feature.top.di.topFeatureModule
import org.koin.compose.KoinApplication

@Composable
Expand All @@ -33,8 +35,11 @@ fun NitoApp(
// fakeRemoteDataSourceModule,
dataModule,
useCaseModule,
topFeatureModule,
)

modules(featureModules)

// val kermit = Logger.withTag("koin")
// logger(KermitKoinLogger(kermit))
},
Expand Down
8 changes: 8 additions & 0 deletions app/android/src/main/java/club/nito/app/di/FeatureModules.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package club.nito.app.di

import club.nito.feature.top.di.topFeatureModule
import org.koin.core.module.Module

val featureModules: List<Module> = listOf(
topFeatureModule,
)
79 changes: 79 additions & 0 deletions core/ui/src/commonMain/kotlin/club/nito/core/ui/UiStateBuilder.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package club.nito.core.ui

import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn

public fun <T1, R> StateMachine.buildUiState(
flow: StateFlow<T1>,
transform: (T1) -> R,
): StateFlow<R> = flow.map(transform = transform)
.stateIn(
scope = stateMachineScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = transform(
flow.value,
),
)

public fun <T1, T2, R> StateMachine.buildUiState(
flow: StateFlow<T1>,
flow2: StateFlow<T2>,
transform: (T1, T2) -> R,
): StateFlow<R> = combine(
flow = flow,
flow2 = flow2,
transform = transform,
).stateIn(
scope = stateMachineScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = transform(
flow.value,
flow2.value,
),
)

public fun <T1, T2, T3, R> StateMachine.buildUiState(
flow: StateFlow<T1>,
flow2: StateFlow<T2>,
flow3: StateFlow<T3>,
transform: (T1, T2, T3) -> R,
): StateFlow<R> = combine(
flow = flow,
flow2 = flow2,
flow3 = flow3,
transform = transform,
).stateIn(
scope = stateMachineScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = transform(
flow.value,
flow2.value,
flow3.value,
),
)

public fun <T1, T2, T3, T4, R> StateMachine.buildUiState(
flow: StateFlow<T1>,
flow2: StateFlow<T2>,
flow3: StateFlow<T3>,
flow4: StateFlow<T4>,
transform: (T1, T2, T3, T4) -> R,
): StateFlow<R> = combine(
flow = flow,
flow2 = flow2,
flow3 = flow3,
flow4 = flow4,
transform = transform,
).stateIn(
scope = stateMachineScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = transform(
flow.value,
flow2.value,
flow3.value,
flow4.value,
),
)
3 changes: 3 additions & 0 deletions feature/top/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ kotlin {
implementation(projects.core.designsystem)

implementation(libs.kotlinxCoroutinesCore)

implementation(libs.koin)
implementation(libs.koinCompose)
}
}
androidMain {
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,63 +5,63 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import club.nito.core.designsystem.component.CenterAlignedTopAppBar
import club.nito.core.designsystem.component.Scaffold
import club.nito.core.designsystem.component.Text
import club.nito.core.ui.ConfirmParticipateDialog
import club.nito.core.ui.message.SnackbarMessageEffect
import club.nito.feature.top.component.ParticipantScheduleSection
import org.koin.compose.koinInject

@Composable
fun TopRoute(
viewModel: TopViewModel = hiltViewModel(),
stateMachine: TopStateMachine = koinInject(),
onScheduleListClick: () -> Unit = {},
onSettingsClick: () -> Unit = {},
) {
viewModel.event.collectAsState(initial = null).value?.let {
stateMachine.event.collectAsState(initial = null).value?.let {
LaunchedEffect(it.hashCode()) {
when (it) {
TopEvent.NavigateToScheduleList -> onScheduleListClick()
TopEvent.NavigateToSettings -> onSettingsClick()
TopScreenEvent.NavigateToScheduleList -> onScheduleListClick()
TopScreenEvent.NavigateToSettings -> onSettingsClick()
}
viewModel.consume(it)
stateMachine.consume(it)
}
}

val uiState by viewModel.uiState.collectAsState()
val uiState by stateMachine.uiState.collectAsState()
val snackbarHostState = remember { SnackbarHostState() }

SnackbarMessageEffect(
snackbarHostState = snackbarHostState,
userMessageStateHolder = viewModel.userMessageStateHolder,
userMessageStateHolder = stateMachine.userMessageStateHolder,
)

TopScreen(
uiState = uiState,
snackbarHostState = snackbarHostState,
dispatch = viewModel::dispatch,
dispatch = stateMachine::dispatch,
)
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopScreen(
internal fun TopScreen(
uiState: TopScreenUiState,
snackbarHostState: SnackbarHostState,
dispatch: (TopIntent) -> Unit = {},
dispatch: (TopScreenIntent) -> Unit = {},
) {
val recentSchedule = uiState.recentSchedule
val confirmParticipateDialog = uiState.confirmParticipateDialog
Expand All @@ -75,7 +75,7 @@ private fun TopScreen(
)
},
actions = {
IconButton(onClick = { dispatch(TopIntent.ClickSettings) }) {
IconButton(onClick = { dispatch(TopScreenIntent.ClickSettings) }) {
Icon(
imageVector = Icons.Default.Settings,
contentDescription = "Settings",
Expand All @@ -90,8 +90,8 @@ private fun TopScreen(
ConfirmParticipateDialog(
schedule = confirmParticipateDialog.schedule,
dateTimeFormatter = uiState.dateTimeFormatter,
onParticipateRequest = { dispatch(TopIntent.ClickParticipateSchedule(it)) },
onDismissRequest = { dispatch(TopIntent.ClickDismissConfirmParticipateDialog) },
onParticipateRequest = { dispatch(TopScreenIntent.ClickParticipateSchedule(it)) },
onDismissRequest = { dispatch(TopScreenIntent.ClickDismissConfirmParticipateDialog) },
)
}

Expand All @@ -104,8 +104,8 @@ private fun TopScreen(
ParticipantScheduleSection(
recentSchedule = recentSchedule,
dateTimeFormatter = uiState.dateTimeFormatter,
onRecentScheduleClick = { dispatch(TopIntent.ClickShowConfirmParticipateDialog(it)) },
onScheduleListClick = { dispatch(TopIntent.ClickScheduleList) },
onRecentScheduleClick = { dispatch(TopScreenIntent.ClickShowConfirmParticipateDialog(it)) },
onScheduleListClick = { dispatch(TopScreenIntent.ClickScheduleList) },
)
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package club.nito.feature.top

sealed class TopScreenEvent {
/**
* Navigate to schedule list screen
*/
data object NavigateToScheduleList : TopScreenEvent()

/**
* Navigate to settings screen
*/
data object NavigateToSettings : TopScreenEvent()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package club.nito.feature.top

import club.nito.core.domain.model.ParticipantSchedule

sealed class TopScreenIntent {
/**
* Click schedule list
*/
data object ClickScheduleList : TopScreenIntent()

/**
* Click settings
*/
data object ClickSettings : TopScreenIntent()

/**
* Click show confirm participate dialog
*/
data class ClickShowConfirmParticipateDialog(val schedule: ParticipantSchedule) : TopScreenIntent()

/**
* Click participate schedule
*/
data class ClickParticipateSchedule(val schedule: ParticipantSchedule) : TopScreenIntent()

/**
* Click dismiss confirm participate dialog
*/
data object ClickDismissConfirmParticipateDialog : TopScreenIntent()
}
Loading

0 comments on commit 8f7f5c9

Please sign in to comment.