From a14722859d6ef367c7fb9cbfef85aca9db0c4080 Mon Sep 17 00:00:00 2001 From: Hyoeun Date: Tue, 17 Dec 2024 20:53:18 +0900 Subject: [PATCH] =?UTF-8?q?#11=20[Mod]=20MyPageViewModel,ProfileScreen=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../and/feature/mypage/MyPageViewModel.kt | 38 +++++++++------ .../sopt/and/feature/mypage/ProfileScreen.kt | 47 +++++++++++++------ 2 files changed, 56 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/org/sopt/and/feature/mypage/MyPageViewModel.kt b/app/src/main/java/org/sopt/and/feature/mypage/MyPageViewModel.kt index 505c71d..8418b08 100644 --- a/app/src/main/java/org/sopt/and/feature/mypage/MyPageViewModel.kt +++ b/app/src/main/java/org/sopt/and/feature/mypage/MyPageViewModel.kt @@ -1,31 +1,39 @@ -package org.sopt.and.feature.mypage +package org.sopt.and.feature.mypage.viewmodel -import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch +import org.sopt.and.core.component.BaseViewModel import org.sopt.and.domain.repository.MyPageRepository +import org.sopt.and.feature.mypage.model.MyPageContract.MyPageEvent +import org.sopt.and.feature.mypage.model.MyPageContract.MyPageSideEffect +import org.sopt.and.feature.mypage.model.MyPageContract.MyPageState import javax.inject.Inject @HiltViewModel class MyPageViewModel @Inject constructor( private val myPageRepository: MyPageRepository -) : ViewModel() { +) : BaseViewModel() { - private val _hobby = MutableStateFlow(null) - val hobby: StateFlow = _hobby.asStateFlow() + override fun createInitialState() = MyPageState() - fun loadHobby(token: String) { + override suspend fun handleEvent(event: MyPageEvent) { + when (event) { + is MyPageEvent.LoadHobby -> loadHobby(event.token) + } + } + + private fun loadHobby(token: String) { + setState { copy(isLoading = true) } viewModelScope.launch { - val result = myPageRepository.getMyHobby(token) - result.onSuccess { response -> - _hobby.value = response.hobby - }.onFailure { - _hobby.value = "데이터를 불러오는데 실패했습니다." - } + myPageRepository.getMyHobby(token) + .onSuccess { response -> + setState { copy(hobby = response.hobby, isLoading = false) } + } + .onFailure { + setState { copy(hobby = "", isLoading = false, error = "데이터를 불러오는데 실패했습니다.") } + setSideEffect { MyPageSideEffect.ShowErrorToast("데이터를 불러오는데 실패했습니다.") } + } } } } diff --git a/app/src/main/java/org/sopt/and/feature/mypage/ProfileScreen.kt b/app/src/main/java/org/sopt/and/feature/mypage/ProfileScreen.kt index 88393f1..6bb14e4 100644 --- a/app/src/main/java/org/sopt/and/feature/mypage/ProfileScreen.kt +++ b/app/src/main/java/org/sopt/and/feature/mypage/ProfileScreen.kt @@ -2,6 +2,7 @@ package org.sopt.and.feature.mypage import android.content.Context import android.util.Log +import android.widget.Toast import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column @@ -29,26 +30,39 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel +import kotlinx.coroutines.flow.collectLatest import org.sopt.and.R +import org.sopt.and.feature.mypage.model.MyPageContract +import org.sopt.and.feature.mypage.viewmodel.MyPageViewModel @Composable -fun ProfileScreen() { - val viewModel: MyPageViewModel = hiltViewModel() - val hobby by viewModel.hobby.collectAsState() +fun ProfileScreen(viewModel: MyPageViewModel = hiltViewModel()) { + val uiState by viewModel.uiState.collectAsState() val context = LocalContext.current LaunchedEffect(Unit) { val token = getAuthToken(context) if (token != null) { - viewModel.loadHobby(token) + viewModel.setEvent(MyPageContract.MyPageEvent.LoadHobby(token)) } else { - Log.e("MyPageScreen", "토근 못 찾음") + Log.e("ProfileScreen", "토큰 못 찾음") } } + + LaunchedEffect(Unit) { + viewModel.sideEffect.collectLatest { sideEffect -> + when (sideEffect) { + is MyPageContract.MyPageSideEffect.ShowErrorToast -> { + Toast.makeText(context, sideEffect.message, Toast.LENGTH_SHORT).show() + } + } + } + } + Column( modifier = Modifier .fillMaxSize() - .verticalScroll(rememberScrollState()), + .verticalScroll(rememberScrollState()) ) { Row( modifier = Modifier @@ -63,30 +77,35 @@ fun ProfileScreen() { alignment = Alignment.CenterStart ) Text( - hobby ?: "찾을 수 없습니다", + text = when { + uiState.isLoading -> "로딩 중..." + uiState.hobby.isNotEmpty() -> uiState.hobby + else -> "찾을 수 없습니다" + }, color = Color.White, + fontSize = 20.sp, modifier = Modifier .weight(1f) - .padding(end = 8.dp), - fontSize = 20.sp + .padding(end = 8.dp) ) Image( painter = painterResource(id = R.drawable.ic_alarm), - contentDescription = "alarm", + contentDescription = "Alarm Icon", modifier = Modifier.size(80.dp), alignment = Alignment.CenterEnd ) } + MyPagePurchase(stringResource(R.string.profile_first_purchase_description)) Spacer(modifier = Modifier.padding(top = 4.dp)) MyPagePurchase(stringResource(R.string.profile_no_ticket)) VideoList( - stringResource(R.string.profile_total_view_history), - stringResource(R.string.profile_no_view_history) + videoDescription = stringResource(R.string.profile_total_view_history), + emptyDescription = stringResource(R.string.profile_no_view_history) ) VideoList( - stringResource(R.string.profile_interest_program), - stringResource(R.string.profile_no_interest_program) + videoDescription = stringResource(R.string.profile_interest_program), + emptyDescription = stringResource(R.string.profile_no_interest_program) ) } }