Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PC-589] 매칭 상태 타이머 ui 적용 #71

Merged
merged 13 commits into from
Feb 15, 2025

Conversation

sksowk156
Copy link
Contributor

1. ⭐️ 변경된 내용

  • 매칭 상태 타이머 ui 적용
  • 연락처 확인 화면 api 연결

2. 🖼️ 스크린샷(선택)

3. 💡 알게된 부분

4. 📌 이 부분은 꼭 봐주세요!

@sksowk156 sksowk156 added UI/UX 🎨 디자인 시스템, 디자인 리소스 관련 코드 🎨 기능 ⚒️ 새로운 기능 구현 ⚒️ 리뷰 원해요🔥 피어의 리뷰를 기다리는 ing.. 🔥 ㅈㅎ찐혁 🌙 훗날 세상을 아우를 남자, sksowk156 labels Feb 15, 2025
@sksowk156 sksowk156 requested a review from tgyuuAn February 15, 2025 16:05
@sksowk156 sksowk156 self-assigned this Feb 15, 2025
Comment on lines 41 to 50
val valuePickQuestions = profileDataSource.loadValuePickQuestions()
.getOrThrow()
.toDomain()
val valuePickQuestions = profileDataSource.loadValuePickQuestions().getOrThrow().toDomain()
.filter { it.id != UNKNOWN_INT }

localProfileDataSource.setValuePickQuestions(valuePickQuestions)
}

