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

✨ ID を元にスケジュールを取得するユースケースを追加 #117

Merged
merged 5 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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 @@ -2,13 +2,14 @@ package club.nito.ios.combined

import club.nito.core.data.AuthRepository
import club.nito.core.data.ScheduleRepository
import club.nito.core.domain.AuthStatusStreamUseCase
import club.nito.core.domain.FetchParticipantScheduleByIdUseCase
import club.nito.core.domain.GetParticipantScheduleListUseCase
import club.nito.core.domain.GetRecentScheduleUseCase
import club.nito.core.domain.ModifyPasswordUseCase
import club.nito.core.domain.AuthStatusStreamUseCase
import club.nito.core.domain.ParticipateUseCase
import club.nito.core.domain.LoginUseCase
import club.nito.core.domain.LogoutUseCase
import club.nito.core.domain.ModifyPasswordUseCase
import club.nito.core.domain.ParticipateUseCase
import club.nito.core.network.auth.AuthRemoteDataSource
import club.nito.core.network.participation.ParticipantRemoteDataSource
import club.nito.core.network.schedule.ScheduleRemoteDataSource
Expand Down Expand Up @@ -39,6 +40,7 @@ class EntryPointTest {
assertNotNull(kmpEntryPoint.get<LoginUseCase>())
assertNotNull(kmpEntryPoint.get<ModifyPasswordUseCase>())
assertNotNull(kmpEntryPoint.get<LogoutUseCase>())
assertNotNull(kmpEntryPoint.get<FetchParticipantScheduleByIdUseCase>())
assertNotNull(kmpEntryPoint.get<GetRecentScheduleUseCase>())
assertNotNull(kmpEntryPoint.get<GetParticipantScheduleListUseCase>())
assertNotNull(kmpEntryPoint.get<ParticipateUseCase>())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import club.nito.core.model.AuthStatus
import club.nito.feature.auth.loginNavigationRoute
import club.nito.feature.auth.loginScreen
import club.nito.feature.auth.navigateToLogin
import club.nito.feature.schedule.navigateToSchedule
import club.nito.feature.schedule.scheduleScreen
import club.nito.feature.schedule.list.navigateToScheduleList
import club.nito.feature.schedule.list.scheduleListScreen
import club.nito.feature.settings.navigateToSettings
import club.nito.feature.settings.settingsScreen
import club.nito.feature.top.navigateToTop
Expand Down Expand Up @@ -41,7 +41,7 @@ fun NitoNavHost(
)

topScreen(
onScheduleListClick = navigator::navigateToSchedule,
onScheduleListClick = navigator::navigateToScheduleList,
onSettingsClick = navigator::navigateToSettings,
)
loginScreen(
Expand All @@ -56,7 +56,7 @@ fun NitoNavHost(
)
},
)
scheduleScreen()
scheduleListScreen()
settingsScreen(
onSignedOut = {
navigator.navigateToLogin(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package club.nito.core.data

import club.nito.core.model.Order
import club.nito.core.model.schedule.Schedule
import club.nito.core.model.schedule.ScheduleId
import club.nito.core.network.schedule.ScheduleRemoteDataSource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
Expand All @@ -25,8 +26,5 @@ public class OfflineFirstScheduleRepository(
after = after,
)

override fun scheduleFlow(id: String): Flow<Schedule> = flow {
// TODO: LocalDataSource
emit(remoteDataSource.getSchedule(id = id))
}
override suspend fun fetchSchedule(id: ScheduleId): Schedule = remoteDataSource.fetchSchedule(id = id)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package club.nito.core.data

import club.nito.core.model.Order
import club.nito.core.model.schedule.Schedule
import club.nito.core.model.schedule.ScheduleId
import kotlinx.coroutines.flow.Flow
import kotlinx.datetime.Instant

Expand All @@ -16,5 +17,8 @@ public sealed interface ScheduleRepository {
after: Instant? = null,
): List<Schedule>

public fun scheduleFlow(id: String): Flow<Schedule>
/**
* スケジュールを取得する
*/
public suspend fun fetchSchedule(id: ScheduleId): Schedule
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package club.nito.core.domain

import club.nito.core.data.ParticipantRepository
import club.nito.core.data.ScheduleRepository
import club.nito.core.data.UserRepository
import club.nito.core.domain.extension.toUserIdList
import club.nito.core.domain.model.ParticipantSchedule
import club.nito.core.model.FetchSingleContentResult
import club.nito.core.model.UserProfile
import club.nito.core.model.participant.Participant
import club.nito.core.model.schedule.Schedule
import club.nito.core.model.schedule.ScheduleId
import club.nito.core.model.toNitoError

/**
* ID を元にスケジュールを取得するユースケース
*/
public sealed interface FetchParticipantScheduleByIdUseCase {
public suspend operator fun invoke(id: ScheduleId): FetchSingleContentResult<ParticipantSchedule>
}

public class FetchParticipantScheduleByIdExecutor(
private val scheduleRepository: ScheduleRepository,
private val participantRepository: ParticipantRepository,
private val userRepository: UserRepository,
) : FetchParticipantScheduleByIdUseCase {
override suspend fun invoke(id: ScheduleId): FetchSingleContentResult<ParticipantSchedule> {
val schedule = try {
scheduleRepository.fetchSchedule(id = id)
} catch (e: Throwable) {
return FetchSingleContentResult.Failure(error = e.toNitoError())
}

val participants = participantRepository.getParticipants(id)
val profiles = userRepository.getProfiles(userIds = participants.toUserIdList())
val participantSchedule = transformToParticipantSchedule(
schedule = schedule,
participants = participants,
userProfiles = profiles,
)

return FetchSingleContentResult.Success(participantSchedule)
}

private fun transformToParticipantSchedule(
schedule: Schedule,
participants: List<Participant>,
userProfiles: List<UserProfile>,
): ParticipantSchedule {
val scheduleParticipants = participants.filter { it.scheduleId == schedule.id }
val scheduleParticipantProfiles = userProfiles.filter { profile ->
scheduleParticipants.any { it.userId == profile.id }
}

return ParticipantSchedule(
id = schedule.id,
scheduledAt = schedule.scheduledAt,
metAt = schedule.metAt,
venueId = schedule.venueId,
meetId = schedule.meetId,
description = schedule.description,
participants = scheduleParticipantProfiles,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package club.nito.core.domain.di

import club.nito.core.domain.AuthStatusStreamExecutor
import club.nito.core.domain.AuthStatusStreamUseCase
import club.nito.core.domain.FetchParticipantScheduleByIdExecutor
import club.nito.core.domain.FetchParticipantScheduleByIdUseCase
import club.nito.core.domain.GetParticipantScheduleListExecutor
import club.nito.core.domain.GetParticipantScheduleListUseCase
import club.nito.core.domain.GetRecentScheduleExecutor
Expand All @@ -24,6 +26,7 @@ public val useCaseModule: Module = module {
singleOf(::LoginExecutor) bind LoginUseCase::class
singleOf(::ModifyPasswordExecutor) bind ModifyPasswordUseCase::class
singleOf(::LogoutExecutor) bind LogoutUseCase::class
singleOf(::FetchParticipantScheduleByIdExecutor) bind FetchParticipantScheduleByIdUseCase::class
singleOf(::GetRecentScheduleExecutor) bind GetRecentScheduleUseCase::class
singleOf(::GetParticipantScheduleListExecutor) bind GetParticipantScheduleListUseCase::class
singleOf(::ParticipateExecutor) bind ParticipateUseCase::class
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package club.nito.core.domain.extension

import club.nito.core.model.participant.Participant

/**
* 重複を除いたユーザー ID のリストに変換する
*/
internal fun List<Participant>.toDistinctUserIdList(): List<String> = distinctBy { it.userId }.toUserIdList()

/**
* ユーザー ID のリストに変換する
*/
internal fun List<Participant>.toUserIdList(): List<String> = map { it.userId }
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package club.nito.core.domain.model

import club.nito.core.model.UserProfile
import club.nito.core.model.schedule.ScheduleId
import kotlinx.datetime.Instant

public data class ParticipantSchedule(
val id: String,
val id: ScheduleId,
val scheduledAt: Instant,
val metAt: Instant,
val venueId: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@ package club.nito.core.model.schedule

import kotlinx.datetime.Instant

/**
* スケジュールID
*/
public typealias ScheduleId = String

/**
* スケジュール
* @param id ID
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package club.nito.core.model.schedule

/**
* スケジュールID
*/
public typealias ScheduleId = String
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package club.nito.core.network.schedule

import club.nito.core.model.Order
import club.nito.core.model.schedule.Schedule
import club.nito.core.model.schedule.ScheduleId
import club.nito.core.network.schedule.model.NetworkSchedule
import club.nito.core.network.schedule.model.createFakeNetworkSchedule
import kotlinx.datetime.Clock
Expand All @@ -27,10 +28,10 @@ public data object FakeScheduleRemoteDataSource : ScheduleRemoteDataSource {
}.map(NetworkSchedule::toSchedule)
}

override suspend fun getSchedule(id: String): Schedule {
override suspend fun fetchSchedule(id: ScheduleId): Schedule {
return createFakeNetworkSchedule(
id = id,
scheduledAt = Clock.System.now(),
).toSchedule()
).let(NetworkSchedule::toSchedule)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package club.nito.core.network.schedule

import club.nito.core.model.Order
import club.nito.core.model.schedule.Schedule
import club.nito.core.model.schedule.ScheduleId
import kotlinx.datetime.Instant

public sealed interface ScheduleRemoteDataSource {
Expand All @@ -11,5 +12,8 @@ public sealed interface ScheduleRemoteDataSource {
after: Instant? = null,
): List<Schedule>

public suspend fun getSchedule(id: String): Schedule
/**
* リモートからスケジュールを取得する
*/
public suspend fun fetchSchedule(id: ScheduleId): Schedule
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package club.nito.core.network.schedule

import club.nito.core.model.Order
import club.nito.core.model.schedule.Schedule
import club.nito.core.model.schedule.ScheduleId
import club.nito.core.network.NetworkService
import club.nito.core.network.schedule.model.NetworkSchedule
import club.nito.core.network.toSupabaseOrder
Expand All @@ -10,6 +11,7 @@ import io.github.jan.supabase.postgrest.postgrest
import kotlinx.datetime.Instant

private enum class Column(val columnName: String) {
ID(columnName = "id"),
DELETED_AT(columnName = "deleted_at"),
SCHEDULED_AT(columnName = "scheduled_at"),
}
Expand Down Expand Up @@ -38,15 +40,16 @@ public class SupabaseScheduleRemoteDataSource(
.map(NetworkSchedule::toSchedule)
}

override suspend fun getSchedule(id: String): Schedule = networkService {
override suspend fun fetchSchedule(id: ScheduleId): Schedule = networkService {
postgrest
.select {
single()
filter {
eq(Column.ID.columnName, id)
exact(Column.DELETED_AT.columnName, null)
}
}
.decodeSingle<NetworkSchedule>()
.toSchedule()
.let(NetworkSchedule::toSchedule)
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package club.nito.feature.schedule.di

import club.nito.feature.schedule.ScheduleListViewModel
import club.nito.feature.schedule.list.ScheduleListStateMachine
import org.koin.core.module.Module
import org.koin.dsl.module

public val scheduleFeatureModule: Module = module {
factory {
ScheduleListViewModel(
getParticipantScheduleListUseCase = get(),
ScheduleListStateMachine(
getParticipantScheduleList = get(),
userMessageStateHolder = get(),
dateTimeFormatter = get(),
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 NOTE
Codebase verification is a beta feature.

ScheduleListViewModelからScheduleListStateMachineへの変更が確認されました。しかし、app/ios/Modules/Sources/Schedule/ComposeScheduleListScreen.swiftにおいてScheduleListViewModelの参照が残っているため、この部分の更新が必要です。新しいScheduleListStateMachineの使用は他のファイルで確認されています。

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package club.nito.feature.schedule
package club.nito.feature.schedule.list

public sealed class ScheduleListEvent {
public data class NavigateToScheduleDetail(val scheduleId: String) : ScheduleListEvent()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package club.nito.feature.schedule
package club.nito.feature.schedule.list

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

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package club.nito.feature.schedule
package club.nito.feature.schedule.list

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
Expand All @@ -21,36 +21,36 @@ import club.nito.core.ui.message.SnackbarMessageEffect
import club.nito.feature.schedule.component.ScheduleListSection

@Composable
public fun ScheduleRoute(
viewModel: ScheduleListViewModel = koinStateMachine(ScheduleListViewModel::class),
public fun ScheduleListRoute(
stateMachine: ScheduleListStateMachine = koinStateMachine(ScheduleListStateMachine::class),
) {
viewModel.event.collectAsState(initial = null).value?.let {
stateMachine.event.collectAsState(initial = null).value?.let {
LaunchedEffect(it.hashCode()) {
when (it) {
is ScheduleListEvent.NavigateToScheduleDetail -> {}
}
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,
)

ScheduleScreen(
ScheduleListScreen(
uiState = uiState,
snackbarHostState = snackbarHostState,
dispatch = viewModel::dispatch,
dispatch = stateMachine::dispatch,
)
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun ScheduleScreen(
private fun ScheduleListScreen(
uiState: ScheduleListScreenUiState,
snackbarHostState: SnackbarHostState,
dispatch: (ScheduleListIntent) -> Unit = {},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package club.nito.feature.schedule
package club.nito.feature.schedule.list
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 NOTE
Codebase verification is a beta feature.

パッケージ宣言がclub.nito.feature.scheduleからclub.nito.feature.schedule.listに変更されたことが確認されました。この変更は、以下のファイルに影響を与える可能性があります:

  • feature/schedule/build.gradle.kts: ネームスペースの宣言が古いパッケージ名を参照しています。
  • feature/schedule/src/commonMain/kotlin/club/nito/feature/schedule/di/ScheduleFeatureModule.kt: インポート文が新しいパッケージ構造を反映しているか確認が必要です。
  • app/shared/src/commonMain/kotlin/club/nito/app/shared/di/FeatureModules.ktapp/shared/src/commonMain/kotlin/club/nito/app/shared/NitoNavHost.kt: これらのファイルは古いパッケージ名をインポートしているため、更新が必要です。


import club.nito.core.common.NitoDateFormatter
import club.nito.core.domain.model.ParticipantSchedule
Expand Down
Loading