diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 4b4dadf8..5f4e7266 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -59,6 +59,10 @@ android { compose = true buildConfig = true } + buildFeatures { + compose = true + buildConfig = true + } } dependencies { diff --git a/app/src/main/java/com/paw/key/data/di/NetworkModule.kt b/app/src/main/java/com/paw/key/data/di/NetworkModule.kt index 07ee6ea8..c61b2dc3 100644 --- a/app/src/main/java/com/paw/key/data/di/NetworkModule.kt +++ b/app/src/main/java/com/paw/key/data/di/NetworkModule.kt @@ -116,4 +116,4 @@ object NetworkModule { .addConverterFactory(converterFactory) .client(client) .build() -} +} \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/data/di/RepositoryModule.kt b/app/src/main/java/com/paw/key/data/di/RepositoryModule.kt index ba7d3b07..dc0a0417 100644 --- a/app/src/main/java/com/paw/key/data/di/RepositoryModule.kt +++ b/app/src/main/java/com/paw/key/data/di/RepositoryModule.kt @@ -10,6 +10,7 @@ import com.paw.key.data.remote.datasource.mypage.MypageDataSource import com.paw.key.data.remote.datasource.mypage.MypageDataSourceImpl import com.paw.key.data.repository.mypage.MypageRepositoryImpl import com.paw.key.data.repositoryimpl.ArchivedListRepositoryImpl +import com.paw.key.data.repositoryimpl.DbtiRepositoryImpl import com.paw.key.data.repositoryimpl.LikeRepositoryImpl import com.paw.key.data.repositoryimpl.RegionRepositoryImpl import com.paw.key.data.repositoryimpl.SavedListRepositoryImpl @@ -24,6 +25,7 @@ import com.paw.key.data.repositoryimpl.user.UserRepositoryImpl import com.paw.key.data.repositoryimpl.walk.WalkRepositoryImpl import com.paw.key.data.repositoryimpl.walkpreparation.WalkPreparationRepositoryImpl import com.paw.key.domain.repository.ArchivedListRepository +import com.paw.key.domain.repository.DbtiRepository import com.paw.key.domain.repository.LikeRepository import com.paw.key.domain.repository.RegionRepository import com.paw.key.domain.repository.SavedListRepository @@ -165,4 +167,11 @@ interface RepositoryModule { impl: WalkRepositoryImpl ) : WalkRepository + + //DBTI + @Binds + @Singleton + abstract fun bindDbtiRepository( + dbtiRepositoryImpl: DbtiRepositoryImpl + ): DbtiRepository } diff --git a/app/src/main/java/com/paw/key/data/di/ServiceModule.kt b/app/src/main/java/com/paw/key/data/di/ServiceModule.kt index ab66d9b6..3b0755ee 100644 --- a/app/src/main/java/com/paw/key/data/di/ServiceModule.kt +++ b/app/src/main/java/com/paw/key/data/di/ServiceModule.kt @@ -1,6 +1,7 @@ package com.paw.key.data.di import com.paw.key.data.service.ArchivedListService +import com.paw.key.data.service.DbtiService import com.paw.key.data.service.LikeService import com.paw.key.data.service.SavedListService import com.paw.key.data.service.auth.ReissueService @@ -79,6 +80,7 @@ object ServiceModule { fun provideImageS3Service(@Named("s3") retrofit: Retrofit): S3Service = retrofit.create() + // 리뷰 @Provides @Singleton fun provideWalkPreparationService(retrofit: Retrofit): WalkPreparationService = @@ -104,4 +106,9 @@ object ServiceModule { @Singleton fun provideMypageService(retrofit: Retrofit): MypageService = retrofit.create() + + @Provides + @Singleton + fun provideDbtiService(retrofit: Retrofit): DbtiService = + retrofit.create() } diff --git a/app/src/main/java/com/paw/key/data/dto/request/dbti/DbtiResultRequest.kt b/app/src/main/java/com/paw/key/data/dto/request/dbti/DbtiResultRequest.kt new file mode 100644 index 00000000..db946b17 --- /dev/null +++ b/app/src/main/java/com/paw/key/data/dto/request/dbti/DbtiResultRequest.kt @@ -0,0 +1,8 @@ +package com.paw.key.data.dto.request.dbti + +import kotlinx.serialization.Serializable + +@Serializable +data class DbtiResultRequest( + val optionIds: List +) \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/data/dto/response/DBTI/DbtiQuestionsResponse.kt b/app/src/main/java/com/paw/key/data/dto/response/DBTI/DbtiQuestionsResponse.kt new file mode 100644 index 00000000..87272b57 --- /dev/null +++ b/app/src/main/java/com/paw/key/data/dto/response/DBTI/DbtiQuestionsResponse.kt @@ -0,0 +1,37 @@ +package com.paw.key.data.dto.response.dbti + +import kotlinx.serialization.Serializable + +@Serializable +data class DbtiQuestionsResponse( + val code: String, + val message: String, + val data: QuestionsData +) + +@Serializable +data class QuestionsData( + val questions: List +) + +@Serializable +data class QuestionDto( + val id: Int, + val category: CategoryDto, + val content: String, + val options: List +) + +@Serializable +data class CategoryDto( + val code: String, + val name: String +) + +@Serializable +data class OptionDto( + val id: Int, + val content: String, + val imageUrl: String?, + val value: String +) \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/data/dto/response/DBTI/DbtiResultResponse.kt b/app/src/main/java/com/paw/key/data/dto/response/DBTI/DbtiResultResponse.kt new file mode 100644 index 00000000..35407972 --- /dev/null +++ b/app/src/main/java/com/paw/key/data/dto/response/DBTI/DbtiResultResponse.kt @@ -0,0 +1,29 @@ +package com.paw.key.data.dto.response.dbti + +import kotlinx.serialization.Serializable + +@Serializable +data class DbtiResultResponse( + val code: String, + val message: String, + val data: DbtiResultData +) + +@Serializable +data class DbtiResultData( + val type: String, + val name: String, + val image: String?, + val keyword: List, + val description: String, + val analysis: List +) + +@Serializable +data class AnalysisDto( + val axis: String, + val leftLabel: String, + val rightLabel: String, + val dominantSide: String, + val score: Int +) \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/data/remote/datasource/DBTI/DbtiDataSource.kt b/app/src/main/java/com/paw/key/data/remote/datasource/DBTI/DbtiDataSource.kt new file mode 100644 index 00000000..f2430c25 --- /dev/null +++ b/app/src/main/java/com/paw/key/data/remote/datasource/DBTI/DbtiDataSource.kt @@ -0,0 +1,37 @@ +package com.paw.key.data.remote.datasource + +import com.paw.key.data.dto.request.dbti.DbtiResultRequest +import com.paw.key.data.dto.response.dbti.DbtiQuestionsResponse +import com.paw.key.data.dto.response.dbti.DbtiResultResponse +import com.paw.key.data.service.DbtiService +import javax.inject.Inject + +class DbtiDataSource @Inject constructor( + private val dbtiService: DbtiService +) { + suspend fun getQuestions(token: String): DbtiQuestionsResponse { + return dbtiService.getQuestions("Bearer $token") + } + + suspend fun submitResult( + petId: Long, + token: String, + optionIds: List + ): DbtiResultResponse { + return dbtiService.submitResult( + petId = petId, + authorization = "Bearer $token", + request = DbtiResultRequest(optionIds = optionIds) + ) + } + + suspend fun getResult( + petId: Long, + token: String + ): DbtiResultResponse { + return dbtiService.getResult( + petId = petId, + authorization = "Bearer $token" + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/data/repositoryimpl/DBTI/DbtiRepositoryImpl.kt b/app/src/main/java/com/paw/key/data/repositoryimpl/DBTI/DbtiRepositoryImpl.kt new file mode 100644 index 00000000..8e34de4f --- /dev/null +++ b/app/src/main/java/com/paw/key/data/repositoryimpl/DBTI/DbtiRepositoryImpl.kt @@ -0,0 +1,92 @@ +package com.paw.key.data.repositoryimpl + +import com.paw.key.data.remote.datasource.DbtiDataSource +import com.paw.key.domain.entity.DBTI.DbtiAnalysisEntity +import com.paw.key.domain.entity.DBTI.DbtiResultEntity +import com.paw.key.domain.entity.dbti.DbtiOptionEntity +import com.paw.key.domain.entity.dbti.DbtiQuestionEntity +import com.paw.key.domain.repository.DbtiRepository +import javax.inject.Inject + +class DbtiRepositoryImpl @Inject constructor( + private val dbtiDataSource: DbtiDataSource +) : DbtiRepository { + + override suspend fun getQuestions(): Result> { + return runCatching { + val response = dbtiDataSource.getQuestions("YOUR_TOKEN") // TODO: 실제 토큰으로 변경 + response.data.questions.map { questionDto -> + DbtiQuestionEntity( + id = questionDto.id, + categoryCode = questionDto.category.code, + categoryName = questionDto.category.name, + content = questionDto.content, + options = questionDto.options.map { optionDto -> + DbtiOptionEntity( + id = optionDto.id, + content = optionDto.content, + imageUrl = optionDto.imageUrl, + value = optionDto.value + ) + } + ) + } + } + } + + override suspend fun submitResult( + petId: Long, + optionIds: List + ): Result { + return runCatching { + val response = dbtiDataSource.submitResult( + petId = petId, + token = "YOUR_TOKEN", // TODO: 실제 토큰으로 변경 + optionIds = optionIds + ) + + DbtiResultEntity( + type = response.data.type, + name = response.data.name, + image = response.data.image, + keyword = response.data.keyword, + description = response.data.description, + analysis = response.data.analysis.map { analysisDto -> + DbtiAnalysisEntity( + axis = analysisDto.axis, + leftLabel = analysisDto.leftLabel, + rightLabel = analysisDto.rightLabel, + dominantSide = analysisDto.dominantSide, + score = analysisDto.score + ) + } + ) + } + } + + override suspend fun getResult(petId: Long): Result { + return runCatching { + val response = dbtiDataSource.getResult( + petId = petId, + token = "YOUR_TOKEN" // TODO: 실제 토큰으로 변경 + ) + + DbtiResultEntity( + type = response.data.type, + name = response.data.name, + image = response.data.image, + keyword = response.data.keyword, + description = response.data.description, + analysis = response.data.analysis.map { analysisDto -> + DbtiAnalysisEntity( + axis = analysisDto.axis, + leftLabel = analysisDto.leftLabel, + rightLabel = analysisDto.rightLabel, + dominantSide = analysisDto.dominantSide, + score = analysisDto.score + ) + } + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/data/service/DBTI/DbtiService.kt b/app/src/main/java/com/paw/key/data/service/DBTI/DbtiService.kt new file mode 100644 index 00000000..05ec6b2e --- /dev/null +++ b/app/src/main/java/com/paw/key/data/service/DBTI/DbtiService.kt @@ -0,0 +1,30 @@ +package com.paw.key.data.service + +import com.paw.key.data.dto.request.dbti.DbtiResultRequest +import com.paw.key.data.dto.response.dbti.DbtiQuestionsResponse +import com.paw.key.data.dto.response.dbti.DbtiResultResponse +import retrofit2.http.Body +import retrofit2.http.GET +import retrofit2.http.Header +import retrofit2.http.POST +import retrofit2.http.Path + +interface DbtiService { + @GET("pets/dbti/questions") + suspend fun getQuestions( + @Header("Authorization") authorization: String + ): DbtiQuestionsResponse + + @POST("pets/dbti/{petId}") + suspend fun submitResult( + @Path("petId") petId: Long, + @Header("Authorization") authorization: String, + @Body request: DbtiResultRequest + ): DbtiResultResponse + + @GET("pets/dbti/{petId}") + suspend fun getResult( + @Path("petId") petId: Long, + @Header("Authorization") authorization: String + ): DbtiResultResponse +} \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/domain/entity/DBTI/DbtiQuestionEntity.kt b/app/src/main/java/com/paw/key/domain/entity/DBTI/DbtiQuestionEntity.kt new file mode 100644 index 00000000..e7d7f1b5 --- /dev/null +++ b/app/src/main/java/com/paw/key/domain/entity/DBTI/DbtiQuestionEntity.kt @@ -0,0 +1,16 @@ +package com.paw.key.domain.entity.dbti + +data class DbtiQuestionEntity( + val id: Int, + val categoryCode: String, + val categoryName: String, + val content: String, + val options: List +) + +data class DbtiOptionEntity( + val id: Int, + val content: String, + val imageUrl: String?, + val value: String +) \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/domain/entity/DBTI/DbtiResultEntity.kt b/app/src/main/java/com/paw/key/domain/entity/DBTI/DbtiResultEntity.kt new file mode 100644 index 00000000..35d56f55 --- /dev/null +++ b/app/src/main/java/com/paw/key/domain/entity/DBTI/DbtiResultEntity.kt @@ -0,0 +1,18 @@ +package com.paw.key.domain.entity.DBTI + +data class DbtiResultEntity( + val type: String, + val name: String, + val image: String?, + val keyword: List, + val description: String, + val analysis: List +) + +data class DbtiAnalysisEntity( + val axis: String, + val leftLabel: String, + val rightLabel: String, + val dominantSide: String, + val score: Int +) \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/domain/repository/DBTI/DbtiRepository.kt b/app/src/main/java/com/paw/key/domain/repository/DBTI/DbtiRepository.kt new file mode 100644 index 00000000..912f90c7 --- /dev/null +++ b/app/src/main/java/com/paw/key/domain/repository/DBTI/DbtiRepository.kt @@ -0,0 +1,15 @@ +package com.paw.key.domain.repository + +import com.paw.key.domain.entity.DBTI.DbtiResultEntity +import com.paw.key.domain.entity.dbti.DbtiQuestionEntity + +interface DbtiRepository { + suspend fun getQuestions(): Result> + + suspend fun submitResult( + petId: Long, + optionIds: List + ): Result + + suspend fun getResult(petId: Long): Result +} \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/domain/usecase/GetDbtiQuestionsUseCase.kt b/app/src/main/java/com/paw/key/domain/usecase/GetDbtiQuestionsUseCase.kt new file mode 100644 index 00000000..36ec603e --- /dev/null +++ b/app/src/main/java/com/paw/key/domain/usecase/GetDbtiQuestionsUseCase.kt @@ -0,0 +1,13 @@ +package com.paw.key.domain.usecase + +import com.paw.key.domain.entity.dbti.DbtiQuestionEntity +import com.paw.key.domain.repository.DbtiRepository +import javax.inject.Inject + +class GetDbtiQuestionsUseCase @Inject constructor( + private val repository: DbtiRepository +) { + suspend operator fun invoke(): Result> { + return repository.getQuestions() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/domain/usecase/SubmitDbtiResultUseCase.kt b/app/src/main/java/com/paw/key/domain/usecase/SubmitDbtiResultUseCase.kt new file mode 100644 index 00000000..87e94d7c --- /dev/null +++ b/app/src/main/java/com/paw/key/domain/usecase/SubmitDbtiResultUseCase.kt @@ -0,0 +1,16 @@ +package com.paw.key.domain.usecase + +import com.paw.key.domain.entity.DBTI.DbtiResultEntity +import com.paw.key.domain.repository.DbtiRepository +import javax.inject.Inject + +class SubmitDbtiResultUseCase @Inject constructor( + private val repository: DbtiRepository +) { + suspend operator fun invoke( + petId: Long, + optionIds: List + ): Result { + return repository.submitResult(petId, optionIds) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/presentation/ui/dbti/StartScreen.kt b/app/src/main/java/com/paw/key/presentation/ui/dbti/StartScreen.kt index b2e42957..93e1ec44 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/dbti/StartScreen.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/dbti/StartScreen.kt @@ -1,8 +1,13 @@ package com.paw.key.presentation.ui.dbti import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +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.Button import androidx.compose.material3.ButtonDefaults @@ -13,11 +18,9 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource -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.paw.key.R import com.paw.key.core.designsystem.component.TopBar import com.paw.key.core.designsystem.theme.PawKeyTheme @@ -40,8 +43,7 @@ fun StartScreen( ) Column( - modifier = modifier - .fillMaxSize() + modifier = Modifier.fillMaxSize() ) { TopBar( title = "DBTI 검사", @@ -59,11 +61,8 @@ fun StartScreen( Text( text = "반려견 성향을 알아보는\nDBTI 성격 유형 검사", - fontSize = 24.sp, - fontWeight = FontWeight.Bold, color = PawKeyTheme.colors.contents, textAlign = TextAlign.Start, - lineHeight = 32.sp, style = PawKeyTheme.typography.header1 ) @@ -71,22 +70,13 @@ fun StartScreen( Text( text = "본 조사는 사랑하는 반려견 위한 비정식 테스트입니다.", - fontSize = 14.sp, color = PawKeyTheme.colors.defaultDark, - textAlign = TextAlign.Center, + textAlign = TextAlign.Start, style = PawKeyTheme.typography.body14R ) Spacer(modifier = Modifier.weight(1f)) -// Image( -// painter = painterResource(id = R.drawable.doki_welcome), -// contentDescription = "DOKI 캐릭터", -// modifier = Modifier -// .fillMaxSize(), // 전체 화면 차지 -// contentScale = ContentScale.Crop -// ) - Spacer(modifier = Modifier.weight(1f)) // 조건부 건너뛰기 @@ -117,7 +107,6 @@ fun StartScreen( ) { Text( text = "시작하기", - fontWeight = FontWeight.SemiBold, color = PawKeyTheme.colors.background, style = PawKeyTheme.typography.mainButtonActive ) diff --git a/app/src/main/java/com/paw/key/presentation/ui/dbti/navigation/DbtiNavigation.kt b/app/src/main/java/com/paw/key/presentation/ui/dbti/navigation/DbtiNavigation.kt new file mode 100644 index 00000000..fe193dfb --- /dev/null +++ b/app/src/main/java/com/paw/key/presentation/ui/dbti/navigation/DbtiNavigation.kt @@ -0,0 +1,43 @@ +package com.paw.key.presentation.ui.dbti.navigation + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavOptions +import androidx.navigation.compose.composable +import com.paw.key.presentation.ui.dbti.StartScreen +import com.paw.key.presentation.ui.dbti.test.TestScreen +import kotlinx.serialization.Serializable + +fun NavController.navigateDbtiStart(navOptions: NavOptions? = null) { + navigate(DbtiStart, navOptions) +} + +fun NavController.navigateDbtiTest(navOptions: NavOptions? = null) { + navigate(DbtiTest, navOptions) +} + +fun NavGraphBuilder.dbtiNavGraph( + navController: NavController, // 파라미터 추가! + navigateUp: () -> Unit, +) { + composable { + StartScreen( + navigateUp = navigateUp, + navigateToTest = { navController.navigateDbtiTest() }, // 연결! + showSkipButton = false, + onSkip = null + ) + } + + composable { + TestScreen( + onBackClick = navigateUp + ) + } +} + +@Serializable +data object DbtiStart + +@Serializable +data object DbtiTest \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/presentation/ui/dbti/result/ResultScreen.kt b/app/src/main/java/com/paw/key/presentation/ui/dbti/result/ResultScreen.kt index 1f60c314..fb95b17e 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/dbti/result/ResultScreen.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/dbti/result/ResultScreen.kt @@ -7,20 +7,23 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.paw.key.core.designsystem.component.DokiBorderButton import com.paw.key.core.designsystem.component.DokiButton import com.paw.key.core.designsystem.component.TopBar import com.paw.key.core.designsystem.theme.PawKeyTheme import com.paw.key.presentation.ui.dbti.result.component.ResultBox import com.paw.key.presentation.ui.dbti.result.component.TraitAnalysis +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf @Composable fun ResultScreen( type: String, name: String, imageUrl: String?, - keywords: List, + keywords: ImmutableList, description: String, - analysis: List, + analysis: ImmutableList, onRetakeTest: () -> Unit, onGoHome: () -> Unit, navigateUp: () -> Unit, @@ -60,12 +63,11 @@ fun ResultScreen( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(12.dp) ) { - DokiButton( + DokiBorderButton( text = "다시 테스트하기", onClick = onRetakeTest, modifier = Modifier.weight(1f), enabled = true - // TODO: 버튼 바꾸기 ) DokiButton( @@ -89,9 +91,9 @@ private fun ResultScreenPreview() { type = "EPR", name = "탐험대장 멍멍이", imageUrl = null, - keywords = listOf("모험", "활발", "사교성"), + keywords = persistentListOf("모험", "활발", "사교성"), description = "활발하고 친구들과 어울리며 모험을 좋아해요.\n집사에게 언제나 애너지를 주는 타입!", - analysis = listOf( + analysis = persistentListOf( TraitAnalysis( leftLabel = "휴식가", rightLabel = "탐험가", diff --git a/app/src/main/java/com/paw/key/presentation/ui/dbti/result/component/ResultBox.kt b/app/src/main/java/com/paw/key/presentation/ui/dbti/result/component/ResultBox.kt index d36ad828..4630bd6d 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/dbti/result/component/ResultBox.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/dbti/result/component/ResultBox.kt @@ -1,7 +1,13 @@ package com.paw.key.presentation.ui.dbti.result.component import androidx.compose.foundation.background -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +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.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -10,14 +16,14 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext -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 coil.compose.AsyncImage import coil.request.ImageRequest import com.paw.key.core.designsystem.theme.PawKeyTheme +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf // TraitAnalysis 데이터 클래스 정의 data class TraitAnalysis( @@ -32,9 +38,9 @@ fun ResultBox( type: String, name: String, imageUrl: String?, - keywords: List, + keywords: ImmutableList, description: String, - analysis: List, + analysis: ImmutableList, modifier: Modifier = Modifier, ) { Surface( @@ -45,94 +51,73 @@ fun ResultBox( Column( modifier = Modifier .fillMaxWidth() - .padding(vertical = 32.dp), + .padding(vertical = 32.dp, horizontal = 28.dp), horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(20.dp) + verticalArrangement = Arrangement.spacedBy(24.dp) ) { - Column( - modifier = Modifier.width(210.dp), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(16.dp) - ) { - Text( - text = "내 강아지의 성향은", - fontSize = 14.sp, - fontWeight = FontWeight.Medium, - color = PawKeyTheme.colors.defaultDark, - textAlign = TextAlign.Center, - style = PawKeyTheme.typography.body14M, - modifier = Modifier.fillMaxWidth() - ) + // 타이틀 + Text( + text = "내 강아지의 성향은", + color = PawKeyTheme.colors.defaultDark, + textAlign = TextAlign.Center, + style = PawKeyTheme.typography.body14M + ) - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text( - text = name, - fontSize = 24.sp, - fontWeight = FontWeight.Bold, - color = PawKeyTheme.colors.contents, - letterSpacing = (-0.48).sp, - textAlign = TextAlign.Center, - style = PawKeyTheme.typography.header1 - ) - Text( - text = type, - fontSize = 28.sp, - fontWeight = FontWeight.Bold, - color = PawKeyTheme.colors.primary, - letterSpacing = (-0.56).sp, - textAlign = TextAlign.Center, - style = PawKeyTheme.typography.header1 - ) - } - } - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(24.dp) - ) { - if (imageUrl != null) { - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(imageUrl) - .crossfade(true) - .build(), - contentDescription = null, - modifier = Modifier.size(150.dp), - contentScale = ContentScale.Crop - ) - } else { - Box( - modifier = Modifier - .size(150.dp) - .background(PawKeyTheme.colors.defaultButton) - ) - } + // 이름 + Text( + text = name, + color = PawKeyTheme.colors.contents, + textAlign = TextAlign.Center, + style = PawKeyTheme.typography.header2 + ) - Row( - horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally), - modifier = Modifier.fillMaxWidth() - ) { - keywords.forEach { keyword -> - CharacterChip(text = "# $keyword") - } - } + // 타입 + Text( + text = type, + color = PawKeyTheme.colors.primary, + textAlign = TextAlign.Center, + style = PawKeyTheme.typography.header1 + ) - Text( - text = description, - fontSize = 14.sp, - fontWeight = FontWeight.Medium, - color = PawKeyTheme.colors.contents, - textAlign = TextAlign.Center, - style = PawKeyTheme.typography.body14M, + // 이미지 + if (imageUrl != null) { + AsyncImage( + model = ImageRequest.Builder(LocalContext.current) + .data(imageUrl) + .crossfade(true) + .build(), + contentDescription = null, + modifier = Modifier.size(150.dp), + contentScale = ContentScale.Crop + ) + } else { + Box( modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 28.dp) + .size(150.dp) + .background(PawKeyTheme.colors.defaultButton) ) } + // 키워드 + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally), + modifier = Modifier.fillMaxWidth() + ) { + keywords.forEach { keyword -> + CharacterChip(text = "# $keyword") + } + } + + // 설명 + Text( + text = description, + color = PawKeyTheme.colors.contents, + textAlign = TextAlign.Center, + style = PawKeyTheme.typography.body14M, + modifier = Modifier.fillMaxWidth() + ) + + // 분석 바들 Column( modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(16.dp) @@ -158,9 +143,9 @@ private fun ResultBoxPreview() { type = "ISF", name = "온순한 방구석멍", imageUrl = null, - keywords = listOf("차분", "다소 활발", "탐험"), + keywords = persistentListOf("차분", "다소 활발", "탐험"), description = "내향적이고 온순하며 자유로운 흐름 속에서 소소한 행복을 찾습니다.", - analysis = listOf( + analysis = persistentListOf( TraitAnalysis( leftLabel = "탐험가", rightLabel = "휴식가", diff --git a/app/src/main/java/com/paw/key/presentation/ui/dbti/test/TestScreen.kt b/app/src/main/java/com/paw/key/presentation/ui/dbti/test/TestScreen.kt index 3f92e902..779e9f12 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/dbti/test/TestScreen.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/dbti/test/TestScreen.kt @@ -1,110 +1,120 @@ package com.paw.key.presentation.ui.dbti.test -import androidx.compose.foundation.layout.* -import androidx.compose.runtime.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -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 androidx.compose.material3.Text import com.paw.key.core.designsystem.component.DokiButton +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.paw.key.core.designsystem.component.LoadingScreen import com.paw.key.core.designsystem.component.TopBar import com.paw.key.core.designsystem.theme.PawKeyTheme import com.paw.key.presentation.ui.dbti.component.SelectCard - - -data class TestOption( - val id: Int, - val topText: String, - val bottomText: String, - val imageUrl: String? = null -) +import com.paw.key.presentation.ui.dbti.test.state.TestUiState +import com.paw.key.presentation.ui.dbti.test.viewmodel.TestViewModel @Composable fun TestScreen( - categoryName: String, - questionText: String, - options: List, onBackClick: () -> Unit, - onNextClick: () -> Unit, - modifier: Modifier = Modifier, + viewModel: TestViewModel = hiltViewModel() ) { - var selectedOptionId by remember { mutableStateOf(null) } - - Box(modifier = modifier.fillMaxSize()) { - Column(modifier = Modifier.fillMaxSize()) { - TopBar( - title = "프로필 설정", - onBackClick = onBackClick, - isBackVisible = true - ) - - Column( - modifier = Modifier - .fillMaxSize() - .padding(horizontal = 24.dp) - ) { - Spacer(modifier = Modifier.weight(67f)) // TopBar ↔ 텍스트 - - Column( - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text( - text = categoryName, - fontWeight = FontWeight.SemiBold, - color = PawKeyTheme.colors.primary, - style = PawKeyTheme.typography.bodyActive + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + + when (val state = uiState) { + is TestUiState.Success -> { + Box(modifier = Modifier.fillMaxSize()) { + Column(modifier = Modifier.fillMaxSize()) { + TopBar( + title = "프로필 설정", + onBackClick = onBackClick, + isBackVisible = true ) - Spacer(modifier = Modifier.height(16.dp)) - - Text( - text = questionText, - color = PawKeyTheme.colors.contents, - textAlign = TextAlign.Center, - lineHeight = 28.sp, - style = PawKeyTheme.typography.header3, - modifier = Modifier.fillMaxWidth() - ) + Column( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 24.dp) + ) { + Spacer(modifier = Modifier.weight(67f)) + + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "${state.questionNumber}/${state.totalQuestions}", + color = PawKeyTheme.colors.defaultMiddle, + style = PawKeyTheme.typography.body14M + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = state.categoryName, + color = PawKeyTheme.colors.primary, + style = PawKeyTheme.typography.bodyActive + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + text = state.questionText, + color = PawKeyTheme.colors.contents, + textAlign = TextAlign.Center, + style = PawKeyTheme.typography.header3, + modifier = Modifier.fillMaxWidth() + ) + } + + Spacer(modifier = Modifier.weight(30f)) + Spacer(modifier = Modifier.weight(219.31f)) + Spacer(modifier = Modifier.weight(1f)) + + DokiButton( + text = "다음으로", + onClick = { viewModel.nextQuestion() }, + enabled = state.selectedOptionId != null, + modifier = Modifier.fillMaxWidth() + ) + + Spacer(modifier = Modifier.height(34.dp)) + } } - Spacer(modifier = Modifier.weight(30f)) - - Spacer(modifier = Modifier.weight(219.31f)) - - Spacer(modifier = Modifier.weight(1f)) - - DokiButton( - text = "다음으로", - onClick = onNextClick, - enabled = selectedOptionId != null, - modifier = Modifier.fillMaxWidth() - ) - - Spacer(modifier = Modifier.height(34.dp)) + Row( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.CenterStart) + .padding(horizontal = 24.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + state.options.forEach { option -> + SelectCard( + text = option.text, + imageUrl = option.imageUrl, + onClick = { viewModel.selectOption(option.id) }, + modifier = Modifier.weight(1f), + isSelected = state.selectedOptionId == option.id + ) + } + } } } - - Row( - modifier = Modifier - .fillMaxWidth() - .align(Alignment.CenterStart) - .padding(horizontal = 24.dp), - horizontalArrangement = Arrangement.spacedBy(12.dp) - ) { - options.forEach { option -> - SelectCard( - imageUrl = option.imageUrl, - topText = option.topText, - bottomText = option.bottomText, - isSelected = selectedOptionId == option.id, - onClick = { selectedOptionId = option.id }, - modifier = Modifier.weight(1f) - ) - } + else -> { + LoadingScreen() } } } @@ -113,25 +123,86 @@ fun TestScreen( @Composable private fun TestScreenPreview() { PawKeyTheme { - TestScreen( - categoryName = "부끄멍 vs 적극멍", - questionText = "산책 중 다른 강아지를 만나면\n우리 강아지는...", - options = listOf( - TestOption( - id = 1, - topText = "잠깐 눈치만 보고", - bottomText = "거리를 유지해요", - imageUrl = null - ), - TestOption( - id = 2, - topText = "먼저 다가가서", - bottomText = "인사하고 놀자고 해요", - imageUrl = null + Box(modifier = Modifier.fillMaxSize()) { + Column(modifier = Modifier.fillMaxSize()) { + TopBar( + title = "프로필 설정", + onBackClick = {}, + isBackVisible = true ) - ), - onBackClick = {}, - onNextClick = {} - ) + + Column( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 24.dp) + ) { + Spacer(modifier = Modifier.weight(67f)) + + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "1/9", + color = PawKeyTheme.colors.defaultMiddle, + style = PawKeyTheme.typography.body14M + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = "탐험가 vs 휴식가", + color = PawKeyTheme.colors.primary, + style = PawKeyTheme.typography.bodyActive + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + text = "산책 나가면 우리 강아지는...", + color = PawKeyTheme.colors.contents, + textAlign = TextAlign.Center, + style = PawKeyTheme.typography.header3, + modifier = Modifier.fillMaxWidth() + ) + } + + Spacer(modifier = Modifier.weight(30f)) + Spacer(modifier = Modifier.weight(219.31f)) + Spacer(modifier = Modifier.weight(1f)) + + DokiButton( + text = "다음으로", + onClick = {}, + enabled = false, + modifier = Modifier.fillMaxWidth() + ) + + Spacer(modifier = Modifier.height(34.dp)) + } + } + + Row( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.CenterStart) + .padding(horizontal = 24.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + SelectCard( + text = "동네 구석구석 새 길을\n탐험해야 신나요", + imageUrl = null, + onClick = {}, + modifier = Modifier.weight(1f), + isSelected = false + ) + SelectCard( + text = "익숙한 코스에서\n짧게 다녀오는게 좋아요", + imageUrl = null, + onClick = {}, + modifier = Modifier.weight(1f), + isSelected = false + ) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/presentation/ui/dbti/test/component/SelectCard.kt b/app/src/main/java/com/paw/key/presentation/ui/dbti/test/component/SelectCard.kt index f4413225..bd4f571b 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/dbti/test/component/SelectCard.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/dbti/test/component/SelectCard.kt @@ -2,7 +2,13 @@ package com.paw.key.presentation.ui.dbti.component import androidx.compose.foundation.background import androidx.compose.foundation.border -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -22,12 +28,11 @@ import com.paw.key.core.extension.noRippleClickable @Composable fun SelectCard( + text: String, imageUrl: String?, - topText: String, - bottomText: String, - isSelected: Boolean = false, onClick: () -> Unit, modifier: Modifier = Modifier, + isSelected: Boolean = false, ) { val backgroundColor = if (isSelected) { PawKeyTheme.colors.opacity5Primary @@ -55,7 +60,7 @@ fun SelectCard( Column( modifier = modifier - .aspectRatio(159.5f / 219.31f) // 비율로 크기 조정 + .aspectRatio(8f / 11f) .clip(RoundedCornerShape(8.dp)) .background(backgroundColor) .border( @@ -80,30 +85,13 @@ fun SelectCard( contentScale = ContentScale.Crop ) - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center - ) { - Text( - text = topText, - color = textColor, - style = textStyle, - textAlign = TextAlign.Center, - maxLines = 1, - modifier = Modifier.fillMaxWidth() - ) - - Spacer(modifier = Modifier.height(2.dp)) - - Text( - text = bottomText, - color = textColor, - style = textStyle, - textAlign = TextAlign.Center, - maxLines = 1, - modifier = Modifier.fillMaxWidth() - ) - } + Text( + text = text, + color = textColor, + style = textStyle, + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth() + ) } } @@ -116,21 +104,19 @@ private fun SelectionCardPreview() { horizontalArrangement = Arrangement.spacedBy(16.dp) ) { SelectCard( + text = "잠깐 눈치만 보고\n거리를 유지해요", imageUrl = null, - topText = "잠깐 눈치만 보고", - bottomText = "거리를 유지해요", - isSelected = false, onClick = {}, - modifier = Modifier.weight(1f) + modifier = Modifier.weight(1f), + isSelected = false ) SelectCard( + text = "먼저 다가가서\n인사하고 놀자고 해요", imageUrl = null, - topText = "먼저 다가가서", - bottomText = "인사하고 놀자고 해요", - isSelected = true, onClick = {}, - modifier = Modifier.weight(1f) + modifier = Modifier.weight(1f), + isSelected = true ) } } diff --git a/app/src/main/java/com/paw/key/presentation/ui/dbti/test/model/TestOptionModel.kt b/app/src/main/java/com/paw/key/presentation/ui/dbti/test/model/TestOptionModel.kt new file mode 100644 index 00000000..e4979ba0 --- /dev/null +++ b/app/src/main/java/com/paw/key/presentation/ui/dbti/test/model/TestOptionModel.kt @@ -0,0 +1,7 @@ +package com.paw.key.presentation.ui.dbti.test.model + +data class TestOptionModel( + val id: Int, + val text: String, + val imageUrl: String? = null +) \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/presentation/ui/dbti/test/state/TestContract.kt b/app/src/main/java/com/paw/key/presentation/ui/dbti/test/state/TestContract.kt new file mode 100644 index 00000000..b4abf732 --- /dev/null +++ b/app/src/main/java/com/paw/key/presentation/ui/dbti/test/state/TestContract.kt @@ -0,0 +1,18 @@ +package com.paw.key.presentation.ui.dbti.test.state + +import com.paw.key.presentation.ui.dbti.test.model.TestOptionModel + +sealed interface TestUiState { + data object Loading : TestUiState + + data class Success( + val questionNumber: Int, + val totalQuestions: Int, + val categoryName: String, + val questionText: String, + val options: List, + val selectedOptionId: Int? + ) : TestUiState + + data class Error(val message: String) : TestUiState +} \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/presentation/ui/dbti/test/viewmodel/TestViewModel.kt b/app/src/main/java/com/paw/key/presentation/ui/dbti/test/viewmodel/TestViewModel.kt new file mode 100644 index 00000000..2edfc922 --- /dev/null +++ b/app/src/main/java/com/paw/key/presentation/ui/dbti/test/viewmodel/TestViewModel.kt @@ -0,0 +1,124 @@ +package com.paw.key.presentation.ui.dbti.test.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.paw.key.domain.entity.dbti.DbtiQuestionEntity +import com.paw.key.domain.usecase.GetDbtiQuestionsUseCase +import com.paw.key.domain.usecase.SubmitDbtiResultUseCase +import com.paw.key.presentation.ui.dbti.test.model.TestOptionModel +import com.paw.key.presentation.ui.dbti.test.state.TestUiState +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class TestViewModel @Inject constructor( + private val getDbtiQuestionsUseCase: GetDbtiQuestionsUseCase, + private val submitDbtiResultUseCase: SubmitDbtiResultUseCase +) : ViewModel() { + + private val _uiState = MutableStateFlow(TestUiState.Loading) + val uiState = _uiState.asStateFlow() + + private var questions: List = emptyList() + private var currentIndex = 0 + private val selectedAnswers = mutableMapOf() // questionId to optionId + + init { + loadQuestions() + } + + private fun loadQuestions() { + viewModelScope.launch { + _uiState.value = TestUiState.Loading + + getDbtiQuestionsUseCase() + .onSuccess { questionList -> + questions = questionList + if (questionList.isNotEmpty()) { + updateCurrentQuestion() + } else { + _uiState.value = TestUiState.Error("질문을 불러올 수 없습니다.") + } + } + .onFailure { error -> + _uiState.value = TestUiState.Error( + error.message ?: "알 수 없는 오류가 발생했습니다" + ) + } + } + } + + fun selectOption(optionId: Int) { + val currentQuestion = questions.getOrNull(currentIndex) ?: return + selectedAnswers[currentQuestion.id] = optionId + updateCurrentQuestion() + } + + fun nextQuestion() { + if (currentIndex < questions.size - 1) { + currentIndex++ + updateCurrentQuestion() + } else { + // 마지막 질문 → 결과 제출 + submitResult() + } + } + + private fun submitResult() { + viewModelScope.launch { + _uiState.value = TestUiState.Loading + + // 순서대로 optionId 리스트 생성 + val optionIds = questions.map { question -> + selectedAnswers[question.id] ?: 0 + } + + submitDbtiResultUseCase( + petId = 2L, // TODO: 실제 petId로 변경 + optionIds = optionIds + ) + .onSuccess { result -> + // TODO: ResultScreen으로 이동하면서 결과 전달 + // navigateToResult(result) + } + .onFailure { error -> + _uiState.value = TestUiState.Error( + error.message ?: "결과 제출에 실패했습니다" + ) + } + } + } + + fun previousQuestion() { + if (currentIndex > 0) { + currentIndex-- + updateCurrentQuestion() + } + } + + private fun updateCurrentQuestion() { + val currentQuestion = questions.getOrNull(currentIndex) ?: return + + _uiState.value = TestUiState.Success( + questionNumber = currentIndex + 1, + totalQuestions = questions.size, + categoryName = currentQuestion.categoryName, + questionText = currentQuestion.content, + options = currentQuestion.options.map { option -> + TestOptionModel( + id = option.id, + text = option.content, + imageUrl = option.imageUrl + ) + }, + selectedOptionId = selectedAnswers[currentQuestion.id] + ) + } + + fun retry() { + loadQuestions() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/presentation/ui/main/MainNavigator.kt b/app/src/main/java/com/paw/key/presentation/ui/main/MainNavigator.kt index b3384541..51f08307 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/main/MainNavigator.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/main/MainNavigator.kt @@ -26,6 +26,7 @@ import com.paw.key.presentation.ui.onboard.navigation.navigateOnboarding import com.paw.key.presentation.ui.region.navigation.navigateRegional import com.paw.key.presentation.ui.signup.navigation.navigateSignUp import com.paw.key.presentation.ui.splash.navigation.Splash +import com.paw.key.presentation.ui.dbti.navigation.navigateDbtiStart class MainNavigator( val navController: NavHostController, @@ -149,6 +150,10 @@ class MainNavigator( navController.navigateRegional(regionId, navOptions) } + fun navigateDbtiStart(navOptions: NavOptions? = null) { + navController.navigateDbtiStart(navOptions) + } + @Composable fun showBottomBar() = MainTab.contains { @@ -161,4 +166,4 @@ fun rememberMainNavigator( navController: NavHostController = rememberNavController(), ): MainNavigator = remember(navController) { MainNavigator(navController) -} +} \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/presentation/ui/main/PawKeyNavHost.kt b/app/src/main/java/com/paw/key/presentation/ui/main/PawKeyNavHost.kt index 6ac58367..caed6d6d 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/main/PawKeyNavHost.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/main/PawKeyNavHost.kt @@ -27,6 +27,7 @@ import com.paw.key.presentation.ui.onboard.navigation.onboardingNavGraph import com.paw.key.presentation.ui.region.navigation.regionalNavGraph import com.paw.key.presentation.ui.signup.navigation.signUpNavGraph import com.paw.key.presentation.ui.splash.navigation.splashNavGraph +import com.paw.key.presentation.ui.dbti.navigation.dbtiNavGraph @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) @Composable @@ -111,6 +112,11 @@ fun PawKeyNavHost( snackBarHostState = snackbarHostState ) + dbtiNavGraph( + navController = navigator.navController, + navigateUp = navigator::navigateUp + ) + myPageNavGraph( paddingValues = paddingValues, navigateUp = navigator::navigateUp, @@ -193,7 +199,7 @@ fun PawKeyNavHost( }, // Todo: Home 으로 수정 navigateHome = { - navigator.navigateHome(clearStackNavOptions) + navigator.navigateSignUp(clearStackNavOptions) }, snackBarHostState = snackbarHostState ) diff --git a/app/src/main/java/com/paw/key/presentation/ui/mypage/route/courseinfo/viewmodel/CourseInfoViewModel.kt b/app/src/main/java/com/paw/key/presentation/ui/mypage/route/courseinfo/viewmodel/CourseInfoViewModel.kt index e7f8b4b5..a4cae5d5 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/mypage/route/courseinfo/viewmodel/CourseInfoViewModel.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/mypage/route/courseinfo/viewmodel/CourseInfoViewModel.kt @@ -10,6 +10,7 @@ import com.paw.key.presentation.ui.mypage.route.courseinfo.model.CourseInfoSideE import com.paw.key.presentation.ui.mypage.route.courseinfo.model.CourseInfoState import com.paw.key.presentation.ui.mypage.route.courseinfo.model.CourseType import com.paw.key.presentation.ui.mypage.route.courseinfo.model.toCourseData +import com.paw.key.presentation.ui.mypage.route.courseinfo.model.toUiModel import com.paw.key.presentation.ui.mypage.route.courseinfo.navigation.CourseInfoNavRoute import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableSharedFlow @@ -43,8 +44,8 @@ class CourseInfoViewModel @Inject constructor( _state.update { it.copy(courses = UiState.Loading) } val result = when (courseType) { - CourseType.MyCourse -> mypageRepository.getMyRoutes().map { list -> list.map { it.toCourseData() } } - CourseType.AllCourse -> mypageRepository.getLikedPosts().map { list -> list.map { it.toCourseData() } } + CourseType.MyCourse -> mypageRepository.getMyRoutes().map { list -> list.map { it.toUiModel() } } + CourseType.AllCourse -> mypageRepository.getLikedPosts().map { list -> list.map { it.toUiModel() } } CourseType.ReviewCourse -> mypageRepository.getMyReviews().map { list -> list.map { it.toCourseData() } } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7d306342..78e9ac5a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Fri Jun 20 02:14:50 KST 2025 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists