From 4e00b177d026c5e87ff92a8015d97ce1f2402dae Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Tue, 11 Feb 2025 16:54:19 +0900 Subject: [PATCH 01/12] =?UTF-8?q?[PC-555]=20Matching=20=EC=83=81=EB=8C=80?= =?UTF-8?q?=EB=B0=A9=20ValueTalk=20Api=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/MatchingRepositoryImpl.kt | 9 +++++- .../domain/repository/MatchingRepository.kt | 2 ++ .../java/com/puzzle/network/api/PieceApi.kt | 6 +++- .../matching/GetOpponentValueTalksResponse.kt | 28 +++++++++++++++++++ .../source/matching/MatchingDataSource.kt | 4 +++ .../graph/detail/MatchingDetailScreen.kt | 2 +- .../graph/detail/MatchingDetailViewModel.kt | 6 ++++ .../detail/contract/MatchingDetailState.kt | 2 +- 8 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 core/network/src/main/java/com/puzzle/network/model/matching/GetOpponentValueTalksResponse.kt diff --git a/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt b/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt index aa981041..be3c588b 100644 --- a/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt +++ b/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt @@ -1,7 +1,10 @@ package com.puzzle.data.repository import com.puzzle.domain.model.match.MatchInfo +import com.puzzle.domain.model.profile.OpponentValueTalk import com.puzzle.domain.repository.MatchingRepository +import com.puzzle.network.model.matching.GetMatchInfoResponse +import com.puzzle.network.model.matching.GetOpponentValueTalksResponse import com.puzzle.network.source.matching.MatchingDataSource import javax.inject.Inject @@ -16,7 +19,11 @@ class MatchingRepositoryImpl @Inject constructor( matchingDataSource.blockContacts(phoneNumbers) override suspend fun getMatchInfo(): Result = matchingDataSource.getMatchInfo() - .mapCatching { response -> response.toDomain() } + .mapCatching(GetMatchInfoResponse::toDomain) + + override suspend fun getOpponentValueTalks(): Result> = + matchingDataSource.getOpponentValueTalks() + .mapCatching(GetOpponentValueTalksResponse::toDomain) override suspend fun checkMatchingPiece(): Result = matchingDataSource.checkMatchingPiece() diff --git a/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt b/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt index a2a10ffb..0a7a6475 100644 --- a/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt +++ b/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt @@ -1,12 +1,14 @@ package com.puzzle.domain.repository import com.puzzle.domain.model.match.MatchInfo +import com.puzzle.domain.model.profile.OpponentValueTalk interface MatchingRepository { suspend fun reportUser(userId: Int, reason: String): Result suspend fun blockUser(userId: Int): Result suspend fun blockContacts(phoneNumbers: List): Result suspend fun getMatchInfo(): Result + suspend fun getOpponentValueTalks(): Result> suspend fun checkMatchingPiece(): Result suspend fun acceptMatching(): Result } diff --git a/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt b/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt index 3cd0f45f..17360f28 100644 --- a/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt +++ b/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt @@ -8,6 +8,7 @@ import com.puzzle.network.model.auth.VerifyAuthCodeRequest import com.puzzle.network.model.auth.VerifyAuthCodeResponse import com.puzzle.network.model.matching.BlockContactsRequest import com.puzzle.network.model.matching.GetMatchInfoResponse +import com.puzzle.network.model.matching.GetOpponentValueTalksResponse import com.puzzle.network.model.matching.LoadValuePicksResponse import com.puzzle.network.model.matching.LoadValueTalksResponse import com.puzzle.network.model.matching.ReportUserRequest @@ -20,8 +21,8 @@ import com.puzzle.network.model.token.RefreshTokenResponse import okhttp3.MultipartBody import retrofit2.http.Body import retrofit2.http.GET -import retrofit2.http.PATCH import retrofit2.http.Multipart +import retrofit2.http.PATCH import retrofit2.http.POST import retrofit2.http.Part import retrofit2.http.Path @@ -77,6 +78,9 @@ interface PieceApi { @GET("/api/matches/infos") suspend fun getMatchInfo(): Result> + @GET("/api/matches/values/talks") + suspend fun getOpponentValueTalks(): Result> + @PATCH("/api/matches/pieces/check") suspend fun checkMatchingPiece(): Result> diff --git a/core/network/src/main/java/com/puzzle/network/model/matching/GetOpponentValueTalksResponse.kt b/core/network/src/main/java/com/puzzle/network/model/matching/GetOpponentValueTalksResponse.kt new file mode 100644 index 00000000..24ffc655 --- /dev/null +++ b/core/network/src/main/java/com/puzzle/network/model/matching/GetOpponentValueTalksResponse.kt @@ -0,0 +1,28 @@ +package com.puzzle.network.model.matching + +import com.puzzle.domain.model.profile.OpponentValueTalk +import com.puzzle.network.model.UNKNOWN_STRING +import kotlinx.serialization.Serializable + +@Serializable +data class GetOpponentValueTalksResponse( + val matchId: Int?, + val description: String?, + val nickname: String?, + val valueTalks: List?, +) { + fun toDomain() = valueTalks?.map(OpponentValueTalkResponse::toDomain) ?: emptyList() +} + +@Serializable +data class OpponentValueTalkResponse( + val category: String?, + val summary: String?, + val answer: String?, +) { + fun toDomain() = OpponentValueTalk( + category = category ?: UNKNOWN_STRING, + summary = summary ?: UNKNOWN_STRING, + answer = answer ?: UNKNOWN_STRING, + ) +} diff --git a/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt b/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt index cb987efd..22545cb1 100644 --- a/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt +++ b/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt @@ -3,6 +3,7 @@ package com.puzzle.network.source.matching import com.puzzle.network.api.PieceApi import com.puzzle.network.model.matching.BlockContactsRequest import com.puzzle.network.model.matching.GetMatchInfoResponse +import com.puzzle.network.model.matching.GetOpponentValueTalksResponse import com.puzzle.network.model.matching.ReportUserRequest import com.puzzle.network.model.unwrapData import javax.inject.Inject @@ -20,7 +21,10 @@ class MatchingDataSource @Inject constructor( pieceApi.blockContacts(BlockContactsRequest(phoneNumbers)).unwrapData() suspend fun getMatchInfo(): Result = pieceApi.getMatchInfo().unwrapData() + suspend fun getOpponentValueTalks(): Result = + pieceApi.getOpponentValueTalks().unwrapData() suspend fun checkMatchingPiece(): Result = pieceApi.checkMatchingPiece().unwrapData() suspend fun acceptMatching(): Result = pieceApi.acceptMatching().unwrapData() + } diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt index 85220700..e0d334ed 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt @@ -300,7 +300,7 @@ private fun MatchingDetailContent( ValueTalkPage( nickName = state.nickName, selfDescription = state.selfDescription, - talkCards = state.talkCards, + talkCards = state.valueTalks, onMoreClick = onMoreClick, ) diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt index d3240633..82f918d0 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt @@ -39,6 +39,12 @@ class MatchingDetailViewModel @AssistedInject constructor( private val matchUserId = 0 // Todo 임시 init { + viewModelScope.launch { + matchingRepository.getOpponentValueTalks() + .onSuccess { valueTalks -> setState { copy(valueTalks = valueTalks) } } + .onFailure { errorHelper.sendError(it) } + } + intents.receiveAsFlow() .onEach(::processIntent) .launchIn(viewModelScope) diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt index 88f37d62..b4061616 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt @@ -15,7 +15,7 @@ data class MatchingDetailState( val occupation: String = "개발자", val activityRegion: String = "서울특별시", val smokeStatue: String = "비흡연", - val talkCards: List = emptyList(), + val valueTalks: List = emptyList(), val pickCards: List = emptyList(), val imageUri: String = "", ) : MavericksState { From 999edbed4842bedc8f88f99eb4ce283704a8decf Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Tue, 11 Feb 2025 17:00:20 +0900 Subject: [PATCH 02/12] =?UTF-8?q?[PC-555]=20Matching=20=EC=83=81=EB=8C=80?= =?UTF-8?q?=EB=B0=A9=20ValuePick=20Api=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/MatchingRepositoryImpl.kt | 6 ++++ .../domain/repository/MatchingRepository.kt | 2 ++ .../java/com/puzzle/network/api/PieceApi.kt | 4 +++ .../matching/GetOpponentValuePicksResponse.kt | 34 +++++++++++++++++++ .../source/matching/MatchingDataSource.kt | 4 +++ .../graph/detail/MatchingDetailScreen.kt | 2 +- .../graph/detail/MatchingDetailViewModel.kt | 14 ++++++-- .../detail/contract/MatchingDetailState.kt | 2 +- 8 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 core/network/src/main/java/com/puzzle/network/model/matching/GetOpponentValuePicksResponse.kt diff --git a/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt b/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt index be3c588b..3e553bf1 100644 --- a/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt +++ b/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt @@ -1,9 +1,11 @@ package com.puzzle.data.repository import com.puzzle.domain.model.match.MatchInfo +import com.puzzle.domain.model.profile.OpponentValuePick import com.puzzle.domain.model.profile.OpponentValueTalk import com.puzzle.domain.repository.MatchingRepository import com.puzzle.network.model.matching.GetMatchInfoResponse +import com.puzzle.network.model.matching.GetOpponentValuePicksResponse import com.puzzle.network.model.matching.GetOpponentValueTalksResponse import com.puzzle.network.source.matching.MatchingDataSource import javax.inject.Inject @@ -25,6 +27,10 @@ class MatchingRepositoryImpl @Inject constructor( matchingDataSource.getOpponentValueTalks() .mapCatching(GetOpponentValueTalksResponse::toDomain) + override suspend fun getOpponentValuePicks(): Result> = + matchingDataSource.getOpponentValuePicks() + .mapCatching(GetOpponentValuePicksResponse::toDomain) + override suspend fun checkMatchingPiece(): Result = matchingDataSource.checkMatchingPiece() diff --git a/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt b/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt index 0a7a6475..ea0740cb 100644 --- a/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt +++ b/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt @@ -1,6 +1,7 @@ package com.puzzle.domain.repository import com.puzzle.domain.model.match.MatchInfo +import com.puzzle.domain.model.profile.OpponentValuePick import com.puzzle.domain.model.profile.OpponentValueTalk interface MatchingRepository { @@ -9,6 +10,7 @@ interface MatchingRepository { suspend fun blockContacts(phoneNumbers: List): Result suspend fun getMatchInfo(): Result suspend fun getOpponentValueTalks(): Result> + suspend fun getOpponentValuePicks(): Result> suspend fun checkMatchingPiece(): Result suspend fun acceptMatching(): Result } diff --git a/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt b/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt index 17360f28..14dfbd4d 100644 --- a/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt +++ b/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt @@ -8,6 +8,7 @@ import com.puzzle.network.model.auth.VerifyAuthCodeRequest import com.puzzle.network.model.auth.VerifyAuthCodeResponse import com.puzzle.network.model.matching.BlockContactsRequest import com.puzzle.network.model.matching.GetMatchInfoResponse +import com.puzzle.network.model.matching.GetOpponentValuePicksResponse import com.puzzle.network.model.matching.GetOpponentValueTalksResponse import com.puzzle.network.model.matching.LoadValuePicksResponse import com.puzzle.network.model.matching.LoadValueTalksResponse @@ -81,6 +82,9 @@ interface PieceApi { @GET("/api/matches/values/talks") suspend fun getOpponentValueTalks(): Result> + @GET("/api/matches/values/picks") + suspend fun getOpponentValuePicks(): Result> + @PATCH("/api/matches/pieces/check") suspend fun checkMatchingPiece(): Result> diff --git a/core/network/src/main/java/com/puzzle/network/model/matching/GetOpponentValuePicksResponse.kt b/core/network/src/main/java/com/puzzle/network/model/matching/GetOpponentValuePicksResponse.kt new file mode 100644 index 00000000..3dfad065 --- /dev/null +++ b/core/network/src/main/java/com/puzzle/network/model/matching/GetOpponentValuePicksResponse.kt @@ -0,0 +1,34 @@ +package com.puzzle.network.model.matching + +import com.puzzle.domain.model.profile.OpponentValuePick +import com.puzzle.network.model.UNKNOWN_INT +import com.puzzle.network.model.UNKNOWN_STRING +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class GetOpponentValuePicksResponse( + val matchId: Int?, + val description: String?, + val nickname: String?, + val valuePicks: List?, +) { + fun toDomain() = valuePicks?.map(OpponentValuePickResponse::toDomain) ?: emptyList() +} + +@Serializable +data class OpponentValuePickResponse( + val category: String?, + val question: String?, + @SerialName("sameWithMe") val isSameWithMe: Boolean?, + @SerialName("answer") val answerOptions: List?, + @SerialName("answerNumber") val selectedAnswer: Int?, +) { + fun toDomain() = OpponentValuePick( + category = category ?: UNKNOWN_STRING, + question = question ?: UNKNOWN_STRING, + isSameWithMe = isSameWithMe ?: false, + answerOptions = answerOptions?.map(ValuePickAnswerResponse::toDomain) ?: emptyList(), + selectedAnswer = selectedAnswer ?: UNKNOWN_INT, + ) +} diff --git a/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt b/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt index 22545cb1..b1984760 100644 --- a/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt +++ b/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt @@ -3,6 +3,7 @@ package com.puzzle.network.source.matching import com.puzzle.network.api.PieceApi import com.puzzle.network.model.matching.BlockContactsRequest import com.puzzle.network.model.matching.GetMatchInfoResponse +import com.puzzle.network.model.matching.GetOpponentValuePicksResponse import com.puzzle.network.model.matching.GetOpponentValueTalksResponse import com.puzzle.network.model.matching.ReportUserRequest import com.puzzle.network.model.unwrapData @@ -24,6 +25,9 @@ class MatchingDataSource @Inject constructor( suspend fun getOpponentValueTalks(): Result = pieceApi.getOpponentValueTalks().unwrapData() + suspend fun getOpponentValuePicks(): Result = + pieceApi.getOpponentValuePicks().unwrapData() + suspend fun checkMatchingPiece(): Result = pieceApi.checkMatchingPiece().unwrapData() suspend fun acceptMatching(): Result = pieceApi.acceptMatching().unwrapData() diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt index e0d334ed..6f9a418f 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt @@ -308,7 +308,7 @@ private fun MatchingDetailContent( ValuePickPage( nickName = state.nickName, selfDescription = state.selfDescription, - pickCards = state.pickCards, + pickCards = state.valuePicks, onDeclineClick = onDeclineClick, ) } diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt index 82f918d0..37e9d442 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt @@ -40,9 +40,17 @@ class MatchingDetailViewModel @AssistedInject constructor( init { viewModelScope.launch { - matchingRepository.getOpponentValueTalks() - .onSuccess { valueTalks -> setState { copy(valueTalks = valueTalks) } } - .onFailure { errorHelper.sendError(it) } + launch { + matchingRepository.getOpponentValueTalks() + .onSuccess { valueTalks -> setState { copy(valueTalks = valueTalks) } } + .onFailure { errorHelper.sendError(it) } + } + + launch { + matchingRepository.getOpponentValuePicks() + .onSuccess { valuePicks -> setState { copy(valuePicks = valuePicks) } } + .onFailure { errorHelper.sendError(it) } + } } intents.receiveAsFlow() diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt index b4061616..2b92eeaa 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt @@ -16,7 +16,7 @@ data class MatchingDetailState( val activityRegion: String = "서울특별시", val smokeStatue: String = "비흡연", val valueTalks: List = emptyList(), - val pickCards: List = emptyList(), + val valuePicks: List = emptyList(), val imageUri: String = "", ) : MavericksState { From 8aa89b966f2ae6ccf7e31ba9a65d4bfb10484e4d Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Tue, 11 Feb 2025 17:18:33 +0900 Subject: [PATCH 03/12] =?UTF-8?q?[PC-555]=20Matching=20=EC=83=81=EB=8C=80?= =?UTF-8?q?=EB=B0=A9=20ProfileBasic=20Api=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/MatchingRepositoryImpl.kt | 6 ++ .../model/profile/OpponentProfileBasic.kt | 13 ++++ .../domain/repository/MatchingRepository.kt | 2 + .../java/com/puzzle/network/api/PieceApi.kt | 4 ++ .../GetOpponentProfileBasicResponse.kt | 32 +++++++++ .../source/matching/MatchingDataSource.kt | 4 ++ .../graph/detail/MatchingDetailScreen.kt | 17 ++--- .../graph/detail/MatchingDetailViewModel.kt | 71 +++++++++++++------ .../detail/contract/MatchingDetailState.kt | 17 ++--- .../graph/detail/page/BasicInfoPage.kt | 8 ++- 10 files changed, 134 insertions(+), 40 deletions(-) create mode 100644 core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentProfileBasic.kt create mode 100644 core/network/src/main/java/com/puzzle/network/model/matching/GetOpponentProfileBasicResponse.kt diff --git a/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt b/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt index 3e553bf1..e0872ee5 100644 --- a/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt +++ b/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt @@ -1,10 +1,12 @@ package com.puzzle.data.repository import com.puzzle.domain.model.match.MatchInfo +import com.puzzle.domain.model.profile.OpponentProfileBasic import com.puzzle.domain.model.profile.OpponentValuePick import com.puzzle.domain.model.profile.OpponentValueTalk import com.puzzle.domain.repository.MatchingRepository import com.puzzle.network.model.matching.GetMatchInfoResponse +import com.puzzle.network.model.matching.GetOpponentProfileBasicResponse import com.puzzle.network.model.matching.GetOpponentValuePicksResponse import com.puzzle.network.model.matching.GetOpponentValueTalksResponse import com.puzzle.network.source.matching.MatchingDataSource @@ -31,6 +33,10 @@ class MatchingRepositoryImpl @Inject constructor( matchingDataSource.getOpponentValuePicks() .mapCatching(GetOpponentValuePicksResponse::toDomain) + override suspend fun getOpponentProfileBasic(): Result = + matchingDataSource.getOpponentProfileBasic() + .mapCatching(GetOpponentProfileBasicResponse::toDomain) + override suspend fun checkMatchingPiece(): Result = matchingDataSource.checkMatchingPiece() diff --git a/core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentProfileBasic.kt b/core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentProfileBasic.kt new file mode 100644 index 00000000..32a4cf97 --- /dev/null +++ b/core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentProfileBasic.kt @@ -0,0 +1,13 @@ +package com.puzzle.domain.model.profile + +data class OpponentProfileBasic( + val description: String, + val nickname: String, + val age: Int, + val birthYear: String, + val height: Int, + val weight: Int, + val location: String, + val job: String, + val smokingStatus: String, +) diff --git a/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt b/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt index ea0740cb..feb35669 100644 --- a/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt +++ b/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt @@ -1,6 +1,7 @@ package com.puzzle.domain.repository import com.puzzle.domain.model.match.MatchInfo +import com.puzzle.domain.model.profile.OpponentProfileBasic import com.puzzle.domain.model.profile.OpponentValuePick import com.puzzle.domain.model.profile.OpponentValueTalk @@ -11,6 +12,7 @@ interface MatchingRepository { suspend fun getMatchInfo(): Result suspend fun getOpponentValueTalks(): Result> suspend fun getOpponentValuePicks(): Result> + suspend fun getOpponentProfileBasic(): Result suspend fun checkMatchingPiece(): Result suspend fun acceptMatching(): Result } diff --git a/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt b/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt index 14dfbd4d..f804c10a 100644 --- a/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt +++ b/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt @@ -8,6 +8,7 @@ import com.puzzle.network.model.auth.VerifyAuthCodeRequest import com.puzzle.network.model.auth.VerifyAuthCodeResponse import com.puzzle.network.model.matching.BlockContactsRequest import com.puzzle.network.model.matching.GetMatchInfoResponse +import com.puzzle.network.model.matching.GetOpponentProfileBasicResponse import com.puzzle.network.model.matching.GetOpponentValuePicksResponse import com.puzzle.network.model.matching.GetOpponentValueTalksResponse import com.puzzle.network.model.matching.LoadValuePicksResponse @@ -85,6 +86,9 @@ interface PieceApi { @GET("/api/matches/values/picks") suspend fun getOpponentValuePicks(): Result> + @GET("/api/matches/profiles/basic") + suspend fun getOpponentProfileBasic(): Result> + @PATCH("/api/matches/pieces/check") suspend fun checkMatchingPiece(): Result> diff --git a/core/network/src/main/java/com/puzzle/network/model/matching/GetOpponentProfileBasicResponse.kt b/core/network/src/main/java/com/puzzle/network/model/matching/GetOpponentProfileBasicResponse.kt new file mode 100644 index 00000000..7e6661c5 --- /dev/null +++ b/core/network/src/main/java/com/puzzle/network/model/matching/GetOpponentProfileBasicResponse.kt @@ -0,0 +1,32 @@ +package com.puzzle.network.model.matching + +import com.puzzle.domain.model.profile.OpponentProfileBasic +import com.puzzle.network.model.UNKNOWN_INT +import com.puzzle.network.model.UNKNOWN_STRING +import kotlinx.serialization.Serializable + +@Serializable +data class GetOpponentProfileBasicResponse( + val matchId: Int?, + val description: String?, + val nickname: String?, + val age: Int?, + val birthYear: String?, + val height: Int?, + val weight: Int?, + val location: String?, + val job: String?, + val smokingStatus: String?, +) { + fun toDomain() = OpponentProfileBasic( + description = description ?: UNKNOWN_STRING, + nickname = nickname ?: UNKNOWN_STRING, + age = age ?: UNKNOWN_INT, + birthYear = birthYear ?: UNKNOWN_STRING, + height = height ?: UNKNOWN_INT, + weight = weight ?: UNKNOWN_INT, + location = location ?: UNKNOWN_STRING, + job = job ?: UNKNOWN_STRING, + smokingStatus = smokingStatus ?: UNKNOWN_STRING, + ) +} diff --git a/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt b/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt index b1984760..0ecd5963 100644 --- a/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt +++ b/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt @@ -3,6 +3,7 @@ package com.puzzle.network.source.matching import com.puzzle.network.api.PieceApi import com.puzzle.network.model.matching.BlockContactsRequest import com.puzzle.network.model.matching.GetMatchInfoResponse +import com.puzzle.network.model.matching.GetOpponentProfileBasicResponse import com.puzzle.network.model.matching.GetOpponentValuePicksResponse import com.puzzle.network.model.matching.GetOpponentValueTalksResponse import com.puzzle.network.model.matching.ReportUserRequest @@ -28,6 +29,9 @@ class MatchingDataSource @Inject constructor( suspend fun getOpponentValuePicks(): Result = pieceApi.getOpponentValuePicks().unwrapData() + suspend fun getOpponentProfileBasic(): Result = + pieceApi.getOpponentProfileBasic().unwrapData() + suspend fun checkMatchingPiece(): Result = pieceApi.checkMatchingPiece().unwrapData() suspend fun acceptMatching(): Result = pieceApi.acceptMatching().unwrapData() diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt index 6f9a418f..b7da76ae 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt @@ -285,29 +285,30 @@ private fun MatchingDetailContent( when (it) { MatchingDetailState.MatchingDetailPage.BasicInfoPage -> BasicInfoPage( - nickName = state.nickName, - selfDescription = state.selfDescription, + nickName = state.nickname, + selfDescription = state.description, birthYear = state.birthYear, age = state.age, height = state.height, - activityRegion = state.activityRegion, - occupation = state.occupation, + weight = state.weight, + activityRegion = state.location, + occupation = state.job, smokeStatue = state.smokeStatue, onMoreClick = onMoreClick, ) MatchingDetailState.MatchingDetailPage.ValueTalkPage -> ValueTalkPage( - nickName = state.nickName, - selfDescription = state.selfDescription, + nickName = state.nickname, + selfDescription = state.description, talkCards = state.valueTalks, onMoreClick = onMoreClick, ) MatchingDetailState.MatchingDetailPage.ValuePickPage -> ValuePickPage( - nickName = state.nickName, - selfDescription = state.selfDescription, + nickName = state.nickname, + selfDescription = state.description, pickCards = state.valuePicks, onDeclineClick = onDeclineClick, ) diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt index 37e9d442..d34e89a3 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt @@ -39,25 +39,54 @@ class MatchingDetailViewModel @AssistedInject constructor( private val matchUserId = 0 // Todo 임시 init { - viewModelScope.launch { - launch { - matchingRepository.getOpponentValueTalks() - .onSuccess { valueTalks -> setState { copy(valueTalks = valueTalks) } } - .onFailure { errorHelper.sendError(it) } - } - - launch { - matchingRepository.getOpponentValuePicks() - .onSuccess { valuePicks -> setState { copy(valuePicks = valuePicks) } } - .onFailure { errorHelper.sendError(it) } - } - } + initMatchDetailInfo() intents.receiveAsFlow() .onEach(::processIntent) .launchIn(viewModelScope) } + private fun initMatchDetailInfo() = viewModelScope.launch { + setState { copy(isLoading = true) } + + val valueTalksJob = launch { + matchingRepository.getOpponentValueTalks() + .onSuccess { valueTalks -> setState { copy(valueTalks = valueTalks) } } + .onFailure { errorHelper.sendError(it) } + } + + val valuePicksJob = launch { + matchingRepository.getOpponentValuePicks() + .onSuccess { valuePicks -> setState { copy(valuePicks = valuePicks) } } + .onFailure { errorHelper.sendError(it) } + } + + val profileBasicJob = launch { + matchingRepository.getOpponentProfileBasic() + .onSuccess { profileBasic -> + setState { + copy( + description = profileBasic.description, + nickname = profileBasic.nickname, + age = profileBasic.age.toString(), + weight = profileBasic.weight.toString(), + height = profileBasic.height.toString(), + birthYear = profileBasic.birthYear, + job = profileBasic.job, + location = profileBasic.location, + smokeStatue = profileBasic.smokingStatus, + ) + } + } + .onFailure { errorHelper.sendError(it) } + } + + valuePicksJob.join() + valueTalksJob.join() + profileBasicJob.join() + setState { copy(isLoading = false) } + } + internal fun onIntent(intent: MatchingDetailIntent) = viewModelScope.launch { intents.send(intent) } @@ -65,7 +94,9 @@ class MatchingDetailViewModel @AssistedInject constructor( private suspend fun processIntent(intent: MatchingDetailIntent) { when (intent) { is MatchingDetailIntent.OnMoreClick -> showBottomSheet(intent.content) - MatchingDetailIntent.OnMatchingDetailCloseClick -> navigateTo(NavigationEvent.NavigateUp) + MatchingDetailIntent.OnMatchingDetailCloseClick -> + navigationHelper.navigate(NavigationEvent.NavigateUp) + MatchingDetailIntent.OnPreviousPageClick -> setPreviousPage() MatchingDetailIntent.OnNextPageClick -> setNextPage() MatchingDetailIntent.OnBlockClick -> onBlockClick() @@ -88,11 +119,11 @@ class MatchingDetailViewModel @AssistedInject constructor( private fun onBlockClick() { withState { - navigateTo( + navigationHelper.navigate( NavigationEvent.NavigateTo( MatchingGraphDest.BlockRoute( userId = matchUserId, - userName = it.nickName, + userName = it.nickname, ) ) ) @@ -103,11 +134,11 @@ class MatchingDetailViewModel @AssistedInject constructor( private fun onReportClick() { withState { - navigateTo( + navigationHelper.navigate( NavigationEvent.NavigateTo( MatchingGraphDest.ReportRoute( userId = matchUserId, - userName = it.nickName, + userName = it.nickname, ) ) ) @@ -129,10 +160,6 @@ class MatchingDetailViewModel @AssistedInject constructor( .onFailure { errorHelper.sendError(it) } } - private fun navigateTo(navigationEvent: NavigationEvent) { - _sideEffects.trySend(MatchingDetailSideEffect.Navigate(navigationEvent)) - } - private fun showBottomSheet(content: @Composable () -> Unit) { eventHelper.sendEvent(PieceEvent.ShowBottomSheet(content)) } diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt index 2b92eeaa..bbab525b 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt @@ -7,14 +7,15 @@ import com.puzzle.domain.model.profile.OpponentValueTalk data class MatchingDetailState( val isLoading: Boolean = false, val currentPage: MatchingDetailPage = MatchingDetailPage.BasicInfoPage, - val selfDescription: String = "음악과 요리를 좋아하는", - val nickName: String = "수줍은 수달", - val age: String = "25", - val birthYear: String = "00", - val height: String = "254", - val occupation: String = "개발자", - val activityRegion: String = "서울특별시", - val smokeStatue: String = "비흡연", + val description: String = "", + val nickname: String = "", + val age: String = "", + val birthYear: String = "", + val height: String = "", + val weight: String = "", + val job: String = "", + val location: String = "", + val smokeStatue: String = "", val valueTalks: List = emptyList(), val valuePicks: List = emptyList(), val imageUri: String = "", diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/page/BasicInfoPage.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/page/BasicInfoPage.kt index 66b5ed6e..1c4a33cb 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/page/BasicInfoPage.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/page/BasicInfoPage.kt @@ -32,6 +32,7 @@ internal fun BasicInfoPage( birthYear: String, age: String, height: String, + weight: String, activityRegion: String, occupation: String, smokeStatue: String, @@ -52,6 +53,7 @@ internal fun BasicInfoPage( age = age, birthYear = birthYear, height = height, + weight = weight, activityRegion = activityRegion, occupation = occupation, smokeStatue = smokeStatue, @@ -85,10 +87,11 @@ private fun BasicInfoName( } @Composable -private fun ColumnScope.BasicInfoCard( +private fun BasicInfoCard( age: String, birthYear: String, height: String, + weight: String, activityRegion: String, occupation: String, smokeStatue: String, @@ -165,7 +168,7 @@ private fun ColumnScope.BasicInfoCard( text = { Row(verticalAlignment = Alignment.CenterVertically) { Text( - text = "72", + text = weight, style = PieceTheme.typography.headingSSB, color = PieceTheme.colors.black, ) @@ -258,6 +261,7 @@ private fun ProfileBasicInfoPagePreview() { birthYear = "1994", age = "31", height = "200", + weight = "72", activityRegion = "서울특별시", occupation = "개발자", smokeStatue = "비흡연", From 6d7b9bb35b522c2a5fc5dede69674e3dda78bd70 Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Tue, 11 Feb 2025 17:25:41 +0900 Subject: [PATCH 04/12] =?UTF-8?q?[PC-555]=20Matching=20=EC=83=81=EB=8C=80?= =?UTF-8?q?=EB=B0=A9=20ProfileImage=20Api=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../puzzle/data/repository/MatchingRepositoryImpl.kt | 5 +++++ .../puzzle/domain/repository/MatchingRepository.kt | 1 + .../src/main/java/com/puzzle/network/api/PieceApi.kt | 3 +++ .../model/matching/GetOpponentProfileImageResponse.kt | 11 +++++++++++ .../network/source/matching/MatchingDataSource.kt | 4 ++++ .../matching/graph/detail/MatchingDetailScreen.kt | 2 +- .../matching/graph/detail/MatchingDetailViewModel.kt | 7 +++++++ .../graph/detail/contract/MatchingDetailState.kt | 2 +- 8 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 core/network/src/main/java/com/puzzle/network/model/matching/GetOpponentProfileImageResponse.kt diff --git a/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt b/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt index e0872ee5..37db1756 100644 --- a/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt +++ b/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt @@ -7,6 +7,7 @@ import com.puzzle.domain.model.profile.OpponentValueTalk import com.puzzle.domain.repository.MatchingRepository import com.puzzle.network.model.matching.GetMatchInfoResponse import com.puzzle.network.model.matching.GetOpponentProfileBasicResponse +import com.puzzle.network.model.matching.GetOpponentProfileImageResponse import com.puzzle.network.model.matching.GetOpponentValuePicksResponse import com.puzzle.network.model.matching.GetOpponentValueTalksResponse import com.puzzle.network.source.matching.MatchingDataSource @@ -37,6 +38,10 @@ class MatchingRepositoryImpl @Inject constructor( matchingDataSource.getOpponentProfileBasic() .mapCatching(GetOpponentProfileBasicResponse::toDomain) + override suspend fun getOpponentProfileImage(): Result = + matchingDataSource.getOpponentProfileImage() + .mapCatching(GetOpponentProfileImageResponse::toDomain) + override suspend fun checkMatchingPiece(): Result = matchingDataSource.checkMatchingPiece() diff --git a/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt b/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt index feb35669..b2743cf4 100644 --- a/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt +++ b/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt @@ -13,6 +13,7 @@ interface MatchingRepository { suspend fun getOpponentValueTalks(): Result> suspend fun getOpponentValuePicks(): Result> suspend fun getOpponentProfileBasic(): Result + suspend fun getOpponentProfileImage(): Result suspend fun checkMatchingPiece(): Result suspend fun acceptMatching(): Result } diff --git a/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt b/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt index f804c10a..55bb0943 100644 --- a/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt +++ b/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt @@ -89,6 +89,9 @@ interface PieceApi { @GET("/api/matches/profiles/basic") suspend fun getOpponentProfileBasic(): Result> + @GET("/api/matches/images") + suspend fun getOpponentProfileImage(): Result> + @PATCH("/api/matches/pieces/check") suspend fun checkMatchingPiece(): Result> diff --git a/core/network/src/main/java/com/puzzle/network/model/matching/GetOpponentProfileImageResponse.kt b/core/network/src/main/java/com/puzzle/network/model/matching/GetOpponentProfileImageResponse.kt new file mode 100644 index 00000000..8f4669c5 --- /dev/null +++ b/core/network/src/main/java/com/puzzle/network/model/matching/GetOpponentProfileImageResponse.kt @@ -0,0 +1,11 @@ +package com.puzzle.network.model.matching + +import com.puzzle.network.model.UNKNOWN_STRING +import kotlinx.serialization.Serializable + +@Serializable +data class GetOpponentProfileImageResponse( + val imageUrl: String?, +) { + fun toDomain(): String = imageUrl ?: UNKNOWN_STRING +} diff --git a/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt b/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt index 0ecd5963..da99ece5 100644 --- a/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt +++ b/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt @@ -4,6 +4,7 @@ import com.puzzle.network.api.PieceApi import com.puzzle.network.model.matching.BlockContactsRequest import com.puzzle.network.model.matching.GetMatchInfoResponse import com.puzzle.network.model.matching.GetOpponentProfileBasicResponse +import com.puzzle.network.model.matching.GetOpponentProfileImageResponse import com.puzzle.network.model.matching.GetOpponentValuePicksResponse import com.puzzle.network.model.matching.GetOpponentValueTalksResponse import com.puzzle.network.model.matching.ReportUserRequest @@ -32,6 +33,9 @@ class MatchingDataSource @Inject constructor( suspend fun getOpponentProfileBasic(): Result = pieceApi.getOpponentProfileBasic().unwrapData() + suspend fun getOpponentProfileImage(): Result = + pieceApi.getOpponentProfileImage().unwrapData() + suspend fun checkMatchingPiece(): Result = pieceApi.checkMatchingPiece().unwrapData() suspend fun acceptMatching(): Result = pieceApi.acceptMatching().unwrapData() diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt index b7da76ae..c9e57749 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt @@ -167,7 +167,7 @@ private fun MatchingDetailScreen( DialogType.PROFILE_IMAGE_DETAIL -> { PieceImageDialog( - imageUri = state.imageUri, + imageUri = state.imageUrl, buttonLabel = "매칭 수락하기", onButtonClick = { dialogType = DialogType.ACCEPT_MATCHING }, onDismissRequest = { showDialog = false }, diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt index d34e89a3..644947bd 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt @@ -81,9 +81,16 @@ class MatchingDetailViewModel @AssistedInject constructor( .onFailure { errorHelper.sendError(it) } } + val profileImageJob = launch { + matchingRepository.getOpponentProfileImage() + .onSuccess { profileImageUrl -> setState { copy(imageUrl = profileImageUrl) } } + .onFailure { errorHelper.sendError(it) } + } + valuePicksJob.join() valueTalksJob.join() profileBasicJob.join() + profileImageJob.join() setState { copy(isLoading = false) } } diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt index bbab525b..f06c92fe 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt @@ -18,7 +18,7 @@ data class MatchingDetailState( val smokeStatue: String = "", val valueTalks: List = emptyList(), val valuePicks: List = emptyList(), - val imageUri: String = "", + val imageUrl: String = "", ) : MavericksState { enum class MatchingDetailPage(val title: String) { From f85e2581d53908640118661ab48cf9032644f4fa Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Tue, 11 Feb 2025 17:50:18 +0900 Subject: [PATCH 05/12] =?UTF-8?q?[PC-555]=20MatchingDetail=20=EB=8D=94?= =?UTF-8?q?=EB=AF=B8=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EA=B1=B7=EC=96=B4?= =?UTF-8?q?=EB=82=B4=EA=B3=A0=20=EC=8B=A4=EC=A0=9C=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../puzzle/designsystem/component/Loading.kt | 8 ++ .../domain/model/profile/OpponentProfile.kt | 42 +++++++ .../model/profile/OpponentProfileBasic.kt | 13 --- .../domain/model/profile/OpponentValuePick.kt | 9 -- .../domain/model/profile/OpponentValueTalk.kt | 7 -- .../matching/GetOpponentProfileUseCase.kt | 41 +++++++ .../java/com/puzzle/network/api/PieceApi.kt | 1 + .../graph/detail/MatchingDetailScreen.kt | 108 ++++++++++-------- .../graph/detail/MatchingDetailViewModel.kt | 56 ++------- .../detail/contract/MatchingDetailState.kt | 16 +-- .../graph/detail/page/BasicInfoPage.kt | 30 ++--- 11 files changed, 182 insertions(+), 149 deletions(-) create mode 100644 core/designsystem/src/main/java/com/puzzle/designsystem/component/Loading.kt create mode 100644 core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentProfile.kt delete mode 100644 core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentProfileBasic.kt delete mode 100644 core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentValuePick.kt delete mode 100644 core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentValueTalk.kt create mode 100644 core/domain/src/main/java/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCase.kt diff --git a/core/designsystem/src/main/java/com/puzzle/designsystem/component/Loading.kt b/core/designsystem/src/main/java/com/puzzle/designsystem/component/Loading.kt new file mode 100644 index 00000000..80c5efe6 --- /dev/null +++ b/core/designsystem/src/main/java/com/puzzle/designsystem/component/Loading.kt @@ -0,0 +1,8 @@ +package com.puzzle.designsystem.component + +import androidx.compose.runtime.Composable + +@Composable +fun PieceLoading() { + // TODO +} diff --git a/core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentProfile.kt b/core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentProfile.kt new file mode 100644 index 00000000..20b9b4e2 --- /dev/null +++ b/core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentProfile.kt @@ -0,0 +1,42 @@ +package com.puzzle.domain.model.profile + +data class OpponentProfile( + val description: String, + val nickname: String, + val age: Int, + val birthYear: String, + val height: Int, + val weight: Int, + val location: String, + val job: String, + val smokingStatus: String, + val valuePicks: List, + val valueTalks: List, + val imageUrl: String, +) + +data class OpponentProfileBasic( + val description: String, + val nickname: String, + val age: Int, + val birthYear: String, + val height: Int, + val weight: Int, + val location: String, + val job: String, + val smokingStatus: String, +) + +data class OpponentValuePick( + val category: String, + val question: String, + val answerOptions: List, + val selectedAnswer: Int, + val isSameWithMe: Boolean, +) + +data class OpponentValueTalk( + val category: String, + val summary: String, + val answer: String, +) diff --git a/core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentProfileBasic.kt b/core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentProfileBasic.kt deleted file mode 100644 index 32a4cf97..00000000 --- a/core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentProfileBasic.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.puzzle.domain.model.profile - -data class OpponentProfileBasic( - val description: String, - val nickname: String, - val age: Int, - val birthYear: String, - val height: Int, - val weight: Int, - val location: String, - val job: String, - val smokingStatus: String, -) diff --git a/core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentValuePick.kt b/core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentValuePick.kt deleted file mode 100644 index 6b1561c1..00000000 --- a/core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentValuePick.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.puzzle.domain.model.profile - -data class OpponentValuePick( - val category: String, - val question: String, - val answerOptions: List, - val selectedAnswer: Int, - val isSameWithMe: Boolean, -) diff --git a/core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentValueTalk.kt b/core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentValueTalk.kt deleted file mode 100644 index f284b564..00000000 --- a/core/domain/src/main/java/com/puzzle/domain/model/profile/OpponentValueTalk.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.puzzle.domain.model.profile - -data class OpponentValueTalk( - val category: String, - val summary: String, - val answer: String, -) diff --git a/core/domain/src/main/java/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCase.kt b/core/domain/src/main/java/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCase.kt new file mode 100644 index 00000000..e0dc6c24 --- /dev/null +++ b/core/domain/src/main/java/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCase.kt @@ -0,0 +1,41 @@ +package com.puzzle.domain.usecase.matching + +import com.puzzle.common.suspendRunCatching +import com.puzzle.domain.model.profile.OpponentProfile +import com.puzzle.domain.repository.MatchingRepository +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope +import javax.inject.Inject + +class GetOpponentProfileUseCase @Inject constructor( + private val matchingRepository: MatchingRepository, +) { + suspend operator fun invoke(): Result = suspendRunCatching { + coroutineScope { + val valueTalksDeferred = async { matchingRepository.getOpponentValueTalks() } + val valuePicksDeferred = async { matchingRepository.getOpponentValuePicks() } + val profileBasicDeferred = async { matchingRepository.getOpponentProfileBasic() } + val profileImageDeferred = async { matchingRepository.getOpponentProfileImage() } + + val valuePicks = valuePicksDeferred.await().getOrThrow() + val valueTalks = valueTalksDeferred.await().getOrThrow() + val profileBasic = profileBasicDeferred.await().getOrThrow() + val imageUrl = profileImageDeferred.await().getOrThrow() + + OpponentProfile( + description = profileBasic.description, + nickname = profileBasic.nickname, + age = profileBasic.age, + birthYear = profileBasic.birthYear, + height = profileBasic.height, + weight = profileBasic.weight, + location = profileBasic.location, + job = profileBasic.job, + smokingStatus = profileBasic.smokingStatus, + valuePicks = valuePicks, + valueTalks = valueTalks, + imageUrl = imageUrl, + ) + } + } +} diff --git a/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt b/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt index 55bb0943..85ee07b1 100644 --- a/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt +++ b/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt @@ -9,6 +9,7 @@ import com.puzzle.network.model.auth.VerifyAuthCodeResponse import com.puzzle.network.model.matching.BlockContactsRequest import com.puzzle.network.model.matching.GetMatchInfoResponse import com.puzzle.network.model.matching.GetOpponentProfileBasicResponse +import com.puzzle.network.model.matching.GetOpponentProfileImageResponse import com.puzzle.network.model.matching.GetOpponentValuePicksResponse import com.puzzle.network.model.matching.GetOpponentValueTalksResponse import com.puzzle.network.model.matching.LoadValuePicksResponse diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt index c9e57749..6b80856e 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailScreen.kt @@ -42,9 +42,11 @@ import com.puzzle.designsystem.component.PieceDialog import com.puzzle.designsystem.component.PieceDialogBottom import com.puzzle.designsystem.component.PieceDialogDefaultTop import com.puzzle.designsystem.component.PieceImageDialog +import com.puzzle.designsystem.component.PieceLoading import com.puzzle.designsystem.component.PieceRoundingButton import com.puzzle.designsystem.component.PieceSubCloseTopBar import com.puzzle.designsystem.foundation.PieceTheme +import com.puzzle.domain.model.profile.OpponentProfile import com.puzzle.matching.graph.detail.bottomsheet.MatchingDetailMoreBottomSheet import com.puzzle.matching.graph.detail.common.constant.DialogType import com.puzzle.matching.graph.detail.contract.MatchingDetailIntent @@ -167,7 +169,7 @@ private fun MatchingDetailScreen( DialogType.PROFILE_IMAGE_DETAIL -> { PieceImageDialog( - imageUri = state.imageUrl, + imageUri = state.profile?.imageUrl, buttonLabel = "매칭 수락하기", onButtonClick = { dialogType = DialogType.ACCEPT_MATCHING }, onDismissRequest = { showDialog = false }, @@ -216,13 +218,13 @@ private fun MatchingDetailScreen( .fillMaxWidth() .height(topBarHeight) .align(Alignment.TopCenter) - .let { + .then( if (state.currentPage != MatchingDetailPage.BasicInfoPage) { - it.background(PieceTheme.colors.white) + Modifier.background(PieceTheme.colors.white) } else { - it + Modifier } - } + ) .padding(horizontal = 20.dp), ) @@ -254,10 +256,7 @@ private fun MatchingDetailScreen( @Composable private fun BackgroundImage(modifier: Modifier = Modifier) { - Box( - modifier = modifier - .fillMaxSize() - ) { + Box(modifier = modifier.fillMaxSize()) { Image( painter = painterResource(id = R.drawable.matchingdetail_bg), contentDescription = "basic info 배경화면", @@ -275,45 +274,47 @@ private fun MatchingDetailContent( modifier: Modifier = Modifier, ) { Box(modifier = modifier.fillMaxSize()) { - AnimatedContent( - targetState = state.currentPage, - transitionSpec = { - fadeIn(tween(700)) togetherWith fadeOut(tween(700)) - }, - modifier = Modifier.fillMaxSize(), - ) { - when (it) { - MatchingDetailState.MatchingDetailPage.BasicInfoPage -> - BasicInfoPage( - nickName = state.nickname, - selfDescription = state.description, - birthYear = state.birthYear, - age = state.age, - height = state.height, - weight = state.weight, - activityRegion = state.location, - occupation = state.job, - smokeStatue = state.smokeStatue, - onMoreClick = onMoreClick, - ) + state.profile?.let { profile -> + AnimatedContent( + targetState = state.currentPage, + transitionSpec = { + fadeIn(tween(700)) togetherWith fadeOut(tween(700)) + }, + modifier = Modifier.fillMaxSize(), + ) { + when (it) { + MatchingDetailPage.BasicInfoPage -> + BasicInfoPage( + nickName = profile.nickname, + selfDescription = profile.description, + birthYear = profile.birthYear, + age = profile.age, + height = profile.height, + weight = profile.weight, + activityRegion = profile.location, + occupation = profile.job, + smokingStatus = profile.smokingStatus, + onMoreClick = onMoreClick, + ) - MatchingDetailState.MatchingDetailPage.ValueTalkPage -> - ValueTalkPage( - nickName = state.nickname, - selfDescription = state.description, - talkCards = state.valueTalks, - onMoreClick = onMoreClick, - ) + MatchingDetailPage.ValueTalkPage -> + ValueTalkPage( + nickName = profile.nickname, + selfDescription = profile.description, + talkCards = profile.valueTalks, + onMoreClick = onMoreClick, + ) - MatchingDetailState.MatchingDetailPage.ValuePickPage -> - ValuePickPage( - nickName = state.nickname, - selfDescription = state.description, - pickCards = state.valuePicks, - onDeclineClick = onDeclineClick, - ) + MatchingDetailPage.ValuePickPage -> + ValuePickPage( + nickName = profile.nickname, + selfDescription = profile.description, + pickCards = profile.valuePicks, + onDeclineClick = onDeclineClick, + ) + } } - } + } ?: PieceLoading() } } @@ -387,7 +388,22 @@ private fun MatchingDetailBottomBar( private fun MatchingDetailScreenPreview() { PieceTheme { MatchingDetailScreen( - MatchingDetailState(), + MatchingDetailState( + profile = OpponentProfile( + description = "음악과 요리를 좋아하는", + nickname = "수줍은 수달", + birthYear = "00", + age = 25, + height = 254, + weight = 72, + job = "개발자", + location = "서울특별시", + smokingStatus = "비흡연", + valueTalks = emptyList(), + valuePicks = emptyList(), + imageUrl = "", + ) + ), {}, {}, {}, diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt index 644947bd..cdc86a8e 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/MatchingDetailViewModel.kt @@ -9,6 +9,7 @@ import com.puzzle.common.event.EventHelper import com.puzzle.common.event.PieceEvent import com.puzzle.domain.model.error.ErrorHelper import com.puzzle.domain.repository.MatchingRepository +import com.puzzle.domain.usecase.matching.GetOpponentProfileUseCase import com.puzzle.matching.graph.detail.contract.MatchingDetailIntent import com.puzzle.matching.graph.detail.contract.MatchingDetailSideEffect import com.puzzle.matching.graph.detail.contract.MatchingDetailState @@ -27,6 +28,7 @@ import kotlinx.coroutines.launch class MatchingDetailViewModel @AssistedInject constructor( @Assisted initialState: MatchingDetailState, + private val getOpponentProfileUseCase: GetOpponentProfileUseCase, private val matchingRepository: MatchingRepository, internal val navigationHelper: NavigationHelper, private val eventHelper: EventHelper, @@ -49,56 +51,20 @@ class MatchingDetailViewModel @AssistedInject constructor( private fun initMatchDetailInfo() = viewModelScope.launch { setState { copy(isLoading = true) } - val valueTalksJob = launch { - matchingRepository.getOpponentValueTalks() - .onSuccess { valueTalks -> setState { copy(valueTalks = valueTalks) } } - .onFailure { errorHelper.sendError(it) } + getOpponentProfileUseCase().onSuccess { response -> + setState { copy(profile = response) } + }.onFailure { + errorHelper.sendError(it) + }.also { + setState { copy(isLoading = false) } } - - val valuePicksJob = launch { - matchingRepository.getOpponentValuePicks() - .onSuccess { valuePicks -> setState { copy(valuePicks = valuePicks) } } - .onFailure { errorHelper.sendError(it) } - } - - val profileBasicJob = launch { - matchingRepository.getOpponentProfileBasic() - .onSuccess { profileBasic -> - setState { - copy( - description = profileBasic.description, - nickname = profileBasic.nickname, - age = profileBasic.age.toString(), - weight = profileBasic.weight.toString(), - height = profileBasic.height.toString(), - birthYear = profileBasic.birthYear, - job = profileBasic.job, - location = profileBasic.location, - smokeStatue = profileBasic.smokingStatus, - ) - } - } - .onFailure { errorHelper.sendError(it) } - } - - val profileImageJob = launch { - matchingRepository.getOpponentProfileImage() - .onSuccess { profileImageUrl -> setState { copy(imageUrl = profileImageUrl) } } - .onFailure { errorHelper.sendError(it) } - } - - valuePicksJob.join() - valueTalksJob.join() - profileBasicJob.join() - profileImageJob.join() - setState { copy(isLoading = false) } } internal fun onIntent(intent: MatchingDetailIntent) = viewModelScope.launch { intents.send(intent) } - private suspend fun processIntent(intent: MatchingDetailIntent) { + private fun processIntent(intent: MatchingDetailIntent) { when (intent) { is MatchingDetailIntent.OnMoreClick -> showBottomSheet(intent.content) MatchingDetailIntent.OnMatchingDetailCloseClick -> @@ -130,7 +96,7 @@ class MatchingDetailViewModel @AssistedInject constructor( NavigationEvent.NavigateTo( MatchingGraphDest.BlockRoute( userId = matchUserId, - userName = it.nickname, + userName = it.profile!!.nickname, ) ) ) @@ -145,7 +111,7 @@ class MatchingDetailViewModel @AssistedInject constructor( NavigationEvent.NavigateTo( MatchingGraphDest.ReportRoute( userId = matchUserId, - userName = it.nickname, + userName = it.profile!!.nickname, ) ) ) diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt index f06c92fe..7fb06d33 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/contract/MatchingDetailState.kt @@ -1,24 +1,12 @@ package com.puzzle.matching.graph.detail.contract import com.airbnb.mvrx.MavericksState -import com.puzzle.domain.model.profile.OpponentValuePick -import com.puzzle.domain.model.profile.OpponentValueTalk +import com.puzzle.domain.model.profile.OpponentProfile data class MatchingDetailState( val isLoading: Boolean = false, val currentPage: MatchingDetailPage = MatchingDetailPage.BasicInfoPage, - val description: String = "", - val nickname: String = "", - val age: String = "", - val birthYear: String = "", - val height: String = "", - val weight: String = "", - val job: String = "", - val location: String = "", - val smokeStatue: String = "", - val valueTalks: List = emptyList(), - val valuePicks: List = emptyList(), - val imageUrl: String = "", + val profile: OpponentProfile? = null, ) : MavericksState { enum class MatchingDetailPage(val title: String) { diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/page/BasicInfoPage.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/page/BasicInfoPage.kt index 1c4a33cb..d781034f 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/detail/page/BasicInfoPage.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/detail/page/BasicInfoPage.kt @@ -30,12 +30,12 @@ internal fun BasicInfoPage( nickName: String, selfDescription: String, birthYear: String, - age: String, - height: String, - weight: String, + age: Int, + height: Int, + weight: Int, activityRegion: String, occupation: String, - smokeStatue: String, + smokingStatus: String, onMoreClick: () -> Unit, modifier: Modifier = Modifier, ) { @@ -56,7 +56,7 @@ internal fun BasicInfoPage( weight = weight, activityRegion = activityRegion, occupation = occupation, - smokeStatue = smokeStatue, + smokeStatue = smokingStatus, modifier = Modifier.padding(horizontal = 20.dp) ) } @@ -88,10 +88,10 @@ private fun BasicInfoName( @Composable private fun BasicInfoCard( - age: String, + age: Int, birthYear: String, - height: String, - weight: String, + height: Int, + weight: Int, activityRegion: String, occupation: String, smokeStatue: String, @@ -116,7 +116,7 @@ private fun BasicInfoCard( Spacer(modifier = Modifier.width(4.dp)) Text( - text = age, + text = age.toString(), style = PieceTheme.typography.headingSSB, color = PieceTheme.colors.black, ) @@ -148,7 +148,7 @@ private fun BasicInfoCard( text = { Row(verticalAlignment = Alignment.CenterVertically) { Text( - text = height, + text = height.toString(), style = PieceTheme.typography.headingSSB, color = PieceTheme.colors.black, ) @@ -168,7 +168,7 @@ private fun BasicInfoCard( text = { Row(verticalAlignment = Alignment.CenterVertically) { Text( - text = weight, + text = weight.toString(), style = PieceTheme.typography.headingSSB, color = PieceTheme.colors.black, ) @@ -259,12 +259,12 @@ private fun ProfileBasicInfoPagePreview() { nickName = "수줍은 수달", selfDescription = "음악과 요리를 좋아하는", birthYear = "1994", - age = "31", - height = "200", - weight = "72", + age = 31, + height = 200, + weight = 72, activityRegion = "서울특별시", occupation = "개발자", - smokeStatue = "비흡연", + smokingStatus = "비흡연", onMoreClick = { }, ) } From f8405177769142495447aecdef91e1400f2e4d41 Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Tue, 11 Feb 2025 18:03:59 +0900 Subject: [PATCH 06/12] =?UTF-8?q?[PC-555]=20GetOpponentProfileUseCase=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=EC=9D=84=20Repository=20=EC=88=98=EC=A4=80?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=98=AC=EB=A6=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/MatchingRepositoryImpl.kt | 41 +++++++++++++++++-- .../domain/repository/MatchingRepository.kt | 9 +--- .../matching/GetOpponentProfileUseCase.kt | 32 +-------------- 3 files changed, 40 insertions(+), 42 deletions(-) diff --git a/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt b/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt index 37db1756..abb5365e 100644 --- a/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt +++ b/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt @@ -1,6 +1,8 @@ package com.puzzle.data.repository +import com.puzzle.common.suspendRunCatching import com.puzzle.domain.model.match.MatchInfo +import com.puzzle.domain.model.profile.OpponentProfile import com.puzzle.domain.model.profile.OpponentProfileBasic import com.puzzle.domain.model.profile.OpponentValuePick import com.puzzle.domain.model.profile.OpponentValueTalk @@ -11,6 +13,8 @@ import com.puzzle.network.model.matching.GetOpponentProfileImageResponse import com.puzzle.network.model.matching.GetOpponentValuePicksResponse import com.puzzle.network.model.matching.GetOpponentValueTalksResponse import com.puzzle.network.source.matching.MatchingDataSource +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope import javax.inject.Inject class MatchingRepositoryImpl @Inject constructor( @@ -26,19 +30,48 @@ class MatchingRepositoryImpl @Inject constructor( override suspend fun getMatchInfo(): Result = matchingDataSource.getMatchInfo() .mapCatching(GetMatchInfoResponse::toDomain) - override suspend fun getOpponentValueTalks(): Result> = + override suspend fun getOpponentProfile(): Result = suspendRunCatching { + coroutineScope { + val valueTalksDeferred = async { getOpponentValueTalks() } + val valuePicksDeferred = async { getOpponentValuePicks() } + val profileBasicDeferred = async { getOpponentProfileBasic() } + val profileImageDeferred = async { getOpponentProfileImage() } + + val valuePicks = valuePicksDeferred.await().getOrThrow() + val valueTalks = valueTalksDeferred.await().getOrThrow() + val profileBasic = profileBasicDeferred.await().getOrThrow() + val imageUrl = profileImageDeferred.await().getOrThrow() + + OpponentProfile( + description = profileBasic.description, + nickname = profileBasic.nickname, + age = profileBasic.age, + birthYear = profileBasic.birthYear, + height = profileBasic.height, + weight = profileBasic.weight, + location = profileBasic.location, + job = profileBasic.job, + smokingStatus = profileBasic.smokingStatus, + valuePicks = valuePicks, + valueTalks = valueTalks, + imageUrl = imageUrl, + ) + } + } + + private suspend fun getOpponentValueTalks(): Result> = matchingDataSource.getOpponentValueTalks() .mapCatching(GetOpponentValueTalksResponse::toDomain) - override suspend fun getOpponentValuePicks(): Result> = + private suspend fun getOpponentValuePicks(): Result> = matchingDataSource.getOpponentValuePicks() .mapCatching(GetOpponentValuePicksResponse::toDomain) - override suspend fun getOpponentProfileBasic(): Result = + private suspend fun getOpponentProfileBasic(): Result = matchingDataSource.getOpponentProfileBasic() .mapCatching(GetOpponentProfileBasicResponse::toDomain) - override suspend fun getOpponentProfileImage(): Result = + private suspend fun getOpponentProfileImage(): Result = matchingDataSource.getOpponentProfileImage() .mapCatching(GetOpponentProfileImageResponse::toDomain) diff --git a/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt b/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt index b2743cf4..be2e1ef6 100644 --- a/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt +++ b/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt @@ -1,19 +1,14 @@ package com.puzzle.domain.repository import com.puzzle.domain.model.match.MatchInfo -import com.puzzle.domain.model.profile.OpponentProfileBasic -import com.puzzle.domain.model.profile.OpponentValuePick -import com.puzzle.domain.model.profile.OpponentValueTalk +import com.puzzle.domain.model.profile.OpponentProfile interface MatchingRepository { suspend fun reportUser(userId: Int, reason: String): Result suspend fun blockUser(userId: Int): Result suspend fun blockContacts(phoneNumbers: List): Result suspend fun getMatchInfo(): Result - suspend fun getOpponentValueTalks(): Result> - suspend fun getOpponentValuePicks(): Result> - suspend fun getOpponentProfileBasic(): Result - suspend fun getOpponentProfileImage(): Result + suspend fun getOpponentProfile(): Result suspend fun checkMatchingPiece(): Result suspend fun acceptMatching(): Result } diff --git a/core/domain/src/main/java/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCase.kt b/core/domain/src/main/java/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCase.kt index e0dc6c24..ce4098d0 100644 --- a/core/domain/src/main/java/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCase.kt +++ b/core/domain/src/main/java/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCase.kt @@ -1,41 +1,11 @@ package com.puzzle.domain.usecase.matching -import com.puzzle.common.suspendRunCatching import com.puzzle.domain.model.profile.OpponentProfile import com.puzzle.domain.repository.MatchingRepository -import kotlinx.coroutines.async -import kotlinx.coroutines.coroutineScope import javax.inject.Inject class GetOpponentProfileUseCase @Inject constructor( private val matchingRepository: MatchingRepository, ) { - suspend operator fun invoke(): Result = suspendRunCatching { - coroutineScope { - val valueTalksDeferred = async { matchingRepository.getOpponentValueTalks() } - val valuePicksDeferred = async { matchingRepository.getOpponentValuePicks() } - val profileBasicDeferred = async { matchingRepository.getOpponentProfileBasic() } - val profileImageDeferred = async { matchingRepository.getOpponentProfileImage() } - - val valuePicks = valuePicksDeferred.await().getOrThrow() - val valueTalks = valueTalksDeferred.await().getOrThrow() - val profileBasic = profileBasicDeferred.await().getOrThrow() - val imageUrl = profileImageDeferred.await().getOrThrow() - - OpponentProfile( - description = profileBasic.description, - nickname = profileBasic.nickname, - age = profileBasic.age, - birthYear = profileBasic.birthYear, - height = profileBasic.height, - weight = profileBasic.weight, - location = profileBasic.location, - job = profileBasic.job, - smokingStatus = profileBasic.smokingStatus, - valuePicks = valuePicks, - valueTalks = valueTalks, - imageUrl = imageUrl, - ) - } - } + suspend operator fun invoke(): Result = matchingRepository.getOpponentProfile() } From 221eb4ea4c4ad56476efa0180a9709e7de161b4e Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Tue, 11 Feb 2025 19:16:16 +0900 Subject: [PATCH 07/12] =?UTF-8?q?[PC-555]=20LocalMatchingDataSource=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/datastore/build.gradle.kts | 3 ++ .../matching/LocalMatchingDataSource.kt | 10 +++++ .../matching/LocalMatchingDataSourceImpl.kt | 40 +++++++++++++++++++ .../puzzle/datastore/di/DataStoreModule.kt | 20 +++++++++- .../puzzle/datastore/util/DataStoreUtil.kt | 12 ++---- gradle/libs.versions.toml | 3 ++ 6 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 core/datastore/src/main/java/com/puzzle/datastore/datasource/matching/LocalMatchingDataSource.kt create mode 100644 core/datastore/src/main/java/com/puzzle/datastore/datasource/matching/LocalMatchingDataSourceImpl.kt diff --git a/core/datastore/build.gradle.kts b/core/datastore/build.gradle.kts index 3f005841..563b6ce6 100644 --- a/core/datastore/build.gradle.kts +++ b/core/datastore/build.gradle.kts @@ -8,5 +8,8 @@ android { } dependencies { + implementation(projects.core.domain) + implementation(libs.androidx.datastore) + implementation(libs.gson) } diff --git a/core/datastore/src/main/java/com/puzzle/datastore/datasource/matching/LocalMatchingDataSource.kt b/core/datastore/src/main/java/com/puzzle/datastore/datasource/matching/LocalMatchingDataSource.kt new file mode 100644 index 00000000..3d150e56 --- /dev/null +++ b/core/datastore/src/main/java/com/puzzle/datastore/datasource/matching/LocalMatchingDataSource.kt @@ -0,0 +1,10 @@ +package com.puzzle.datastore.datasource.matching + +import com.puzzle.domain.model.profile.OpponentProfile +import kotlinx.coroutines.flow.Flow + +interface LocalMatchingDataSource { + val opponentProfile: Flow + suspend fun setOpponentProfile(opponentProfile: OpponentProfile) + suspend fun clearOpponentProfile() +} diff --git a/core/datastore/src/main/java/com/puzzle/datastore/datasource/matching/LocalMatchingDataSourceImpl.kt b/core/datastore/src/main/java/com/puzzle/datastore/datasource/matching/LocalMatchingDataSourceImpl.kt new file mode 100644 index 00000000..cf3ddf27 --- /dev/null +++ b/core/datastore/src/main/java/com/puzzle/datastore/datasource/matching/LocalMatchingDataSourceImpl.kt @@ -0,0 +1,40 @@ +package com.puzzle.datastore.datasource.matching + +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.stringPreferencesKey +import com.google.gson.Gson +import com.puzzle.datastore.util.getValue +import com.puzzle.datastore.util.setValue +import com.puzzle.domain.model.profile.OpponentProfile +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject +import javax.inject.Named + +class LocalMatchingDataSourceImpl @Inject constructor( + @Named("matching") private val dataStore: DataStore, +) : LocalMatchingDataSource { + private val gson = Gson() + override val opponentProfile: Flow = dataStore.getValue(OPPONENT_PROFILE, "") + .map { + when { + it.isNotEmpty() -> gson.fromJson(it, OpponentProfile::class.java) + else -> null + } + } + + override suspend fun setOpponentProfile(opponentProfile: OpponentProfile) { + val jsonString = gson.toJson(opponentProfile) + dataStore.setValue(OPPONENT_PROFILE, jsonString) + } + + override suspend fun clearOpponentProfile() { + dataStore.edit { preferences -> preferences.remove(OPPONENT_PROFILE) } + } + + companion object { + private val OPPONENT_PROFILE = stringPreferencesKey("OPPONENT_PROFILE") + } +} diff --git a/core/datastore/src/main/java/com/puzzle/datastore/di/DataStoreModule.kt b/core/datastore/src/main/java/com/puzzle/datastore/di/DataStoreModule.kt index 68bda38b..bf76b4ad 100644 --- a/core/datastore/src/main/java/com/puzzle/datastore/di/DataStoreModule.kt +++ b/core/datastore/src/main/java/com/puzzle/datastore/di/DataStoreModule.kt @@ -4,6 +4,8 @@ import android.content.Context import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.preferencesDataStore +import com.puzzle.datastore.datasource.matching.LocalMatchingDataSource +import com.puzzle.datastore.datasource.matching.LocalMatchingDataSourceImpl import com.puzzle.datastore.datasource.token.LocalTokenDataSource import com.puzzle.datastore.datasource.token.LocalTokenDataSourceImpl import com.puzzle.datastore.datasource.user.LocalUserDataSource @@ -26,6 +28,9 @@ object DataStoreProvidesModule { private const val USER_DATASTORE_NAME = "USERS_PREFERENCES" private val Context.userDataStore by preferencesDataStore(name = USER_DATASTORE_NAME) + private const val MATCHING_DATASTORE_NAME = "MATCHING_PREFERENCES" + private val Context.matchingDataStore by preferencesDataStore(name = MATCHING_DATASTORE_NAME) + @Provides @Singleton @Named("token") @@ -39,6 +44,13 @@ object DataStoreProvidesModule { fun provideUserDataStore( @ApplicationContext context: Context ): DataStore = context.userDataStore + + @Provides + @Singleton + @Named("matching") + fun provideMatchingDataStore( + @ApplicationContext context: Context + ): DataStore = context.matchingDataStore } @Module @@ -47,7 +59,7 @@ abstract class DatastoreBindsModule { @Binds @Singleton - abstract fun bindsLocalMatchingDataSource( + abstract fun bindsLocalTokenDataSource( localTokenDataSourceImpl: LocalTokenDataSourceImpl, ): LocalTokenDataSource @@ -56,4 +68,10 @@ abstract class DatastoreBindsModule { abstract fun bindsLocalUserDataSource( localUserDataSourceImpl: LocalUserDataSourceImpl, ): LocalUserDataSource + + @Binds + @Singleton + abstract fun bindsLocalMatchingDataSource( + localMatchingDataSourceImpl: LocalMatchingDataSourceImpl, + ): LocalMatchingDataSource } diff --git a/core/datastore/src/main/java/com/puzzle/datastore/util/DataStoreUtil.kt b/core/datastore/src/main/java/com/puzzle/datastore/util/DataStoreUtil.kt index 4924c5ea..85257ba3 100644 --- a/core/datastore/src/main/java/com/puzzle/datastore/util/DataStoreUtil.kt +++ b/core/datastore/src/main/java/com/puzzle/datastore/util/DataStoreUtil.kt @@ -15,22 +15,16 @@ internal fun DataStore.getValue( defaultValue: T ): Flow = data.handleException() - .map { preferences -> - preferences[key] ?: defaultValue - } + .map { preferences -> preferences[key] ?: defaultValue } internal suspend fun DataStore.setValue( key: Preferences.Key, value: T, -) = edit { preferences -> - preferences[key] = value -} +) = edit { preferences -> preferences[key] = value } internal suspend fun DataStore.clear( key: Preferences.Key -) = edit { preferences -> - preferences.remove(key) -} +) = edit { preferences -> preferences.remove(key) } private fun Flow.handleException(): Flow = this.catch { exception -> diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5379dfda..7ce48b87 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -56,6 +56,8 @@ kotlin = "2.1.0" kotlinxSerializationJson = "1.7.0" # https://github.com/Kotlin/kotlinx.coroutines kotlinxCoroutine = "1.9.0-RC" +# https://github.com/google/gson +gson = "2.12.1" ## Test # https://github.com/junit-team/junit4 @@ -150,6 +152,7 @@ okhttp-logging = { group = "com.squareup.okhttp3", name = "logging-interceptor", retrofit-core = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" } retrofit-kotlin-serialization = { module = "com.squareup.retrofit2:converter-kotlinx-serialization", version.ref = "retrofit" } kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" } +gson = { module = "com.google.code.gson:gson", version.ref = "gson" } junit4 = { group = "junit", name = "junit", version.ref = "junit4" } junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junitJupiter" } From f1a36661d5c2b7b2b95c8c726d0793eb64c82d49 Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Tue, 11 Feb 2025 19:22:13 +0900 Subject: [PATCH 08/12] =?UTF-8?q?[PC-555]=20retrieve=EA=B0=80=20=EC=8B=A4?= =?UTF-8?q?=ED=8C=A8=ED=95=A0=20=EA=B2=BD=EC=9A=B0=20=EC=8B=A4=EC=A0=9C=20?= =?UTF-8?q?API=EB=A5=BC=20=ED=98=B8=EC=B6=9C=ED=95=B4=EC=84=9C=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/puzzle/data/repository/MatchingRepositoryImpl.kt | 7 +++++++ .../datasource/matching/LocalMatchingDataSource.kt | 2 +- .../datasource/matching/LocalMatchingDataSourceImpl.kt | 9 ++------- .../com/puzzle/domain/repository/MatchingRepository.kt | 1 + .../domain/usecase/matching/GetOpponentProfileUseCase.kt | 4 +++- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt b/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt index abb5365e..09d7e57c 100644 --- a/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt +++ b/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt @@ -1,6 +1,7 @@ package com.puzzle.data.repository import com.puzzle.common.suspendRunCatching +import com.puzzle.datastore.datasource.matching.LocalMatchingDataSource import com.puzzle.domain.model.match.MatchInfo import com.puzzle.domain.model.profile.OpponentProfile import com.puzzle.domain.model.profile.OpponentProfileBasic @@ -15,9 +16,11 @@ import com.puzzle.network.model.matching.GetOpponentValueTalksResponse import com.puzzle.network.source.matching.MatchingDataSource import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.first import javax.inject.Inject class MatchingRepositoryImpl @Inject constructor( + private val localMatchingDataSource: LocalMatchingDataSource, private val matchingDataSource: MatchingDataSource, ) : MatchingRepository { override suspend fun reportUser(userId: Int, reason: String): Result = @@ -30,6 +33,10 @@ class MatchingRepositoryImpl @Inject constructor( override suspend fun getMatchInfo(): Result = matchingDataSource.getMatchInfo() .mapCatching(GetMatchInfoResponse::toDomain) + override suspend fun retrieveOpponentProfile(): Result = suspendRunCatching { + localMatchingDataSource.opponentProfile.first() + } + override suspend fun getOpponentProfile(): Result = suspendRunCatching { coroutineScope { val valueTalksDeferred = async { getOpponentValueTalks() } diff --git a/core/datastore/src/main/java/com/puzzle/datastore/datasource/matching/LocalMatchingDataSource.kt b/core/datastore/src/main/java/com/puzzle/datastore/datasource/matching/LocalMatchingDataSource.kt index 3d150e56..dee8bb61 100644 --- a/core/datastore/src/main/java/com/puzzle/datastore/datasource/matching/LocalMatchingDataSource.kt +++ b/core/datastore/src/main/java/com/puzzle/datastore/datasource/matching/LocalMatchingDataSource.kt @@ -4,7 +4,7 @@ import com.puzzle.domain.model.profile.OpponentProfile import kotlinx.coroutines.flow.Flow interface LocalMatchingDataSource { - val opponentProfile: Flow + val opponentProfile: Flow suspend fun setOpponentProfile(opponentProfile: OpponentProfile) suspend fun clearOpponentProfile() } diff --git a/core/datastore/src/main/java/com/puzzle/datastore/datasource/matching/LocalMatchingDataSourceImpl.kt b/core/datastore/src/main/java/com/puzzle/datastore/datasource/matching/LocalMatchingDataSourceImpl.kt index cf3ddf27..ef7527b4 100644 --- a/core/datastore/src/main/java/com/puzzle/datastore/datasource/matching/LocalMatchingDataSourceImpl.kt +++ b/core/datastore/src/main/java/com/puzzle/datastore/datasource/matching/LocalMatchingDataSourceImpl.kt @@ -17,13 +17,8 @@ class LocalMatchingDataSourceImpl @Inject constructor( @Named("matching") private val dataStore: DataStore, ) : LocalMatchingDataSource { private val gson = Gson() - override val opponentProfile: Flow = dataStore.getValue(OPPONENT_PROFILE, "") - .map { - when { - it.isNotEmpty() -> gson.fromJson(it, OpponentProfile::class.java) - else -> null - } - } + override val opponentProfile: Flow = dataStore.getValue(OPPONENT_PROFILE, "") + .map { gson.fromJson(it, OpponentProfile::class.java) } override suspend fun setOpponentProfile(opponentProfile: OpponentProfile) { val jsonString = gson.toJson(opponentProfile) diff --git a/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt b/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt index be2e1ef6..0fdb0c1e 100644 --- a/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt +++ b/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt @@ -8,6 +8,7 @@ interface MatchingRepository { suspend fun blockUser(userId: Int): Result suspend fun blockContacts(phoneNumbers: List): Result suspend fun getMatchInfo(): Result + suspend fun retrieveOpponentProfile(): Result suspend fun getOpponentProfile(): Result suspend fun checkMatchingPiece(): Result suspend fun acceptMatching(): Result diff --git a/core/domain/src/main/java/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCase.kt b/core/domain/src/main/java/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCase.kt index ce4098d0..f08e2095 100644 --- a/core/domain/src/main/java/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCase.kt +++ b/core/domain/src/main/java/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCase.kt @@ -7,5 +7,7 @@ import javax.inject.Inject class GetOpponentProfileUseCase @Inject constructor( private val matchingRepository: MatchingRepository, ) { - suspend operator fun invoke(): Result = matchingRepository.getOpponentProfile() + suspend operator fun invoke(): Result = + matchingRepository.retrieveOpponentProfile() + .recoverCatching { matchingRepository.getOpponentProfile().getOrThrow() } } From 87ba42951c95490c9267a35d4e6f0cfae77f46b0 Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Tue, 11 Feb 2025 19:26:24 +0900 Subject: [PATCH 09/12] =?UTF-8?q?[PC-555]=20MatchingDataSource=20Interface?= =?UTF-8?q?,=20=EA=B5=AC=ED=98=84=EC=B2=B4=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/puzzle/network/di/NetworkModule.kt | 8 ++++ .../source/matching/MatchingDataSource.kt | 44 +++++------------ .../source/matching/MatchingDataSourceImpl.kt | 47 +++++++++++++++++++ 3 files changed, 66 insertions(+), 33 deletions(-) create mode 100644 core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSourceImpl.kt diff --git a/core/network/src/main/java/com/puzzle/network/di/NetworkModule.kt b/core/network/src/main/java/com/puzzle/network/di/NetworkModule.kt index d82b7ae1..5420547b 100644 --- a/core/network/src/main/java/com/puzzle/network/di/NetworkModule.kt +++ b/core/network/src/main/java/com/puzzle/network/di/NetworkModule.kt @@ -2,6 +2,8 @@ package com.puzzle.network.di import com.puzzle.network.source.auth.AuthDataSource import com.puzzle.network.source.auth.AuthDataSourceImpl +import com.puzzle.network.source.matching.MatchingDataSource +import com.puzzle.network.source.matching.MatchingDataSourceImpl import com.puzzle.network.source.profile.ProfileDataSource import com.puzzle.network.source.profile.ProfileDataSourceImpl import com.puzzle.network.source.term.TermDataSource @@ -33,4 +35,10 @@ abstract class NetworkModule { abstract fun bindsTermDataSource( termDataSourceImpl: TermDataSourceImpl, ): TermDataSource + + @Binds + @Singleton + abstract fun bindsMatchingDataSource( + matchingDataSourceImpl: MatchingDataSourceImpl, + ): MatchingDataSource } diff --git a/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt b/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt index da99ece5..78631b26 100644 --- a/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt +++ b/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSource.kt @@ -1,42 +1,20 @@ package com.puzzle.network.source.matching -import com.puzzle.network.api.PieceApi -import com.puzzle.network.model.matching.BlockContactsRequest import com.puzzle.network.model.matching.GetMatchInfoResponse import com.puzzle.network.model.matching.GetOpponentProfileBasicResponse import com.puzzle.network.model.matching.GetOpponentProfileImageResponse import com.puzzle.network.model.matching.GetOpponentValuePicksResponse import com.puzzle.network.model.matching.GetOpponentValueTalksResponse -import com.puzzle.network.model.matching.ReportUserRequest -import com.puzzle.network.model.unwrapData -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class MatchingDataSource @Inject constructor( - private val pieceApi: PieceApi -) { - suspend fun reportUser(userId: Int, reason: String): Result = - pieceApi.reportUser(ReportUserRequest(userId = userId, reason = reason)).unwrapData() - - suspend fun blockUser(userId: Int): Result = pieceApi.blockUser(userId).unwrapData() - suspend fun blockContacts(phoneNumbers: List): Result = - pieceApi.blockContacts(BlockContactsRequest(phoneNumbers)).unwrapData() - - suspend fun getMatchInfo(): Result = pieceApi.getMatchInfo().unwrapData() - suspend fun getOpponentValueTalks(): Result = - pieceApi.getOpponentValueTalks().unwrapData() - - suspend fun getOpponentValuePicks(): Result = - pieceApi.getOpponentValuePicks().unwrapData() - - suspend fun getOpponentProfileBasic(): Result = - pieceApi.getOpponentProfileBasic().unwrapData() - - suspend fun getOpponentProfileImage(): Result = - pieceApi.getOpponentProfileImage().unwrapData() - - suspend fun checkMatchingPiece(): Result = pieceApi.checkMatchingPiece().unwrapData() - suspend fun acceptMatching(): Result = pieceApi.acceptMatching().unwrapData() +interface MatchingDataSource { + suspend fun reportUser(userId: Int, reason: String): Result + suspend fun blockUser(userId: Int): Result + suspend fun blockContacts(phoneNumbers: List): Result + suspend fun getMatchInfo(): Result + suspend fun getOpponentValueTalks(): Result + suspend fun getOpponentValuePicks(): Result + suspend fun getOpponentProfileBasic(): Result + suspend fun getOpponentProfileImage(): Result + suspend fun checkMatchingPiece(): Result + suspend fun acceptMatching(): Result } diff --git a/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSourceImpl.kt b/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSourceImpl.kt new file mode 100644 index 00000000..e627a546 --- /dev/null +++ b/core/network/src/main/java/com/puzzle/network/source/matching/MatchingDataSourceImpl.kt @@ -0,0 +1,47 @@ +package com.puzzle.network.source.matching + +import com.puzzle.network.api.PieceApi +import com.puzzle.network.model.matching.BlockContactsRequest +import com.puzzle.network.model.matching.GetMatchInfoResponse +import com.puzzle.network.model.matching.GetOpponentProfileBasicResponse +import com.puzzle.network.model.matching.GetOpponentProfileImageResponse +import com.puzzle.network.model.matching.GetOpponentValuePicksResponse +import com.puzzle.network.model.matching.GetOpponentValueTalksResponse +import com.puzzle.network.model.matching.ReportUserRequest +import com.puzzle.network.model.unwrapData +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class MatchingDataSourceImpl @Inject constructor( + private val pieceApi: PieceApi +) : MatchingDataSource { + override suspend fun reportUser(userId: Int, reason: String): Result = + pieceApi.reportUser(ReportUserRequest(userId = userId, reason = reason)).unwrapData() + + override suspend fun blockUser(userId: Int): Result = + pieceApi.blockUser(userId).unwrapData() + + override suspend fun blockContacts(phoneNumbers: List): Result = + pieceApi.blockContacts(BlockContactsRequest(phoneNumbers)).unwrapData() + + override suspend fun getMatchInfo(): Result = + pieceApi.getMatchInfo().unwrapData() + + override suspend fun getOpponentValueTalks(): Result = + pieceApi.getOpponentValueTalks().unwrapData() + + override suspend fun getOpponentValuePicks(): Result = + pieceApi.getOpponentValuePicks().unwrapData() + + override suspend fun getOpponentProfileBasic(): Result = + pieceApi.getOpponentProfileBasic().unwrapData() + + override suspend fun getOpponentProfileImage(): Result = + pieceApi.getOpponentProfileImage().unwrapData() + + override suspend fun checkMatchingPiece(): Result = + pieceApi.checkMatchingPiece().unwrapData() + + override suspend fun acceptMatching(): Result = pieceApi.acceptMatching().unwrapData() +} From 6aae24e725bb96527aa6dc17306a8ae53dedf56b Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Tue, 11 Feb 2025 23:00:41 +0900 Subject: [PATCH 10/12] =?UTF-8?q?[PC-555]=20MatchingRepositoryTest=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/MatchingRepositoryImpl.kt | 4 +- .../matching/FakeLocalMatchingDataSource.kt | 21 ++++ .../source/matching/FakeMatchingDataSource.kt | 92 ++++++++++++++ .../repository/MatchingRepositoryImplTest.kt | 117 ++++++++++++++++++ .../com/puzzle/network/di/NetworkModule.kt | 4 +- 5 files changed, 235 insertions(+), 3 deletions(-) create mode 100644 core/data/src/test/java/com/puzzle/data/fake/source/matching/FakeLocalMatchingDataSource.kt create mode 100644 core/data/src/test/java/com/puzzle/data/fake/source/matching/FakeMatchingDataSource.kt create mode 100644 core/data/src/test/java/com/puzzle/data/repository/MatchingRepositoryImplTest.kt diff --git a/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt b/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt index 09d7e57c..ccf10ae4 100644 --- a/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt +++ b/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt @@ -49,7 +49,7 @@ class MatchingRepositoryImpl @Inject constructor( val profileBasic = profileBasicDeferred.await().getOrThrow() val imageUrl = profileImageDeferred.await().getOrThrow() - OpponentProfile( + val result = OpponentProfile( description = profileBasic.description, nickname = profileBasic.nickname, age = profileBasic.age, @@ -63,6 +63,8 @@ class MatchingRepositoryImpl @Inject constructor( valueTalks = valueTalks, imageUrl = imageUrl, ) + localMatchingDataSource.setOpponentProfile(result) + result } } diff --git a/core/data/src/test/java/com/puzzle/data/fake/source/matching/FakeLocalMatchingDataSource.kt b/core/data/src/test/java/com/puzzle/data/fake/source/matching/FakeLocalMatchingDataSource.kt new file mode 100644 index 00000000..edcfd2e5 --- /dev/null +++ b/core/data/src/test/java/com/puzzle/data/fake/source/matching/FakeLocalMatchingDataSource.kt @@ -0,0 +1,21 @@ +package com.puzzle.data.fake.source.matching + +import com.puzzle.datastore.datasource.matching.LocalMatchingDataSource +import com.puzzle.domain.model.profile.OpponentProfile +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow + +class FakeLocalMatchingDataSource : LocalMatchingDataSource { + private var storedOpponentProfile: OpponentProfile? = null + + override val opponentProfile: Flow = flow { + storedOpponentProfile?.let { emit(it) } + ?: throw NoSuchElementException("No value present in DataStore") + } + + override suspend fun setOpponentProfile(profile: OpponentProfile) { + storedOpponentProfile = profile + } + + override suspend fun clearOpponentProfile() {} +} diff --git a/core/data/src/test/java/com/puzzle/data/fake/source/matching/FakeMatchingDataSource.kt b/core/data/src/test/java/com/puzzle/data/fake/source/matching/FakeMatchingDataSource.kt new file mode 100644 index 00000000..42c89486 --- /dev/null +++ b/core/data/src/test/java/com/puzzle/data/fake/source/matching/FakeMatchingDataSource.kt @@ -0,0 +1,92 @@ +package com.puzzle.data.fake.source.matching + +import com.puzzle.network.model.matching.GetMatchInfoResponse +import com.puzzle.network.model.matching.GetOpponentProfileBasicResponse +import com.puzzle.network.model.matching.GetOpponentProfileImageResponse +import com.puzzle.network.model.matching.GetOpponentValuePicksResponse +import com.puzzle.network.model.matching.GetOpponentValueTalksResponse +import com.puzzle.network.source.matching.MatchingDataSource + +class FakeMatchingDataSource : MatchingDataSource { + private var opponentProfileBasicData: GetOpponentProfileBasicResponse? = null + private var opponentValuePicksData: GetOpponentValuePicksResponse? = null + private var opponentValueTalksData: GetOpponentValueTalksResponse? = null + private var opponentProfileImageData: GetOpponentProfileImageResponse? = null + + fun setOpponentProfileData( + basicData: GetOpponentProfileBasicResponse, + valuePicksData: GetOpponentValuePicksResponse, + valueTalksData: GetOpponentValueTalksResponse, + profileImageData: GetOpponentProfileImageResponse + ) { + opponentProfileBasicData = basicData + opponentValuePicksData = valuePicksData + opponentValueTalksData = valueTalksData + opponentProfileImageData = profileImageData + } + + override suspend fun getOpponentProfileBasic(): Result = + Result.success( + opponentProfileBasicData ?: GetOpponentProfileBasicResponse( + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ) + ) + + override suspend fun getOpponentValuePicks(): Result = + Result.success( + opponentValuePicksData ?: GetOpponentValuePicksResponse( + null, + null, + null, + null + ) + ) + + override suspend fun getOpponentValueTalks(): Result = + Result.success( + opponentValueTalksData ?: GetOpponentValueTalksResponse( + null, + null, + null, + null + ) + ) + + override suspend fun getOpponentProfileImage(): Result = + Result.success(opponentProfileImageData ?: GetOpponentProfileImageResponse(null)) + + override suspend fun reportUser(userId: Int, reason: String): Result = + Result.success(Unit) + + override suspend fun blockUser(userId: Int): Result = Result.success(Unit) + + override suspend fun blockContacts(phoneNumbers: List): Result = + Result.success(Unit) + + override suspend fun getMatchInfo(): Result = Result.success( + GetMatchInfoResponse( + matchId = 1234, + matchStatus = "WAITING", + description = "안녕하세요, 저는 음악과 여행을 좋아하는 사람입니다.", + nickname = "여행하는음악가", + birthYear = "1995", + location = "서울특별시", + job = "음악 프로듀서", + matchedValueCount = 3, + matchedValueList = listOf("음악", "여행", "독서") + ) + ) + + override suspend fun checkMatchingPiece(): Result = Result.success(Unit) + + override suspend fun acceptMatching(): Result = Result.success(Unit) +} diff --git a/core/data/src/test/java/com/puzzle/data/repository/MatchingRepositoryImplTest.kt b/core/data/src/test/java/com/puzzle/data/repository/MatchingRepositoryImplTest.kt new file mode 100644 index 00000000..6bcbfee5 --- /dev/null +++ b/core/data/src/test/java/com/puzzle/data/repository/MatchingRepositoryImplTest.kt @@ -0,0 +1,117 @@ +package com.puzzle.data.repository + +import com.puzzle.data.fake.source.matching.FakeLocalMatchingDataSource +import com.puzzle.data.fake.source.matching.FakeMatchingDataSource +import com.puzzle.domain.model.profile.OpponentProfile +import com.puzzle.domain.model.profile.OpponentValuePick +import com.puzzle.domain.model.profile.OpponentValueTalk +import com.puzzle.network.model.matching.GetOpponentProfileBasicResponse +import com.puzzle.network.model.matching.GetOpponentProfileImageResponse +import com.puzzle.network.model.matching.GetOpponentValuePicksResponse +import com.puzzle.network.model.matching.GetOpponentValueTalksResponse +import com.puzzle.network.model.matching.OpponentValuePickResponse +import com.puzzle.network.model.matching.OpponentValueTalkResponse +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +class MatchingRepositoryImplTest { + + private lateinit var matchingRepository: MatchingRepositoryImpl + private lateinit var fakeMatchingDataSource: FakeMatchingDataSource + private lateinit var fakeLocalMatchingDataSource: FakeLocalMatchingDataSource + + @BeforeEach + fun setUp() { + fakeMatchingDataSource = FakeMatchingDataSource() + fakeLocalMatchingDataSource = FakeLocalMatchingDataSource() + matchingRepository = MatchingRepositoryImpl( + localMatchingDataSource = fakeLocalMatchingDataSource, + matchingDataSource = fakeMatchingDataSource + ) + } + + @Test + fun `매칭된 상대방 정보는 로컬에 저장한다`() = runTest { + // Given + val expectedOpponentProfile = OpponentProfile( + description = "안녕하세요", + nickname = "테스트", + age = 25, + birthYear = "1998", + height = 170, + weight = 60, + location = "서울", + job = "개발자", + smokingStatus = "비흡연", + valuePicks = listOf( + OpponentValuePick( + category = "취미", + question = "당신의 취미는 무엇인가요?", + isSameWithMe = true, + answerOptions = emptyList(), + selectedAnswer = 1 + ) + ), + valueTalks = listOf( + OpponentValueTalk( + category = "음악", + summary = "좋아하는 음악 장르", + answer = "저는 클래식 음악을 좋아합니다." + ) + ), + imageUrl = "https://example.com/image.jpg" + ) + + fakeMatchingDataSource.setOpponentProfileData( + GetOpponentProfileBasicResponse( + matchId = 1, + description = expectedOpponentProfile.description, + nickname = expectedOpponentProfile.nickname, + age = expectedOpponentProfile.age, + birthYear = expectedOpponentProfile.birthYear, + height = expectedOpponentProfile.height, + weight = expectedOpponentProfile.weight, + location = expectedOpponentProfile.location, + job = expectedOpponentProfile.job, + smokingStatus = expectedOpponentProfile.smokingStatus + ), + GetOpponentValuePicksResponse( + matchId = 1, + description = null, + nickname = null, + valuePicks = expectedOpponentProfile.valuePicks.map { + OpponentValuePickResponse( + category = it.category, + question = it.question, + isSameWithMe = it.isSameWithMe, + answerOptions = null, + selectedAnswer = it.selectedAnswer + ) + } + ), + GetOpponentValueTalksResponse( + matchId = 1, + description = null, + nickname = null, + valueTalks = expectedOpponentProfile.valueTalks.map { + OpponentValueTalkResponse( + category = it.category, + summary = it.summary, + answer = it.answer + ) + } + ), + GetOpponentProfileImageResponse(imageUrl = expectedOpponentProfile.imageUrl) + ) + + // When + matchingRepository.getOpponentProfile().getOrThrow() + + // Then + val storedProfile = fakeLocalMatchingDataSource.opponentProfile.first() + assertEquals(expectedOpponentProfile, storedProfile) + } +} diff --git a/core/network/src/main/java/com/puzzle/network/di/NetworkModule.kt b/core/network/src/main/java/com/puzzle/network/di/NetworkModule.kt index 5420547b..ecb840b6 100644 --- a/core/network/src/main/java/com/puzzle/network/di/NetworkModule.kt +++ b/core/network/src/main/java/com/puzzle/network/di/NetworkModule.kt @@ -26,8 +26,8 @@ abstract class NetworkModule { @Binds @Singleton - abstract fun bindsMatchingDataSource( - matchingDataSourceImpl: ProfileDataSourceImpl, + abstract fun bindsProfileDataSource( + profileDataSourceImpl: ProfileDataSourceImpl, ): ProfileDataSource @Binds From d71aab02fab03bd86c4a9e71a41bb02f5cbee584 Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Tue, 11 Feb 2025 23:14:56 +0900 Subject: [PATCH 11/12] =?UTF-8?q?[PC-555]=20GetOpponentProfileUseCaseTest?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/MatchingRepositoryImpl.kt | 3 +- .../repository/MatchingRepositoryImplTest.kt | 2 +- .../domain/repository/MatchingRepository.kt | 2 +- .../matching/GetOpponentProfileUseCase.kt | 5 +- .../spy/repository/SpyMatchingRepository.kt | 64 ++++++++++++++++ .../matching/GetOpponentProfileUseCaseTest.kt | 76 +++++++++++++++++++ 6 files changed, 147 insertions(+), 5 deletions(-) create mode 100644 core/domain/src/test/kotlin/com/puzzle/domain/spy/repository/SpyMatchingRepository.kt create mode 100644 core/domain/src/test/kotlin/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCaseTest.kt diff --git a/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt b/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt index ccf10ae4..ed89daa4 100644 --- a/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt +++ b/core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt @@ -37,7 +37,7 @@ class MatchingRepositoryImpl @Inject constructor( localMatchingDataSource.opponentProfile.first() } - override suspend fun getOpponentProfile(): Result = suspendRunCatching { + override suspend fun loadOpponentProfile(): Result = suspendRunCatching { coroutineScope { val valueTalksDeferred = async { getOpponentValueTalks() } val valuePicksDeferred = async { getOpponentValuePicks() } @@ -64,7 +64,6 @@ class MatchingRepositoryImpl @Inject constructor( imageUrl = imageUrl, ) localMatchingDataSource.setOpponentProfile(result) - result } } diff --git a/core/data/src/test/java/com/puzzle/data/repository/MatchingRepositoryImplTest.kt b/core/data/src/test/java/com/puzzle/data/repository/MatchingRepositoryImplTest.kt index 6bcbfee5..5edfc821 100644 --- a/core/data/src/test/java/com/puzzle/data/repository/MatchingRepositoryImplTest.kt +++ b/core/data/src/test/java/com/puzzle/data/repository/MatchingRepositoryImplTest.kt @@ -108,7 +108,7 @@ class MatchingRepositoryImplTest { ) // When - matchingRepository.getOpponentProfile().getOrThrow() + matchingRepository.loadOpponentProfile().getOrThrow() // Then val storedProfile = fakeLocalMatchingDataSource.opponentProfile.first() diff --git a/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt b/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt index 0fdb0c1e..aff864b3 100644 --- a/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt +++ b/core/domain/src/main/java/com/puzzle/domain/repository/MatchingRepository.kt @@ -9,7 +9,7 @@ interface MatchingRepository { suspend fun blockContacts(phoneNumbers: List): Result suspend fun getMatchInfo(): Result suspend fun retrieveOpponentProfile(): Result - suspend fun getOpponentProfile(): Result + suspend fun loadOpponentProfile(): Result suspend fun checkMatchingPiece(): Result suspend fun acceptMatching(): Result } diff --git a/core/domain/src/main/java/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCase.kt b/core/domain/src/main/java/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCase.kt index f08e2095..4e82390f 100644 --- a/core/domain/src/main/java/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCase.kt +++ b/core/domain/src/main/java/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCase.kt @@ -9,5 +9,8 @@ class GetOpponentProfileUseCase @Inject constructor( ) { suspend operator fun invoke(): Result = matchingRepository.retrieveOpponentProfile() - .recoverCatching { matchingRepository.getOpponentProfile().getOrThrow() } + .recoverCatching { + matchingRepository.loadOpponentProfile().getOrThrow() + matchingRepository.retrieveOpponentProfile().getOrThrow() + } } diff --git a/core/domain/src/test/kotlin/com/puzzle/domain/spy/repository/SpyMatchingRepository.kt b/core/domain/src/test/kotlin/com/puzzle/domain/spy/repository/SpyMatchingRepository.kt new file mode 100644 index 00000000..51c8769e --- /dev/null +++ b/core/domain/src/test/kotlin/com/puzzle/domain/spy/repository/SpyMatchingRepository.kt @@ -0,0 +1,64 @@ +package com.puzzle.domain.spy.repository + +import com.puzzle.domain.model.match.MatchInfo +import com.puzzle.domain.model.profile.OpponentProfile +import com.puzzle.domain.repository.MatchingRepository + +class SpyMatchingRepository : MatchingRepository { + private var localOpponentProfile: OpponentProfile? = null + private var remoteOpponentProfile: OpponentProfile? = null + private var shouldFailLocalRetrieval = false + var loadOpponentProfileCallCount = 0 + private set + + fun setLocalOpponentProfile(profile: OpponentProfile?) { + localOpponentProfile = profile + } + + fun setRemoteOpponentProfile(profile: OpponentProfile) { + remoteOpponentProfile = profile + } + + fun setShouldFailLocalRetrieval(shouldFail: Boolean) { + shouldFailLocalRetrieval = shouldFail + } + + override suspend fun retrieveOpponentProfile(): Result = + if (shouldFailLocalRetrieval) { + Result.failure(NoSuchElementException("No value present in DataStore")) + } else { + localOpponentProfile?.let { Result.success(it) } + ?: Result.failure(NoSuchElementException("No value present in DataStore")) + } + + override suspend fun loadOpponentProfile(): Result { + loadOpponentProfileCallCount++ + shouldFailLocalRetrieval = false + localOpponentProfile = remoteOpponentProfile + return Result.success(Unit) + } + + override suspend fun reportUser(userId: Int, reason: String): Result { + TODO("Not yet implemented") + } + + override suspend fun blockUser(userId: Int): Result { + TODO("Not yet implemented") + } + + override suspend fun blockContacts(phoneNumbers: List): Result { + TODO("Not yet implemented") + } + + override suspend fun getMatchInfo(): Result { + TODO("Not yet implemented") + } + + override suspend fun checkMatchingPiece(): Result { + TODO("Not yet implemented") + } + + override suspend fun acceptMatching(): Result { + TODO("Not yet implemented") + } +} diff --git a/core/domain/src/test/kotlin/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCaseTest.kt b/core/domain/src/test/kotlin/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCaseTest.kt new file mode 100644 index 00000000..0d85f6ac --- /dev/null +++ b/core/domain/src/test/kotlin/com/puzzle/domain/usecase/matching/GetOpponentProfileUseCaseTest.kt @@ -0,0 +1,76 @@ +import com.puzzle.domain.model.profile.OpponentProfile +import com.puzzle.domain.spy.repository.SpyMatchingRepository +import com.puzzle.domain.usecase.matching.GetOpponentProfileUseCase +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +class GetOpponentProfileUseCaseTest { + private lateinit var spyMatchingRepository: SpyMatchingRepository + private lateinit var getOpponentProfileUseCase: GetOpponentProfileUseCase + + @BeforeEach + fun setup() { + spyMatchingRepository = SpyMatchingRepository() + getOpponentProfileUseCase = GetOpponentProfileUseCase(spyMatchingRepository) + } + + @Test + fun `로컬에서 데이터를 불러오다가 실패했을 경우 서버 데이터를 불러온다`() = runTest { + // Given + val localProfile = OpponentProfile( + description = "Local Profile", + nickname = "LocalUser", + age = 25, + birthYear = "1998", + height = 170, + weight = 65, + location = "Seoul", + job = "Developer", + smokingStatus = "Non-smoker", + valuePicks = emptyList(), + valueTalks = emptyList(), + imageUrl = "local_image_url" + ) + val remoteProfile = localProfile.copy(description = "Remote Profile") + + spyMatchingRepository.setShouldFailLocalRetrieval(true) + spyMatchingRepository.setRemoteOpponentProfile(remoteProfile) + + // When + val result = getOpponentProfileUseCase() + + // Then + assertEquals(remoteProfile, result.getOrNull()) + assertEquals(1, spyMatchingRepository.loadOpponentProfileCallCount) + } + + @Test + fun `로컬에서 데이터를 성공적으로 불러올 경우 서버 요청을 하지 않는다`() = runTest { + // Given + val localProfile = OpponentProfile( + description = "Local Profile", + nickname = "LocalUser", + age = 25, + birthYear = "1998", + height = 170, + weight = 65, + location = "Seoul", + job = "Developer", + smokingStatus = "Non-smoker", + valuePicks = emptyList(), + valueTalks = emptyList(), + imageUrl = "local_image_url" + ) + + spyMatchingRepository.setLocalOpponentProfile(localProfile) + + // When + val result = getOpponentProfileUseCase() + + // Then + assertEquals(localProfile, result.getOrNull()) + assertEquals(0, spyMatchingRepository.loadOpponentProfileCallCount) + } +} From 401f5ecc8dd89606601d3fcb6662b17f76917d29 Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Tue, 11 Feb 2025 23:16:24 +0900 Subject: [PATCH 12/12] =?UTF-8?q?[PC-555]=20MatchingHome=EC=97=90=EC=84=9C?= =?UTF-8?q?=20=EC=83=81=EB=8C=80=EB=B0=A9=20=ED=94=84=EB=A1=9C=ED=95=84?= =?UTF-8?q?=EC=9D=84=20=EC=BC=80=EC=8B=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/puzzle/matching/graph/main/MatchingViewModel.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/feature/matching/src/main/java/com/puzzle/matching/graph/main/MatchingViewModel.kt b/feature/matching/src/main/java/com/puzzle/matching/graph/main/MatchingViewModel.kt index 867b186d..6e237bee 100644 --- a/feature/matching/src/main/java/com/puzzle/matching/graph/main/MatchingViewModel.kt +++ b/feature/matching/src/main/java/com/puzzle/matching/graph/main/MatchingViewModel.kt @@ -66,7 +66,13 @@ class MatchingViewModel @AssistedInject constructor( } private suspend fun getMatchInfo() = matchingRepository.getMatchInfo() - .onSuccess { setState { copy(matchInfo = it) } } + .onSuccess { + setState { copy(matchInfo = it) } + + // MatchingHome화면에서 사전에 MatchingDetail에서 필요한 데이터를 케싱해놓습니다. + matchingRepository.loadOpponentProfile() + .onFailure { errorHelper.sendError(it) } + } .onFailure { errorHelper.sendError(it) } private fun processOnButtonClick() = withState { state ->