diff --git a/app/src/main/java/DMNavHost.kt b/app/src/main/java/DMNavHost.kt index 67ad673..5704dbc 100644 --- a/app/src/main/java/DMNavHost.kt +++ b/app/src/main/java/DMNavHost.kt @@ -9,7 +9,6 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.rememberNavController import view.Mypage.navigation.MyScreen -import view.Mypage.navigation.navGationToMyPage import view.login.navigation.LoginScreen import view.login.navigation.navigateToLogin @@ -20,11 +19,15 @@ fun DMNavHost( startDestination: String ){ + NavHost(navController = navController, startDestination =startDestination ){ LoginScreen(navigateToHome = navController::navigateToLogin) - MyScreen(navGationToMyPage = navController::popBackStack) + MyScreen( + navigationBack = navController::popBackStack, + onErrorToast = { throwable, message ->} + ) } } \ No newline at end of file diff --git a/data/src/main/java/remote/api/auth/UsersAPi.kt b/data/src/main/java/remote/api/auth/UsersAPi.kt index 93facbb..f900534 100644 --- a/data/src/main/java/remote/api/auth/UsersAPi.kt +++ b/data/src/main/java/remote/api/auth/UsersAPi.kt @@ -9,7 +9,7 @@ interface UsersAPi { @GET("/{user_id}/profile") suspend fun getUsers( @Path("user_id") userId: UUID - ): List + ): UsersResponse diff --git a/data/src/main/java/remote/datasource/users/UsersDataSource.kt b/data/src/main/java/remote/datasource/users/UsersDataSource.kt index 996660e..10ef05c 100644 --- a/data/src/main/java/remote/datasource/users/UsersDataSource.kt +++ b/data/src/main/java/remote/datasource/users/UsersDataSource.kt @@ -5,5 +5,5 @@ import remote.dto.users.response.UsersResponse import java.util.UUID interface UsersDataSource { - fun getUsers( userId: UUID): Flow> -} + fun getUsers( userId: UUID): Flow +} \ No newline at end of file diff --git a/data/src/main/java/remote/datasource/users/UsersDataSourceImpl.kt b/data/src/main/java/remote/datasource/users/UsersDataSourceImpl.kt index fbecef3..f021b28 100644 --- a/data/src/main/java/remote/datasource/users/UsersDataSourceImpl.kt +++ b/data/src/main/java/remote/datasource/users/UsersDataSourceImpl.kt @@ -11,6 +11,8 @@ class UsersDataSourceImpl @Inject constructor( private val usersService: UsersAPi ): UsersDataSource { - override fun getUsers(userId: UUID): Flow> = - performApiRequest { usersService.getUsers(userId = userId) } + override fun getUsers( + userId: UUID + ): Flow = + performApiRequest { usersService.getUsers( userId = userId) } } \ No newline at end of file diff --git a/data/src/main/java/remote/dto/myrank/response/MyRankResponse.kt b/data/src/main/java/remote/dto/myrank/response/MyRankResponse.kt index 0510847..640b7cf 100644 --- a/data/src/main/java/remote/dto/myrank/response/MyRankResponse.kt +++ b/data/src/main/java/remote/dto/myrank/response/MyRankResponse.kt @@ -11,6 +11,7 @@ data class MyRankResponse ( @Json(name = "userId") val userId: UUID, @Json(name = "rank") val rank: Int, @Json(name = "profileImage") val profileImage: String, + @Json(name = "roomNum") val roomNum: Int, @Json(name = "name") val name: String, @Json(name = "penaltyPoint") val penaltyPoint: Int, ) @@ -21,6 +22,7 @@ fun MyRankResponse.toModel() = MyRankResponseModel( rank = rank, profileImage = profileImage, name = name, - penaltyPoint = penaltyPoint + penaltyPoint = penaltyPoint, + roomNum = roomNum ) diff --git a/data/src/main/java/remote/dto/rank/response/RankResponse.kt b/data/src/main/java/remote/dto/rank/response/RankResponse.kt index 2767f7a..9f7137d 100644 --- a/data/src/main/java/remote/dto/rank/response/RankResponse.kt +++ b/data/src/main/java/remote/dto/rank/response/RankResponse.kt @@ -11,11 +11,13 @@ data class RankResponse( @Json(name = "rank") val rank: Int, @Json(name = "name") val name: String, @Json(name = "penaltyPoint") val penaltyPoint: Int, + @Json(name = "roomNum") val roomNum: Int, ) fun RankResponse.toModel() = RankResponseModel( userId = userId, rank = rank, name = name, - penaltyPoint = penaltyPoint + penaltyPoint = penaltyPoint, + roomNum = roomNum ) \ No newline at end of file diff --git a/data/src/main/java/remote/dto/users/response/UsersResponse.kt b/data/src/main/java/remote/dto/users/response/UsersResponse.kt index 3d83aea..13c81e0 100644 --- a/data/src/main/java/remote/dto/users/response/UsersResponse.kt +++ b/data/src/main/java/remote/dto/users/response/UsersResponse.kt @@ -15,6 +15,7 @@ data class UsersResponse ( @Json(name = "myBecause") val myBecause: String, @Json(name = "because") val because: String, @Json(name = "Point-List") val pointList: Int, + @Json(name = "roomNum") val roomNum: Int, ) fun UsersResponse.toModel() = UsersResponseModel( @@ -25,5 +26,6 @@ fun UsersResponse.toModel() = UsersResponseModel( penaltyPoint = penaltyPoint, myBecause = myBecause, because = because, - pointList = pointList + pointList = pointList, + roomNum = roomNum ) \ No newline at end of file diff --git a/data/src/main/java/repoistory/UsersRepositoryImpl.kt b/data/src/main/java/repoistory/UsersRepositoryImpl.kt index 778391e..552a586 100644 --- a/data/src/main/java/repoistory/UsersRepositoryImpl.kt +++ b/data/src/main/java/repoistory/UsersRepositoryImpl.kt @@ -12,8 +12,7 @@ import javax.inject.Inject class UsersRepositoryImpl @Inject constructor( private val usersDataSource: UsersDataSource ): UsersRepository { - - override suspend fun getUsers(userId: UUID): Flow> { - return usersDataSource.getUsers(userId = userId).map { list -> list.map { it.toModel() } } + + override suspend fun getUsers(userId: UUID): Flow { + return usersDataSource.getUsers(userId = userId).map { it.toModel() } } } -} \ No newline at end of file diff --git a/domain/src/main/java/model/myrank/response/MyRankResponseModel.kt b/domain/src/main/java/model/myrank/response/MyRankResponseModel.kt index 2733758..c24fb32 100644 --- a/domain/src/main/java/model/myrank/response/MyRankResponseModel.kt +++ b/domain/src/main/java/model/myrank/response/MyRankResponseModel.kt @@ -8,4 +8,5 @@ data class MyRankResponseModel( val name: String, val penaltyPoint: Int, val profileImage: String, + val roomNum: Int, ) \ No newline at end of file diff --git a/domain/src/main/java/model/rank/response/RankResponseModel.kt b/domain/src/main/java/model/rank/response/RankResponseModel.kt index cb71e75..797123a 100644 --- a/domain/src/main/java/model/rank/response/RankResponseModel.kt +++ b/domain/src/main/java/model/rank/response/RankResponseModel.kt @@ -7,4 +7,5 @@ data class RankResponseModel( val rank: Int, val name: String, val penaltyPoint: Int, + val roomNum: Int, ) \ No newline at end of file diff --git a/domain/src/main/java/model/users/response/UsersResponseModel.kt b/domain/src/main/java/model/users/response/UsersResponseModel.kt index e05e2e6..e5faed5 100644 --- a/domain/src/main/java/model/users/response/UsersResponseModel.kt +++ b/domain/src/main/java/model/users/response/UsersResponseModel.kt @@ -11,4 +11,5 @@ data class UsersResponseModel ( val myBecause: String, val because: String, val pointList: Int, + val roomNum: Int, ) \ No newline at end of file diff --git a/domain/src/main/java/reopoistory/UsersRepository.kt b/domain/src/main/java/reopoistory/UsersRepository.kt index 10e9a19..4fb06a6 100644 --- a/domain/src/main/java/reopoistory/UsersRepository.kt +++ b/domain/src/main/java/reopoistory/UsersRepository.kt @@ -5,6 +5,6 @@ import model.users.response.UsersResponseModel import java.util.UUID interface UsersRepository { - - suspend fun getUsers(userId: UUID): Flow> + + suspend fun getUsers(userId: UUID): Flow } \ No newline at end of file diff --git a/domain/src/main/java/usecase/Users/GetUsersUseCase.kt b/domain/src/main/java/usecase/Users/GetUsersUseCase.kt index 3baaa72..b62cce6 100644 --- a/domain/src/main/java/usecase/Users/GetUsersUseCase.kt +++ b/domain/src/main/java/usecase/Users/GetUsersUseCase.kt @@ -9,6 +9,6 @@ import javax.inject.Inject class GetUsersUseCase @Inject constructor( private val usersRepository: UsersRepository ){ - suspend operator fun invoke(userId: UUID): Flow> = + suspend operator fun invoke(userId: UUID): Flow = usersRepository.getUsers(userId = userId) } \ No newline at end of file diff --git a/presentation/src/main/java/view/Mypage/Screen/MyPage.kt b/presentation/src/main/java/view/Mypage/Screen/MyPage.kt index aa8a524..bea41b5 100644 --- a/presentation/src/main/java/view/Mypage/Screen/MyPage.kt +++ b/presentation/src/main/java/view/Mypage/Screen/MyPage.kt @@ -1,140 +1,113 @@ package view.Mypage.Screen +import androidx.activity.ComponentActivity import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Text +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import model.users.response.UsersResponseModel +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import view.Mypage.component.DemeritList import view.Mypage.component.MyDemeritList import view.Mypage.component.MyClean +import viewmodel.users.UsersViewModel +import viewmodel.users.uistate.UsersUiState import java.util.UUID +@Composable +internal fun MyPageRoute( + modifier: Modifier = Modifier, + onErrorToast: (throwable: Throwable?, message: Int?) -> Unit, + viewModel: UsersViewModel = hiltViewModel(LocalContext.current as ComponentActivity), + navigateToBack: () -> Unit, +) { + val usersUiState by viewModel.usersUiState.collectAsStateWithLifecycle() + + MyPage( + modifier = modifier, + onErrorToast = onErrorToast, + navigateToBack = navigateToBack, + usersUiState = usersUiState, + getUserCallBack = viewModel::getUsers, + ) + +} + @Composable fun MyPage( modifier: Modifier = Modifier, - data:UsersResponseModel + onErrorToast: (throwable: Throwable?, message: Int?) -> Unit, + navigateToBack: () -> Unit, + usersUiState: UsersUiState, + getUserCallBack: (UUID) -> Unit, +) { + val scrollState = rememberScrollState() + var uuid by remember { mutableStateOf(UUID.randomUUID()) } - ) { + LaunchedEffect(Unit) { + getUserCallBack(uuid) + } Column( modifier = modifier .fillMaxSize() + .verticalScroll(scrollState) .background(color = Color(0xFF1E1E1E)) ) { Column( - modifier = Modifier.fillMaxWidth(), - verticalArrangement = Arrangement.Top, + modifier = Modifier + .fillMaxWidth() + .padding( + horizontal = 20.dp, + vertical = 16.dp, + ), + verticalArrangement = Arrangement.spacedBy(10.dp, Alignment.Top), horizontalAlignment = Alignment.Start, ) { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(start = 20.dp, end = 235.dp), - horizontalAlignment = Alignment.Start, - ) { - Text( - text = "안녕하세요", style = TextStyle( - fontSize = 20.sp, - fontWeight = FontWeight(600), - color = Color(0xFFFFFFFF), - ) - ) - Text( - text = AnnotatedString.Builder("${data.name}님").apply { - addStyle( - style = SpanStyle( - color = Color(0xFF9BFFA6), fontSize = 27.sp // 이산 부분의 글자 크기 설정 - ), - start = 0, end = 2 - ) - }. - toAnnotatedString(), style = TextStyle( - fontSize = 22.sp, // 기본 글자 크기 - fontWeight = FontWeight(900), - color = Color(0xFFFFFFFF), - textAlign = TextAlign.Start - ) - ) - } - Column( - modifier = Modifier - .fillMaxWidth() - .padding( - horizontal = 20.dp, - vertical = 16.dp, - ), - verticalArrangement = Arrangement.spacedBy(10.dp, Alignment.Top), - horizontalAlignment = Alignment.Start, - ) { - MyClean( - modifier = modifier, - data.todayClean, - data.penaltyPoint, - data.cleanPoint, - ) - - } - Column( - modifier = Modifier - .fillMaxWidth() - .padding(start = 20.dp, end = 20.dp, bottom = 16.dp), - verticalArrangement = Arrangement.spacedBy(10.dp, Alignment.Top), - horizontalAlignment = Alignment.Start, - ) { - MyDemeritList( - modifier = modifier, - data.myBecause, - data.penaltyPoint, - ) - } - Column( - modifier = Modifier - .fillMaxWidth() - .padding(start = 20.dp, end = 20.dp), - verticalArrangement = Arrangement.spacedBy(10.dp, Alignment.Top), - horizontalAlignment = Alignment.Start, - ) { - DemeritList( - modifier = modifier, - data.because, - data.pointList, - ) - } + MyClean( + usersUiState = usersUiState, + onErrorToast = onErrorToast, + modifier = modifier, + ) + } + Column( + modifier = Modifier + .fillMaxWidth() + .padding(start = 20.dp, end = 20.dp, bottom = 16.dp), + verticalArrangement = Arrangement.spacedBy(10.dp, Alignment.Top), + horizontalAlignment = Alignment.Start, + ) { + MyDemeritList( + usersUiState = usersUiState, + onErrorToast = onErrorToast, + modifier = modifier, + ) + } + Column( + modifier = Modifier + .fillMaxWidth() + .padding(start = 20.dp, end = 20.dp), + verticalArrangement = Arrangement.spacedBy(10.dp, Alignment.Top), + horizontalAlignment = Alignment.Start, + ) { + DemeritList( + usersUiState = usersUiState, + onErrorToast = onErrorToast, + ) } } } - -@Composable -@Preview -fun PreviewMyPage() { - MyPage( - data = UsersResponseModel( - because = "노트북", - cleanPoint = 3, - myBecause = "노트북", - pointList = 3, - name = "이산", - penaltyPoint = 1, - todayClean = "화장실", - userId = UUID.randomUUID(), - - - - ) - ) -} \ No newline at end of file diff --git a/presentation/src/main/java/view/Mypage/component/DemeritList.kt b/presentation/src/main/java/view/Mypage/component/DemeritList.kt index 9077386..00e7953 100644 --- a/presentation/src/main/java/view/Mypage/component/DemeritList.kt +++ b/presentation/src/main/java/view/Mypage/component/DemeritList.kt @@ -1,84 +1,113 @@ package view.Mypage.component -import androidx.compose.runtime.Composable + +import androidx.compose.animation.* import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon import androidx.compose.material3.Text +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.kim.presentation.R - - +import model.users.response.UsersResponseModel +import viewmodel.users.uistate.UsersUiState @Composable -fun DemeritList( +internal fun DemeritList( modifier: Modifier = Modifier, - because: String, - pointList: Int, + usersUiState: UsersUiState, + onErrorToast: (throwable: Throwable?, message: Int?) -> Unit, ){ - Column ( + when (usersUiState) { + is UsersUiState.Fail -> { + onErrorToast(usersUiState.exception, R.string.error) + } + is UsersUiState.Success -> { + val data = usersUiState.data + DemeritComponent( + modifier = modifier, + data = data + ) + } + is UsersUiState.Loading -> { + + } + is UsersUiState.Empty ->{ + } + } +} +@Composable +fun DemeritComponent( + modifier: Modifier = Modifier, + data: UsersResponseModel +) { + var isExpanded by remember { mutableStateOf(false) } + + Column( modifier = modifier .fillMaxWidth() .background(color = Color(0xFF252525), shape = RoundedCornerShape(size = 10.dp)) - .padding( - horizontal = 16.dp, - vertical = 12.dp - ), - verticalArrangement = Arrangement.spacedBy(10.dp, Alignment.Top), - horizontalAlignment = Alignment.Start, - ){ - Column( + .padding(horizontal = 16.dp, vertical = 12.dp) + ) { + + Row( modifier = Modifier.fillMaxWidth(), - verticalArrangement = Arrangement.spacedBy(8.dp, Alignment.Top), - horizontalAlignment = Alignment.Start, - ){ - Column ( - modifier = Modifier.fillMaxWidth() - ){ - Text( - text = "벌점 리스트", - style = TextStyle( - fontSize = 16.sp, - fontWeight = FontWeight(600), - color = Color(0xFFFFFFFF), - ) - ) - } + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "벌점 리스트", + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + color = Color.White + ), + modifier = Modifier.weight(1f) + ) + + + Icon( + modifier = Modifier.clickable { isExpanded = !isExpanded }, + painter = painterResource(id = if (isExpanded) R.drawable.down else R.drawable.up), + contentDescription = "Expand Toggle", + tint = Color.White + ) + } + + + AnimatedVisibility( + visible = isExpanded, + enter = expandVertically() + fadeIn(), + exit = shrinkVertically() + fadeOut() + ) { Column( modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(2.dp, Alignment.Top), - horizontalAlignment = Alignment.Start, - ){ + horizontalAlignment = Alignment.Start + ) { Text( text = stringResource( R.string.stringResource, - because, - pointList, + data.myBecause, + data.penaltyPoint ), style = TextStyle( fontSize = 14.sp, - fontWeight = FontWeight(500), - color = Color(0xFFC1C1C1), - ) + fontWeight = FontWeight.Medium, + color = Color(0xFFC1C1C1) + ), + modifier = Modifier.padding(top = 8.dp) ) } } } } -@Composable -@Preview -fun PreviewDemeritList(){ - DemeritList( - because = "노트북", - pointList = 1, - ) -} \ No newline at end of file + + diff --git a/presentation/src/main/java/view/Mypage/component/MyClean.kt b/presentation/src/main/java/view/Mypage/component/MyClean.kt index a80b02a..65acb11 100644 --- a/presentation/src/main/java/view/Mypage/component/MyClean.kt +++ b/presentation/src/main/java/view/Mypage/component/MyClean.kt @@ -4,7 +4,9 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text @@ -12,113 +14,213 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.kim.presentation.R +import model.users.response.UsersResponseModel +import view.theme.DoMaAndroidTheme +import viewmodel.users.uistate.UsersUiState @Composable fun MyClean( modifier: Modifier = Modifier, - toDayClean: String, - penaltyPoint: Int, - cleanPoint: Int, + usersUiState: UsersUiState, + onErrorToast: (throwable: Throwable?, message: Int?) -> Unit, ) { - Row( - modifier = modifier - .fillMaxWidth() - .background(color = Color(0xFF252525), shape = RoundedCornerShape(size = 10.dp)) - .padding(start = 10.dp, top = 16.dp, end = 20.dp, bottom = 16.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - // 오늘의 청소 구역 - Column( - verticalArrangement = Arrangement.spacedBy(4.dp), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Text( - text = "오늘의 청소 구역", - style = TextStyle( - fontSize = 13.sp, - fontWeight = FontWeight.W500, - color = Color.White, - ) - ) - Text( - text = toDayClean, - style = TextStyle( - fontSize = 13.sp, - fontWeight = FontWeight.W500, - color = Color.White, - ) - ) + when (usersUiState) { + is UsersUiState.Fail -> { + onErrorToast(usersUiState.exception, R.string.error) } - // 벌점 - Column( - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Text( - text = "벌점", - style = TextStyle( - fontSize = 14.sp, - fontWeight = FontWeight.W500, - color = Color.White, - textAlign = TextAlign.Center, - ) - ) - Text( - text = "${penaltyPoint}점", - style = TextStyle( - fontSize = 16.sp, - fontWeight = FontWeight.W600, - color = Color.White, - textAlign = TextAlign.Center - ) + is UsersUiState.Success -> { + val data = usersUiState.data + MyCleanComponent( + modifier = modifier, + data = data ) } + is UsersUiState.Loading -> { + + } + is UsersUiState.Empty ->{ + + } + } +} - // 남은 청소 +@Composable +fun MyCleanComponent( + modifier: Modifier = Modifier, + data: UsersResponseModel, +) { + DoMaAndroidTheme { colors, typography -> Column( - verticalArrangement = Arrangement.spacedBy(4.dp), - horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.fillMaxWidth(), + verticalArrangement = Arrangement.Top, + horizontalAlignment = Alignment.Start, ) { - Text( - text = "남은 청소", - style = TextStyle( - fontSize = 14.sp, - fontWeight = FontWeight.W500, - color = Color.White, - textAlign = TextAlign.Center, + Column( + modifier = Modifier + .fillMaxWidth() + .padding(start = 20.dp, end = 235.dp), + horizontalAlignment = Alignment.Start, + ) { + Text( + text = "안녕하세요", style = TextStyle( + fontSize = 20.sp, + fontWeight = FontWeight(600), + color = colors.WHITE, + ) ) - ) - Text( - text = stringResource( - R.string.CleanResource, - cleanPoint - ), - style = TextStyle( - fontSize = 15.sp, - fontWeight = FontWeight.W600, - color = Color.White, - textAlign = TextAlign.Center, + Text( + text = AnnotatedString.Builder("${data.name}님").apply { + addStyle( + style = SpanStyle( + color = colors.GRAY, fontSize = 27.sp // 이산 부분의 글자 크기 설정 + ), + start = 0, end = 2 + ) + }.toAnnotatedString(), style = TextStyle( + fontSize = 22.sp, + fontWeight = FontWeight(900), + color = colors.WHITE, + textAlign = TextAlign.Start + ) ) - ) + } + Column( + modifier = modifier + .fillMaxWidth() + .background(color = Color(0xFF252525), shape = RoundedCornerShape(size = 10.dp)) + .padding(start = 16.dp, top = 16.dp, end = 16.dp, bottom = 16.dp), + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.Top + ) { + + // 호실 + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "호실", + style = TextStyle( + fontSize = 14.sp, + fontFamily = typography.bodySmall.fontFamily, + fontWeight = FontWeight.W500, + color = colors.WHITE + ), + modifier = Modifier.weight(1f) + ) + Text( + text = "${data.roomNum}호", + style = TextStyle( + fontSize = 14.sp, + fontFamily = typography.bodySmall.fontFamily, + fontWeight = FontWeight.W500, + color = colors.GRAY, + textAlign = TextAlign.End + ), + modifier = Modifier.weight(1f) + ) + } + + Spacer(modifier = Modifier.height(8.dp)) + + // 남은 청소 + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "남은 청소", + style = TextStyle( + fontSize = 14.sp, + fontFamily = typography.bodySmall.fontFamily, + fontWeight = FontWeight.W500, + color = colors.WHITE + ), + modifier = Modifier.weight(1f) + ) + Text( + text = "${data.cleanPoint}회", + style = TextStyle( + fontSize = 14.sp, + fontFamily = typography.bodySmall.fontFamily, + fontWeight = FontWeight.W500, + color = colors.GRAY, + textAlign = TextAlign.End + ), + modifier = Modifier.weight(1f) + ) + } + + Spacer(modifier = Modifier.height(8.dp)) + + // 벌점 + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "벌점", + style = TextStyle( + fontSize = 14.sp, + fontFamily = typography.bodySmall.fontFamily, + fontWeight = FontWeight.W500, + color = colors.WHITE + ), + modifier = Modifier.weight(1f) + ) + Text( + text = "${data.penaltyPoint}점", + style = TextStyle( + fontSize = 14.sp, + fontFamily = typography.bodySmall.fontFamily, + fontWeight = FontWeight.W500, + color = colors.GRAY, + textAlign = TextAlign.End + ), + modifier = Modifier.weight(1f) + ) + } + + Spacer(modifier = Modifier.height(8.dp)) + + // 오늘의 청소 + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "오늘의 청소", + style = TextStyle( + fontSize = 14.sp, + fontFamily = typography.bodySmall.fontFamily, + fontWeight = FontWeight.W500, + color = colors.WHITE + ), + modifier = Modifier.weight(1f) + ) + Text( + text = "${data.todayClean}학년", + style = TextStyle( + fontSize = 14.sp, + fontFamily = typography.bodySmall.fontFamily, + fontWeight = FontWeight.W500, + color = colors.GRAY, + textAlign = TextAlign.End + ), + modifier = Modifier.weight(1f) + ) + } + } } } } -@Composable -@Preview -fun PreviewMyClean() { - MyClean( - penaltyPoint = 1, - toDayClean = "3층 화장실", - cleanPoint = 4 - ) -} \ No newline at end of file diff --git a/presentation/src/main/java/view/Mypage/component/MyDemeritList.kt b/presentation/src/main/java/view/Mypage/component/MyDemeritList.kt index 6abcad8..7615dea 100644 --- a/presentation/src/main/java/view/Mypage/component/MyDemeritList.kt +++ b/presentation/src/main/java/view/Mypage/component/MyDemeritList.kt @@ -1,17 +1,29 @@ package view.Mypage.component +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.expandVertically +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.shrinkVertically import androidx.compose.runtime.Composable import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon import androidx.compose.material3.Text +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight @@ -19,66 +31,118 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.kim.presentation.R +import model.users.response.UsersResponseModel +import viewmodel.users.uistate.UsersUiState +import java.util.UUID +@Composable +internal fun MyDemeritList( + modifier: Modifier = Modifier, + usersUiState: UsersUiState, + onErrorToast: (throwable: Throwable?, message: Int?) -> Unit, +){ + when (usersUiState) { + is UsersUiState.Fail -> { + onErrorToast(usersUiState.exception, R.string.error) + } + + is UsersUiState.Success -> { + val data = usersUiState.data + MyDemeritComponent( + modifier = modifier, + data = data + ) + } + is UsersUiState.Empty ->{ + + } + is UsersUiState.Loading -> { + + } + } +} @Composable -fun MyDemeritList( +fun MyDemeritComponent( modifier: Modifier = Modifier, - myBecause: String, - myPointList: Int + data: UsersResponseModel ) { - Row( + var isExpanded by remember { mutableStateOf(false) } // 펼쳐짐 상태 관리 + + Column( modifier = modifier .fillMaxWidth() .background(color = Color(0xFF252525), shape = RoundedCornerShape(size = 10.dp)) - .padding( - horizontal = 16.dp, - vertical = 12.dp - ), - horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.Start), - verticalAlignment = Alignment.CenterVertically, + .padding(horizontal = 16.dp, vertical = 12.dp) ) { - Column( - verticalArrangement = Arrangement.spacedBy(8.dp, Alignment.Top), - horizontalAlignment = Alignment.Start, - ) { - Text( - text = "나의 벌점 내역", - style = TextStyle( - fontSize = 16.sp, - fontWeight = FontWeight(600), - color = Color(0xFFFFFFFF), - ) - ) - } + // 헤더: 클릭하면 펼쳐짐/접힘 전환 + Row( + modifier = Modifier + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "나의 벌점 내역", + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + color = Color.White + ), + modifier = Modifier.weight(1f) + ) + + // 펼쳐짐/접힘 아이콘 + Icon( + modifier = Modifier + .clickable { isExpanded = !isExpanded }, + painter = painterResource(id = if (isExpanded) R.drawable.up else R.drawable.down), + contentDescription = "Expand Toggle", + + tint = Color.White + ) + } + + // 애니메이션 적용된 벌점 내역 + AnimatedVisibility( + visible = isExpanded, + enter = expandVertically() + fadeIn(), + exit = shrinkVertically() + fadeOut() + ) { Column( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier.fillMaxWidth().padding(top = 8.dp), verticalArrangement = Arrangement.spacedBy(2.dp, Alignment.Top), - horizontalAlignment = Alignment.Start, + horizontalAlignment = Alignment.Start ) { Text( text = stringResource( R.string.DemeritList, - myBecause, - myPointList - + data.myBecause, + data.pointList ), style = TextStyle( fontSize = 14.sp, - fontWeight = FontWeight(500), - color = Color(0xFFD4D4D4), + fontWeight = FontWeight.Medium, + color = Color(0xFFD4D4D4) ) ) - } } } - +} @Composable @Preview -fun PreviewMyDemeritList() { - MyDemeritList( - myBecause = "노트북", - myPointList = 3, +fun PreviewMyDemeritComponent() { + MyDemeritComponent( + data = UsersResponseModel( + penaltyPoint = 3, + myBecause = "청소", + because = "청소", + cleanPoint = 0, + todayClean = "호날두", + roomNum = 0, + name = "김재관", + userId = UUID.randomUUID(), + pointList = 3 + ) ) -} \ No newline at end of file +} diff --git a/presentation/src/main/java/view/Mypage/navigation/MyPageNavigation.kt b/presentation/src/main/java/view/Mypage/navigation/MyPageNavigation.kt index 5c85f5c..47c2789 100644 --- a/presentation/src/main/java/view/Mypage/navigation/MyPageNavigation.kt +++ b/presentation/src/main/java/view/Mypage/navigation/MyPageNavigation.kt @@ -3,19 +3,24 @@ package view.Mypage.navigation import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable +import view.Mypage.Screen.MyPage +import view.Mypage.Screen.MyPageRoute const val MyPage_loute = "Mypage_loute" -fun NavController.navGationToMyPage() { +fun NavController.navigationToMyPage() { this.navigate(MyPage_loute) } - fun NavGraphBuilder.MyScreen( - navGationToMyPage: () -> Unit + navigationBack: () -> Unit, + onErrorToast: (throwable: Throwable?, message: Int?) -> Unit, ) { composable(MyPage_loute) { - MyScreen(navGationToMyPage = navGationToMyPage) + MyPageRoute( + onErrorToast = onErrorToast, + navigateToBack = navigationBack, + ) } } \ No newline at end of file diff --git a/presentation/src/main/java/view/main/component/Rankingcomponent.kt b/presentation/src/main/java/view/main/component/Rankingcomponent.kt index b6c6fe9..ffd7bec 100644 --- a/presentation/src/main/java/view/main/component/Rankingcomponent.kt +++ b/presentation/src/main/java/view/main/component/Rankingcomponent.kt @@ -139,13 +139,10 @@ internal fun RankingListItem( data = data ) } - } - } } - @Composable @Preview fun PreviewRankingComponent() { @@ -154,9 +151,8 @@ fun PreviewRankingComponent() { rank = 3, name = "김재관", penaltyPoint = 5, - userId = UUID.randomUUID() + userId = UUID.randomUUID(), + roomNum = 3 ) - - ) } \ No newline at end of file diff --git a/presentation/src/main/java/view/theme/DomaAndroidTheme.kt b/presentation/src/main/java/view/theme/DomaAndroidTheme.kt index 648c117..bf8c3b2 100644 --- a/presentation/src/main/java/view/theme/DomaAndroidTheme.kt +++ b/presentation/src/main/java/view/theme/DomaAndroidTheme.kt @@ -8,9 +8,10 @@ import view.theme.color.DoMaColor @Composable fun DoMaAndroidTheme( colors: ColorTheme = DoMaColor, - content: @Composable (colors: ColorTheme) -> Unit + typography: Typography = DoMaTypography, + content: @Composable (colors: ColorTheme, typography: Typography) -> Unit ){ - content(colors = colors) + content(colors = colors, typography = typography) } \ No newline at end of file diff --git a/presentation/src/main/java/view/theme/DomaTypography.kt b/presentation/src/main/java/view/theme/DomaTypography.kt index cf7c604..e6f7c8e 100644 --- a/presentation/src/main/java/view/theme/DomaTypography.kt +++ b/presentation/src/main/java/view/theme/DomaTypography.kt @@ -9,9 +9,8 @@ import androidx.compose.ui.unit.sp import com.kim.presentation.R val suit = FontFamily( - Font(R.font.suitbold), Font(R.font.suitregular), - + Font(R.font.suitbold), ) diff --git a/presentation/src/main/java/viewModel/users/UsersViewModel.kt b/presentation/src/main/java/viewModel/users/UsersViewModel.kt index d87a064..850572f 100644 --- a/presentation/src/main/java/viewModel/users/UsersViewModel.kt +++ b/presentation/src/main/java/viewModel/users/UsersViewModel.kt @@ -35,15 +35,11 @@ class UsersViewModel @Inject constructor( } is Result.Error -> { - _usersUiState.value = UsersUiState.Fail + _usersUiState.value = UsersUiState.Fail(result.exception) } is Result.Success -> { - if (result.data.isEmpty()) { - _usersUiState.value = UsersUiState.Empty - } else { - _usersUiState.value = UsersUiState.Success(result.data.toImmutableList()) - } + _usersUiState.value = UsersUiState.Success(result.data) } } } diff --git a/presentation/src/main/java/viewModel/users/uistate/UsersUiState.kt b/presentation/src/main/java/viewModel/users/uistate/UsersUiState.kt index aa4a39b..98a0ab7 100644 --- a/presentation/src/main/java/viewModel/users/uistate/UsersUiState.kt +++ b/presentation/src/main/java/viewModel/users/uistate/UsersUiState.kt @@ -6,6 +6,6 @@ import model.users.response.UsersResponseModel sealed interface UsersUiState { object Loading : UsersUiState object Empty : UsersUiState - data class Success(val data: ImmutableList) : UsersUiState - object Fail : UsersUiState + data class Success(val data: UsersResponseModel) : UsersUiState + data class Fail(val exception: Throwable) : UsersUiState } \ No newline at end of file diff --git a/presentation/src/main/res/drawable/down.xml b/presentation/src/main/res/drawable/down.xml new file mode 100644 index 0000000..588a74b --- /dev/null +++ b/presentation/src/main/res/drawable/down.xml @@ -0,0 +1,12 @@ + + + diff --git a/presentation/src/main/res/drawable/up.xml b/presentation/src/main/res/drawable/up.xml new file mode 100644 index 0000000..f1e3129 --- /dev/null +++ b/presentation/src/main/res/drawable/up.xml @@ -0,0 +1,11 @@ + + +