override suspend fun loadValueTalkQuestions(): Result<Unit> = suspendRunCatching {
val valueTalkQuestions = profileDataSource.loadValueTalkQuestions()
.getOrThrow()
.toDomain()
val valueTalkQuestions = profileDataSource.loadValueTalkQuestions().getOrThrow().toDomain()
.filter { it.id != UNKNOWN_INT }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

체이닝 메서드를 일렬로 만드신 이유가 있을까용?!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

줄정리하다가 자동으로 적용된 거 같아요!

Copy link
Member

@tgyuuAn tgyuuAn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

진혁님 고생하셨습니다!!!!!!!!

제가 강제 업데이트랑 탈퇴하기 API 연결해볼게요!!

코멘트 남긴거 반영해주시고 conflict 해결해주세요!!!!!!!!!

Comment on lines 65 to 84
override suspend fun loadMyValueTalks(): Result<Unit> = suspendRunCatching {
val valueTalks = profileDataSource.getMyValueTalks()
.getOrThrow()
.toDomain()
val valueTalks = profileDataSource.getMyValueTalks().getOrThrow().toDomain()

localProfileDataSource.setMyValueTalks(valueTalks)
}

override suspend fun retrieveMyValueTalks(): Result<List<MyValueTalk>> =
suspendRunCatching { localProfileDataSource.myValueTalks.first() }
override suspend fun retrieveMyValueTalks(): Result<List<MyValueTalk>> = suspendRunCatching {
localProfileDataSource.myValueTalks.firstOrNull() ?: throw Exception()
}

override suspend fun loadMyValuePicks(): Result<Unit> = suspendRunCatching {
val valuePicks = profileDataSource.getMyValuePicks()
.getOrThrow()
.toDomain()
val valuePicks = profileDataSource.getMyValuePicks().getOrThrow().toDomain()

localProfileDataSource.setMyValuePicks(valuePicks)
}

override suspend fun retrieveMyValuePicks(): Result<List<MyValuePick>> =
suspendRunCatching { localProfileDataSource.myValuePicks.first() }
suspendRunCatching {
localProfileDataSource.myValuePicks.firstOrNull() ?: throw Exception()
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2)

firstOrNull()을 하신 이유가 궁금해요!

아마도 DataStore 모듈 내부에서 제가 에러를 스로잉하고 있을거라서 기존 로직으로 두는게 좋을 것 같아요!

만약 에러를 명시하시려면 더 정확한 Exception과 에러 메세지가 필요할 것 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 usecase쪽으로 데이터가 안넘어와서 repository쪽 수정하다가 변경한건데 다시 돌려놓는걸 깜빡한 거 같아요! 수정해둘게요!!

Comment on lines 29 to 31
override fun observeUserRole(): Flow<UserRole> = localUserDataSource.userRole.map {
UserRole.create(it)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2)

    override suspend fun getUserRole(): Result<UserRole> = suspendRunCatching {
        val userRoleString = localUserDataSource.userRole.first()
        UserRole.create(userRoleString)
    }

getUserRole이라는 메서드가 있어서 불필요한 메서드인 것 같아요.

그리고 해당 데이터는 자주 변경되는 데이터가 아니라서 Stream으로 구독하면 오히려 불필요한 오버헤드인 것 같습니다.

일부로 Flow를 Repository에서 스트림을 끊고 원샷으로 내려준거였어요!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그럼 userRole 갱신은 그냥 껐다가 켜야 할 수 있을 텐데 그렇게 해둘까요?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그럼 userRole 갱신은 그냥 껐다가 켜야 할 수 있을 텐데 그렇게 해둘까요?

Stream이 필요한 화면이 있나요 ?!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stream 없이 갱신할 수 잇을 거 같아요! 수정해둘게요!

Comment on lines 36 to 42
result.getOrNull()?.let { rejectReason ->
if (rejectReason.profileStatus == ProfileStatus.APPROVED) {
localUserDataSource.setUserRole(UserRole.USER.name)
} else {
localUserDataSource.setUserRole(UserRole.PENDING.name)
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

null일 때의 처리가 없는데 혹시 APi명세가 그런걸까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

명세에는 null에 대한 처리는 없었어요! 그래서 일단 null이 아닐 때만 처리해두고 result 그대로 반환해서 viewmodel에서 errorHelper 로 에러 던져놨어요!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아하, 그런거라면 getOrThrow()는 어떨까요?!

Comment on lines 21 to 28
fun getRemainingTimeInSec(startTimeInSec: Long): Long {
val startTimeInMillis = startTimeInSec * 1000
val zoneId = ZoneId.systemDefault()
val now = ZonedDateTime.ofInstant(Instant.ofEpochMilli(startTimeInMillis), zoneId)
val today10PM = now.withHour(22).withMinute(0).withSecond(0).withNano(0)
val targetTime = if (now.isBefore(today10PM)) today10PM else today10PM.plusDays(1)
return Duration.between(now, targetTime).seconds
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3)

아마 이 부분은 서버에서 한국 TimeZone을 기준으로 돌아갈거라서 systemDefault보다는 Asia/Seoul 명시해주는 것이 좋을 것 같아요~~

1000은 SECOND라는 상수로 TimeUitll 로 뺴면 좋을 것 같네용

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분 로직이 많아서 테스트할만한 것 같은데 너무 조금 오래 걸리겠쭁 ...?!

22시 이전이면 금일 22시를 기준으로, 22시 이후면 다음 날 22시를 기준으로 남은 시간을 설정한다

Comment on lines -17 to +18
fun isSmoke(): Boolean = if (smokingStatus == "흡연") true else false
fun isSnsActive(): Boolean = if (snsActivityLevel == "활동") true else false
fun isSmoke(): Boolean = smokingStatus == "흡연"
fun isSnsActive(): Boolean = snsActivityLevel == "활동"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍👍👍

Comment on lines 8 to 12
data class GetRejectReasonResponse(
val profileStatus: String,
val reasonImage: Boolean,
val reasonValues: Boolean,
) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2)

여기도 다른 DTO처럼 Nullable로 받고 toDomain()에서 Default Value를 줘야할 것 같아요~

Comment on lines 49 to 57
getOpponentProfileUseCase().onSuccess { response ->
setState {
copy(nickName = response.nickname)
}
}.onFailure {
errorHelper.sendError(it)
}.also {
setState { copy(isLoading = false) }
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nickname만 필요한거라면 다른 네비게이션에서 argument로 들고오는 것은 어떨까요?

++ 만약 호출해야한다면 아래 getContacts()랑 동기적으로 호출해야할 이유가 없는 것 같아요!

launch{}로 감싸서 병렬적으로 호출해도 될 것 같네용

Comment on lines +136 to +147
}.onFailure {
if (it is HttpResponseException) {
// 1. 회원가입하고 처음 매칭을 하는데 아직 오후 10시가 안되었을 때
// 2. 내가 차단했을 때
// 3. 상대방 아이디가 없어졌을 때
if (it.status == HttpResponseStatus.NotFound) {
startWaitingTimer()
}
return@onFailure
}

errorHelper.sendError(it)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍👍👍

Comment on lines 23 to 25
val hours = totalSeconds / 3600
val minutes = (totalSeconds % 3600) / 60
val seconds = totalSeconds % 60
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3)

매직 넘버 모두 TimeUitl에 상수화 하면 좋을 것 같아요~

Comment on lines 90 to +91
withStyle(style = SpanStyle(color = PieceTheme.colors.subDefault)) {
append("02:32:75")
append(remainTime)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍👍👍

Comment on lines 46 to 71
private fun initContactInfo() = viewModelScope.launch {
setState { copy(isLoading = true) }

val opponentProfileDeferred = async { getOpponentProfileUseCase() }
val opponentContactsDeferred = async { matchingRepository.getOpponentContacts() }

opponentProfileDeferred.await().fold(
onSuccess = { response ->
setState { copy(nickName = response.nickname) }
},
onFailure = { errorHelper.sendError(it) }
)

opponentContactsDeferred.await().fold(
onSuccess = { response ->
setState {
copy(
contacts = response,
selectedContact = response.first()
)
}
},
onFailure = { errorHelper.sendError(it) }
)

setState { copy(isLoading = false) }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3)

조아요~~~ 이제 병렬로 호출되네요.

근데 이제 fold를 쓰면 가독성이 좀 딸려서

마지막으로 아래와 같이 변경해주고 머지해주세요~~~~

private fun initContactInfo() = viewModelScope.launch {
    setState { copy(isLoading = true) }
    val opponentProfileDeferred = async { 
        getOpponentProfileUseCase().onSuccess { response ->
            setState { copy(nickName = response.nickname) }
        }.onFailure { 
            errorHelper.sendError(it) 
        }
    }
    
    val opponentContactsDeferred = async { 
        matchingRepository.getOpponentContacts().onSuccess { response ->
            setState { 
                copy(
                    contacts = response,
                    selectedContact = response.first()
                ) 
            }
        }.onFailure { 
            errorHelper.sendError(it) 
        }
    }

    opponentProfileDeferred.await()
    opponentContactsDeferred.await()

    setState { copy(isLoading = false) }
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗차차 아래 코드가 더 좋을 것 같아요

private fun initContactInfo() = viewModelScope.launch {
    setState { copy(isLoading = true) }
    val opponentProfileJob = launch { 
        getOpponentProfileUseCase().onSuccess { response ->
            setState { copy(nickName = response.nickname) }
        }.onFailure { 
            errorHelper.sendError(it) 
        }
    }
    
    val opponentContactsJob = launch { 
        matchingRepository.getOpponentContacts().onSuccess { response ->
            setState { 
                copy(
                    contacts = response,
                    selectedContact = response.first()
                ) 
            }
        }.onFailure { 
            errorHelper.sendError(it) 
        }
    }

    opponentProfileJob.join()
    opponentContactsJob.join()

    setState { copy(isLoading = false) }
}

Copy link
Member

@tgyuuAn tgyuuAn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍👍👍👍

@tgyuuAn tgyuuAn added 머지 해도될듯염🌟 현재 코드를 기존 코드에 합쳐도 될 것 같다라고 판단..! 🌟 and removed 리뷰 원해요🔥 피어의 리뷰를 기다리는 ing.. 🔥 labels Feb 15, 2025
@sksowk156 sksowk156 merged commit 8f53fd1 into develop Feb 15, 2025
1 check passed
@sksowk156 sksowk156 deleted the feature/sksowk156/PC-589 branch February 15, 2025 18:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
UI/UX 🎨 디자인 시스템, 디자인 리소스 관련 코드 🎨 ㅈㅎ찐혁 🌙 훗날 세상을 아우를 남자, sksowk156 기능 ⚒️ 새로운 기능 구현 ⚒️ 머지 해도될듯염🌟 현재 코드를 기존 코드에 합쳐도 될 것 같다라고 판단..! 🌟
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants