Skip to content

Commit

Permalink
✨ Settings モジュールを Compose Multiplatform 化
Browse files Browse the repository at this point in the history
  • Loading branch information
tatsutakein committed Nov 22, 2023
1 parent 2e9b2a4 commit 525fb38
Show file tree
Hide file tree
Showing 18 changed files with 90 additions and 85 deletions.
2 changes: 2 additions & 0 deletions app/android/src/main/java/club/nito/app/di/FeatureModules.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package club.nito.app.di

import club.nito.feature.auth.di.authFeatureModule
import club.nito.feature.schedule.di.scheduleFeatureModule
import club.nito.feature.settings.di.settingsFeatureModule
import club.nito.feature.top.di.topFeatureModule
import org.koin.core.module.Module

val featureModules: List<Module> = listOf(
authFeatureModule,
topFeatureModule,
scheduleFeatureModule,
settingsFeatureModule,
)
3 changes: 3 additions & 0 deletions feature/settings/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,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.

Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import androidx.navigation.compose.composable

const val settingsNavigationRoute = "settings_route"

fun NavController.navigateToSettings(navOptions: NavOptions? = null) {
this.navigate(settingsNavigationRoute, navOptions)
}
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package club.nito.feature.settings

import moe.tlaster.precompose.navigation.NavOptions
import moe.tlaster.precompose.navigation.Navigator
import moe.tlaster.precompose.navigation.RouteBuilder

const val settingsNavigationRoute = "settings_route"

fun Navigator.navigateToSettings(navOptions: NavOptions? = null) {
this.navigate(settingsNavigationRoute, navOptions)
}

