Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 16 additions & 11 deletions Near/app/src/main/java/com/alarmy/near/data/mapper/FriendMapper.kt
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package com.alarmy.near.data.mapper

import com.alarmy.near.model.Friend
import com.alarmy.near.model.ContactFrequency
import com.alarmy.near.model.FriendSummary
import com.alarmy.near.network.response.FriendEntity

fun FriendEntity.toModel(): Friend =
Friend(
friendId = friendId,
position = position,
source = source,
fun FriendEntity.toModel(): FriendSummary =
FriendSummary(
id = friendId,
name = name,
imageUrl = imageUrl,
fileName = fileName,
checkRate = checkRate,
lastContactAt = lastContactAt,
)
profileImageUrl = imageUrl,
lastContactedAt = lastContactAt,
isContacted = true,
contactFrequency =
when (checkRate) {
in 0..29 -> ContactFrequency.LOW
in 30..69 -> ContactFrequency.MIDDLE
in 70..100 -> ContactFrequency.HIGH
else -> ContactFrequency.LOW

Choose a reason for hiding this comment

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

medium

checkRate가 0..100 범위를 벗어나는 경우를 else로 처리하여 ContactFrequency.LOW를 반환하고 있습니다. 만약 checkRate가 항상 0에서 100 사이의 값이라고 보장된다면 이 else 구문은 필요 없습니다. 만약 범위를 벗어나는 값이 들어올 수 있다면, 이는 예외적인 상황일 수 있으므로 IllegalArgumentException을 던져서 잘못된 데이터가 시스템에 유입되는 것을 방지하는 것이 더 안전한 방법일 수 있습니다.

Suggested change
else -> ContactFrequency.LOW
else -> throw IllegalArgumentException("checkRate must be between 0 and 100, but was $checkRate")

},
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.alarmy.near.data.mapper

import com.alarmy.near.model.monthly.MonthlyFriend
import com.alarmy.near.model.monthly.MonthlyFriendType
import com.alarmy.near.network.response.MonthlyFriendEntity

fun MonthlyFriendEntity.toModel(): MonthlyFriend =
MonthlyFriend(
friendId = friendId,
name = name,
type = MonthlyFriendType.from(type),
nextContactAt = nextContactAt,
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.alarmy.near.data.repository

import com.alarmy.near.data.mapper.toModel
import com.alarmy.near.model.Friend
import com.alarmy.near.model.FriendSummary
import com.alarmy.near.model.monthly.MonthlyFriend
import com.alarmy.near.network.service.FriendService
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
Expand All @@ -12,12 +13,21 @@ class DefaultFriendRepository
constructor(
private val friendService: FriendService,
) : FriendRepository {
override fun fetchFriends(): Flow<List<Friend>> =
override fun fetchFriends(): Flow<List<FriendSummary>> =
flow {
emit(
friendService.fetchFriends().map {
it.toModel()
},
)
}

override fun fetchMonthlyFriends(): Flow<List<MonthlyFriend>> =
flow {
emit(
friendService.fetchMonthlyFriends().map {
it.toModel()
},
)
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.alarmy.near.data.repository

import com.alarmy.near.model.Friend
import com.alarmy.near.model.FriendSummary
import com.alarmy.near.model.monthly.MonthlyFriend
import kotlinx.coroutines.flow.Flow

interface FriendRepository {
fun fetchFriends(): Flow<List<Friend>>
fun fetchFriends(): Flow<List<FriendSummary>>

fun fetchMonthlyFriends(): Flow<List<MonthlyFriend>>
}
22 changes: 0 additions & 22 deletions Near/app/src/main/java/com/alarmy/near/model/ContactSummary.kt

This file was deleted.

12 changes: 0 additions & 12 deletions Near/app/src/main/java/com/alarmy/near/model/Friend.kt

This file was deleted.

13 changes: 13 additions & 0 deletions Near/app/src/main/java/com/alarmy/near/model/FriendSummary.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.alarmy.near.model

import androidx.compose.runtime.Immutable

@Immutable
data class FriendSummary(
val id: String,
val name: String,
val profileImageUrl: String?,
val lastContactedAt: String?,
val isContacted: Boolean,
val contactFrequency: ContactFrequency,
)
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.alarmy.near.model
package com.alarmy.near.model.monthly

import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit

data class MonthlyContact(
data class MonthlyFriend(
val friendId: String,
val name: String,
val type: String,
val type: MonthlyFriendType,
val nextContactAt: String,
) {
fun daysUntilNextContact(today: LocalDate): String {
Expand All @@ -26,7 +26,7 @@ data class MonthlyContact(
return ChronoUnit.DAYS.between(today, targetDate)
}

companion object {
companion object Companion {

Choose a reason for hiding this comment

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

medium

Kotlin에서 companion object의 이름은 기본적으로 Companion이므로 명시적으로 이름을 지정할 필요가 없습니다. 불필요한 Companion 키워드를 제거하여 코드를 더 간결하게 만들 수 있습니다.

Suggested change
companion object Companion {
companion object {

private val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.alarmy.near.model.monthly

import androidx.annotation.DrawableRes
import com.alarmy.near.R

enum class MonthlyFriendType(
@param:DrawableRes val imageSrc: Int,
) {
ANNIVERSARY(R.drawable.icon_visual_24_heart),
BIRTHDAY(R.drawable.icon_visual_cake),
MESSAGE(R.drawable.icon_visual_mail),
;

companion object {
private const val ERROR_MESSAGE_NOT_FOUND_MONTHLY_TYPE = "일치하는 타입이 없습니다"

fun from(value: String): MonthlyFriendType =
entries.firstOrNull { it.name == value }
?: throw IllegalArgumentException(
ERROR_MESSAGE_NOT_FOUND_MONTHLY_TYPE,
)

Choose a reason for hiding this comment

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

medium

문자열로부터 enum 값을 찾는 현재 구현은 entries.firstOrNull를 사용하고 있습니다. Kotlin에서는 valueOf() 함수를 사용하여 더 간결하고 관용적으로 구현할 수 있습니다. valueOf()는 대소문자를 구분하므로, API 응답의 대소문자 정책에 따라 uppercase()를 사용하여 유연성을 높일 수 있습니다.

Suggested change
fun from(value: String): MonthlyFriendType =
entries.firstOrNull { it.name == value }
?: throw IllegalArgumentException(
ERROR_MESSAGE_NOT_FOUND_MONTHLY_TYPE,
)
fun from(value: String): MonthlyFriendType = try {
valueOf(value.uppercase())
} catch (e: IllegalArgumentException) {
throw IllegalArgumentException(ERROR_MESSAGE_NOT_FOUND_MONTHLY_TYPE, e)
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.alarmy.near.network.response

import kotlinx.serialization.Serializable

@Serializable
data class MonthlyFriendEntity(
val friendId: String,
val name: String,
val type: String,
val nextContactAt: String,
)
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package com.alarmy.near.network.service

import com.alarmy.near.network.response.FriendEntity
import com.alarmy.near.network.response.MonthlyFriendEntity
import retrofit2.http.GET

interface FriendService {
@GET("/friend/list")
suspend fun fetchFriends(): List<FriendEntity>

@GET("friend/monthly")

Choose a reason for hiding this comment

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

medium

API 엔드포인트 경로에 일관성이 부족합니다. /friend/list는 슬래시로 시작하지만 friend/monthly는 그렇지 않습니다. Retrofit은 기본 URL에 상대적으로 경로를 해석하지만, 혼동을 피하고 일관성을 유지하기 위해 모든 경로를 슬래시로 시작하는 것이 좋습니다.

Suggested change
@GET("friend/monthly")
@GET("/friend/monthly")

suspend fun fetchMonthlyFriends(): List<MonthlyFriendEntity>
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import kotlinx.serialization.Serializable
@Serializable
object RouteFriendProfile

fun NavController.navigateToFriendProfile(navOptions: NavOptions) {
fun NavController.navigateToFriendProfile(
friendId: String,
navOptions: NavOptions? = null,
) {
navigate(RouteFriendProfile, navOptions)
}

Choose a reason for hiding this comment

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

critical

navigateToFriendProfile 함수가 friendId를 인자로 받지만, 실제 navigate 호출 시에는 사용하지 않고 있습니다. 이로 인해 친구 프로필 화면으로 이동할 때 어떤 친구의 프로필을 보여줘야 할지 알 수 없습니다.

이를 해결하려면 RouteFriendProfileobject에서 friendId를 가질 수 있는 data class로 변경하고, navigate 함수 호출 시 friendId를 전달해야 합니다.

Suggested change
object RouteFriendProfile
fun NavController.navigateToFriendProfile(navOptions: NavOptions) {
fun NavController.navigateToFriendProfile(
friendId: String,
navOptions: NavOptions? = null,
) {
navigate(RouteFriendProfile, navOptions)
}
@Serializable
data class RouteFriendProfile(val friendId: String)
fun NavController.navigateToFriendProfile(
friendId: String,
navOptions: NavOptions? = null,
) {
navigate(RouteFriendProfile(friendId), navOptions)
}


Expand Down
Loading