diff --git a/feature/match/src/main/java/com/moya/funch/MatchScreen.kt b/feature/match/src/main/java/com/moya/funch/MatchScreen.kt new file mode 100644 index 00000000..ff3ab0c2 --- /dev/null +++ b/feature/match/src/main/java/com/moya/funch/MatchScreen.kt @@ -0,0 +1,94 @@ +package com.moya.funch + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Button +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.moya.funch.entity.SubwayStation +import com.moya.funch.entity.match.Chemistry +import com.moya.funch.entity.match.Recommend +import com.moya.funch.entity.profile.Profile + +@Composable +internal fun MatchRoute(onClose: () -> Unit, code: String, matchViewModel: MatchViewModel = hiltViewModel()) { + val uiState by matchViewModel.uiState.collectAsStateWithLifecycle() + val matchCode by matchViewModel.matchCode.collectAsStateWithLifecycle() + + LaunchedEffect(matchViewModel) { + matchViewModel.saveMatchCode(code) + } + + MatchScreen( + onClose = onClose, + memberCode = matchCode, + matchUiState = uiState + ) +} + +@Composable +private fun MatchScreen(onClose: () -> Unit, memberCode: String, matchUiState: MatchUiState) { + CompositionLocalProvider(LocalContentColor provides Color.White) { // @murjune TODO Delete this line + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + when (matchUiState) { + is MatchUiState.Loading -> Loading() + is MatchUiState.Error -> ErrorMatchContent(code = memberCode) + is MatchUiState.Success -> { + val (profile, similarity, chemistrys, recommends, subways) = matchUiState.matching + MatchContent( + profile = profile, + similarity = similarity, + chemistrys = chemistrys, + recommends = recommends, + subways = subways + ) + } + } + Button(onClick = onClose) { + Text("Close") + } + } + } +} + +@Composable +internal fun MatchContent( + profile: Profile, + similarity: Int, + chemistrys: List, + recommends: List, + subways: List +) { + Column { + Text("This is Match Screen") + Text(text = "Profile : $profile") + Text(text = "Similarity : $similarity") + Text(text = "Chemistrys : $chemistrys") + Text(text = "Recommends : $recommends") + Text(text = "Subways : $subways") + } +} + +@Composable +internal fun ErrorMatchContent(code: String) { + Text("There is no match code $code. Please try again.") +} + +@Composable +internal fun Loading() { + Text(text = "Loading...") +} diff --git a/feature/match/src/main/java/com/moya/funch/MatchViewModel.kt b/feature/match/src/main/java/com/moya/funch/MatchViewModel.kt new file mode 100644 index 00000000..b5a3a872 --- /dev/null +++ b/feature/match/src/main/java/com/moya/funch/MatchViewModel.kt @@ -0,0 +1,84 @@ +package com.moya.funch + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.moya.funch.entity.Blood +import com.moya.funch.entity.Club +import com.moya.funch.entity.Job +import com.moya.funch.entity.Mbti +import com.moya.funch.entity.SubwayLine +import com.moya.funch.entity.SubwayStation +import com.moya.funch.entity.match.Chemistry +import com.moya.funch.entity.match.Matching +import com.moya.funch.entity.match.Recommend +import com.moya.funch.entity.profile.Profile +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.mapLatest +import kotlinx.coroutines.flow.stateIn + +@HiltViewModel +class MatchViewModel @Inject constructor( +// private val matchProfileUseCase : MatchProfileUseCase, + private val savedStateHandle: SavedStateHandle +) : ViewModel() { + + val matchCode: StateFlow = savedStateHandle.getStateFlow(MATCH_CODE, "") + + val uiState: StateFlow = matchCode.mapLatest { code -> + if (code.isEmpty()) { + MatchUiState.Loading + } else { + // MatchUiState.Success(matchProfileUseCase("1", it)) + // TODO : Remove 목 데이터, delay + delay(1000L) + MatchUiState.Success(MOCK_MATCHING) + } + }.catch { + emit(MatchUiState.Error) + }.stateIn(viewModelScope, started = SharingStarted.WhileSubscribed(5000), initialValue = MatchUiState.Loading) + + fun saveMatchCode(code: String) { + savedStateHandle[MATCH_CODE] = code + } + + companion object { + private const val MATCH_CODE = "matchCode" + + // id: 65c27d3232e6054951260d3d, code: V3H5, device : bbb + // id: 65c27d8b32e6054951260d3e, code: 6V2Q, device: ccc + private val MOCK_MATCHING = Matching( + profile = Profile().copy( + name = "abc", + job = Job.DEVELOPER, + clubs = listOf(Club.NEXTERS), + mbti = Mbti.INFP, + blood = Blood.A, + subways = listOf( + SubwayStation("목동역", lines = listOf(SubwayLine.FIVE)) + ) + ), + similarity = 80, + chemistrys = listOf( + Chemistry("대한민국 선수분들", "정말 고생 많으셨습니다...") + ), + recommends = listOf( + Recommend("지금은"), + Recommend("새벽"), + Recommend("3시"), + Recommend("48뷴") + ) + ) + } +} + +sealed class MatchUiState { + data object Loading : MatchUiState() + data object Error : MatchUiState() + data class Success(val matching: Matching) : MatchUiState() +} diff --git a/feature/match/src/main/java/com/moya/funch/navigation/MatchNavigatoin.kt b/feature/match/src/main/java/com/moya/funch/navigation/MatchNavigatoin.kt new file mode 100644 index 00000000..f4d59192 --- /dev/null +++ b/feature/match/src/main/java/com/moya/funch/navigation/MatchNavigatoin.kt @@ -0,0 +1,33 @@ +package com.moya.funch.navigation + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavOptions +import androidx.navigation.NavType +import androidx.navigation.compose.composable +import androidx.navigation.navArgument +import com.moya.funch.MatchRoute + +private const val MATCH_ROUTE = "match/{code}" +private const val MEMBER_CODE_KEY = "code" +private const val NO_MEMBER_CODE = "no member code" + +fun NavController.navigateToMatching(memberCode: String, navOptions: NavOptions? = null) = + navigate(createMatchRoute(memberCode), navOptions) + +fun NavGraphBuilder.matchingScreen(onClose: () -> Unit) { + composable( + route = MATCH_ROUTE, + arguments = listOf( + navArgument(MEMBER_CODE_KEY) { + type = NavType.StringType + defaultValue = NO_MEMBER_CODE + } + ) + ) { backStackEntry -> + val code = backStackEntry.arguments?.getString(MEMBER_CODE_KEY) ?: NO_MEMBER_CODE + MatchRoute(code = code, onClose = onClose) + } +} + +private fun createMatchRoute(memberCode: String) = MATCH_ROUTE.replace("{$MEMBER_CODE_KEY}", memberCode)