fun RouteBuilder.settingsScreen(
onSignedOut: () -> Unit = {},
) {
scene(
route = settingsNavigationRoute,
) {
SettingsRoute(onSignedOut = onSignedOut)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,39 +22,39 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
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.koinStateMachine
import club.nito.core.ui.message.SnackbarMessageEffect
import club.nito.feature.settings.component.ModifyPasswordDialog

@Composable
fun SettingsRoute(
viewModel: SettingsViewModel = hiltViewModel(),
stateMachine: SettingsScreenStateMachine = koinStateMachine(),
onSignedOut: () -> Unit = {},
) {
viewModel.event.collectAsState(initial = null).value?.let {
stateMachine.event.collectAsState(initial = null).value?.let {
LaunchedEffect(it.hashCode()) {
when (it) {
SettingsEvent.SignedOut -> onSignedOut()
SettingsScreenEvent.SignedOut -> onSignedOut()
}
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,
)

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

Expand All @@ -63,7 +63,7 @@ fun SettingsRoute(
private fun SettingsScreen(
uiState: SettingsScreenUiState,
snackbarHostState: SnackbarHostState,
dispatch: (SettingsIntent) -> Unit = {},
dispatch: (SettingsScreenIntent) -> Unit = {},
) {
val modifyPassword = uiState.modifyPassword

Expand All @@ -82,9 +82,9 @@ private fun SettingsScreen(
if (modifyPassword is ModifyPasswordUiState.Show) {
ModifyPasswordDialog(
newPassword = modifyPassword.newPassword,
onNewPasswordChanged = { dispatch(SettingsIntent.ChangeNewPasswordValue(it)) },
onModifyRequest = { dispatch(SettingsIntent.ClickModifyPassword) },
onDismissRequest = { dispatch(SettingsIntent.ClickDismissModifyPasswordDialog) },
onNewPasswordChanged = { dispatch(SettingsScreenIntent.ChangeNewPasswordValue(it)) },
onModifyRequest = { dispatch(SettingsScreenIntent.ClickModifyPassword) },
onDismissRequest = { dispatch(SettingsScreenIntent.ClickDismissModifyPasswordDialog) },
)

if (modifyPassword is ModifyPasswordUiState.Show.Modifying) {
Expand All @@ -110,7 +110,7 @@ private fun SettingsScreen(
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 48.dp)
.clickable { dispatch(SettingsIntent.ClickShowModifyPasswordDialog) }
.clickable { dispatch(SettingsScreenIntent.ClickShowModifyPasswordDialog) }
.padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Expand All @@ -125,7 +125,7 @@ private fun SettingsScreen(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
onClick = { dispatch(SettingsIntent.ClickSignOut) },
onClick = { dispatch(SettingsScreenIntent.ClickSignOut) },
enabled = uiState.isSignOutButtonEnabled,
) {
Text(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package club.nito.feature.settings

sealed class SettingsScreenEvent {
data object SignedOut : SettingsScreenEvent()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package club.nito.feature.settings

sealed class SettingsScreenIntent {
data object ClickShowModifyPasswordDialog : SettingsScreenIntent()
data class ChangeNewPasswordValue(val newValue: String) : SettingsScreenIntent()
data object ClickModifyPassword : SettingsScreenIntent()
data object ClickDismissModifyPasswordDialog : SettingsScreenIntent()
data object ClickSignOut : SettingsScreenIntent()
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
package club.nito.feature.settings

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import club.nito.core.domain.ModifyPasswordUseCase
import club.nito.core.domain.ObserveAuthStatusUseCase
import club.nito.core.domain.SignOutUseCase
import club.nito.core.model.AuthStatus
import club.nito.core.model.ExecuteResult
import club.nito.core.model.FetchSingleResult
import club.nito.core.ui.StateMachine
import club.nito.core.ui.buildUiState
import club.nito.core.ui.message.UserMessageStateHolder
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
Expand All @@ -20,18 +18,17 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import javax.inject.Inject
import moe.tlaster.precompose.viewmodel.viewModelScope

@HiltViewModel
class SettingsViewModel @Inject constructor(
observeAuthStatusUseCase: ObserveAuthStatusUseCase,
private val modifyPasswordUseCase: ModifyPasswordUseCase,
private val signOutUseCase: SignOutUseCase,
class SettingsScreenStateMachine(
observeAuthStatus: ObserveAuthStatusUseCase,
private val modifyPassword: ModifyPasswordUseCase,
private val signOut: SignOutUseCase,
val userMessageStateHolder: UserMessageStateHolder,
) : ViewModel(),
) : StateMachine(),
UserMessageStateHolder by userMessageStateHolder {

private val authStatus = observeAuthStatusUseCase().stateIn(
private val authStatus = observeAuthStatus().stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = FetchSingleResult.Loading,
Expand Down Expand Up @@ -59,26 +56,26 @@ class SettingsViewModel @Inject constructor(
)
}

private val _events = MutableStateFlow<List<SettingsEvent>>(emptyList())
val event: Flow<SettingsEvent?> = _events.map { it.firstOrNull() }
private val _events = MutableStateFlow<List<SettingsScreenEvent>>(emptyList())
val event: Flow<SettingsScreenEvent?> = _events.map { it.firstOrNull() }

init {
viewModelScope.launch {
authStatus.collectLatest {
if (it is FetchSingleResult.Success && it.data is AuthStatus.NotAuthenticated) {
_events.emit(listOf(SettingsEvent.SignedOut))
_events.emit(listOf(SettingsScreenEvent.SignedOut))
}
}
}
}

fun dispatch(intent: SettingsIntent) {
fun dispatch(intent: SettingsScreenIntent) {
viewModelScope.launch {
when (intent) {
SettingsIntent.ClickShowModifyPasswordDialog -> showModifyPasswordDialog.emit(true)
is SettingsIntent.ChangeNewPasswordValue -> newPassword.emit(intent.newValue)
SettingsIntent.ClickModifyPassword -> {
when (modifyPasswordUseCase(newPassword.value)) {
SettingsScreenIntent.ClickShowModifyPasswordDialog -> showModifyPasswordDialog.emit(true)
is SettingsScreenIntent.ChangeNewPasswordValue -> newPassword.emit(intent.newValue)
SettingsScreenIntent.ClickModifyPassword -> {
when (modifyPassword(newPassword.value)) {
is ExecuteResult.Success -> {
val showMessage = async { userMessageStateHolder.showMessage("パスワードを変更しました") }
newPassword.emit("")
Expand All @@ -90,9 +87,9 @@ class SettingsViewModel @Inject constructor(
}
}

SettingsIntent.ClickDismissModifyPasswordDialog -> showModifyPasswordDialog.emit(false)
SettingsIntent.ClickSignOut -> {
val result = signOutUseCase()
SettingsScreenIntent.ClickDismissModifyPasswordDialog -> showModifyPasswordDialog.emit(false)
SettingsScreenIntent.ClickSignOut -> {
val result = signOut()
if (result is ExecuteResult.Failure) {
userMessageStateHolder.showMessage("サインアウトに失敗しました")
}
Expand All @@ -101,7 +98,7 @@ class SettingsViewModel @Inject constructor(
}
}

fun consume(event: SettingsEvent) {
fun consume(event: SettingsScreenEvent) {
viewModelScope.launch {
_events.emit(_events.value.filterNot { it == event })
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package club.nito.feature.settings.di

import club.nito.feature.settings.SettingsScreenStateMachine
import org.koin.core.module.Module
import org.koin.dsl.module

val settingsFeatureModule: Module = module {
factory {
SettingsScreenStateMachine(
observeAuthStatus = get(),
modifyPassword = get(),
signOut = get(),
userMessageStateHolder = get(),
)
}
}
Empty file.

This file was deleted.

0 comments on commit 525fb38

Please sign in to comment.