Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,20 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Surface
import androidx.compose.material3.Tab
Expand All @@ -46,7 +43,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.debugInspectorInfo
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
Expand Down Expand Up @@ -146,6 +142,7 @@ fun FriendProfileScreen(
) {
val currentTabPosition = remember { mutableIntStateOf(0) }
val dropdownState = remember { mutableStateOf(false) }
val scrollState = rememberScrollState()

NearFrame(modifier = modifier) {
Box {
Expand All @@ -157,6 +154,7 @@ fun FriendProfileScreen(
Modifier
.align(Alignment.TopStart)
.fillMaxSize()
.verticalScroll(scrollState)
.background(NearTheme.colors.WHITE_FFFFFF),
) {
if (recordSuccessDialogState) {
Expand Down Expand Up @@ -215,14 +213,14 @@ fun FriendProfileScreen(
onEditFriendInfo(friend)
dropdownState.value = false
},
text = stringResource(R.string.friend_profile_info_edit)
text = stringResource(R.string.friend_profile_info_edit),
)
NearDropdownMenuItem(
onClick = {
onDeleteFriend(friend.friendId)
dropdownState.value = false
},
text = stringResource(R.string.friend_profile_info_delete)
text = stringResource(R.string.friend_profile_info_delete),
)
}
}
Expand Down Expand Up @@ -390,6 +388,7 @@ fun FriendProfileScreen(
Modifier
.fillMaxWidth()
.padding(horizontal = 20.dp)
.padding(bottom = 24.dp)
.align(Alignment.BottomCenter),
contentPadding = PaddingValues(vertical = 17.dp),
enabled = friend.isContactedToday.not(),
Expand Down Expand Up @@ -450,6 +449,7 @@ private fun ProfileTab(
ProfileMemoInfo(
content = friend.memo,
)
Spacer(modifier = Modifier.height(76.dp))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fun CallButton(
disabledContainerColor = Color(0xfff7f7f7),
disabledContentColor = NearTheme.colors.GRAY02_B7B7B7,
),
contentPadding = PaddingValues(start = 42.dp, end = 45.dp, top = 12.dp, bottom = 12.dp),
contentPadding = PaddingValues(top = 12.dp, bottom = 12.dp),
enabled = enabled,
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Expand All @@ -47,6 +47,7 @@ fun CallButton(
)
Spacer(modifier = Modifier.width(4.dp))
Text(
maxLines = 1,
text = stringResource(R.string.friend_profile_call),
style = NearTheme.typography.B2_14_MEDIUM,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fun MessageButton(
disabledContainerColor = Color(0xfff7f7f7),
disabledContentColor = NearTheme.colors.GRAY02_B7B7B7,
),
contentPadding = PaddingValues(start = 42.dp, end = 45.dp, top = 12.dp, bottom = 12.dp),
contentPadding = PaddingValues(top = 12.dp, bottom = 12.dp),
enabled = enabled,
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ fun NavGraphBuilder.friendProfileNavGraph(
onEditFriendInfo: (Friend) -> Unit = {},
onClickCallButton: (phoneNumber: String) -> Unit = {},
onClickMessageButton: (phoneNumber: String) -> Unit = {},
onDeleteFriendSuccess: (friendId: String) -> Unit = {},
) {
composable<RouteFriendProfile> { backStackEntry ->
val viewModel: FriendProfileViewModel = hiltViewModel()
Expand All @@ -55,6 +56,7 @@ fun NavGraphBuilder.friendProfileNavGraph(
onEditFriendInfo = onEditFriendInfo,
onClickCallButton = onClickCallButton,
onClickMessageButton = onClickMessageButton,
onDeleteFriendSuccess = onDeleteFriendSuccess,
)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.alarmy.near.presentation.feature.friendprofileedittor

import androidx.activity.compose.BackHandler
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
Expand Down Expand Up @@ -71,6 +72,9 @@ fun FriendProfileEditorRoute(
val friendProfileEditorUIState = viewModel.uiState.collectAsStateWithLifecycle()
val warningDialogState = remember { mutableStateOf(false) }
val context = LocalContext.current
BackHandler {
viewModel.onExit()
}

LaunchedEffect(viewModel.uiEvent) {
launch {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.alarmy.near.R
import com.alarmy.near.model.friendsummary.ContactFrequencyLevel
import com.alarmy.near.model.friendsummary.FriendSummary
import com.alarmy.near.model.member.MemberInfo
import com.alarmy.near.model.monthly.MonthlyFriend
import com.alarmy.near.model.monthly.MonthlyFriendType
import com.alarmy.near.presentation.feature.home.component.MyContacts
Expand All @@ -77,10 +78,11 @@ internal fun HomeRoute(
LaunchedEffect(Unit) {
launch {
viewModel.errorEvent.collect {
onShowErrorSnackBar(it)
onShowErrorSnackBar(IllegalStateException("네트워크 에러가 발생했습니다."))

Choose a reason for hiding this comment

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

high

기존에 viewModel.errorEvent에서 전달되던 Throwable 객체를 사용하지 않고, 새로운 IllegalStateException을 생성하여 하드코딩된 메시지를 전달하고 있습니다. 이 방식은 원래 발생했던 에러의 상세 정보를 잃게 만들어 디버깅을 어렵게 할 수 있습니다. 기존 구현처럼 onShowErrorSnackBar(it)을 그대로 호출하여 원래의 Throwable을 전달하는 것이 더 바람직해 보입니다. onShowErrorSnackBar의 구현을 보면 null이거나 message가 없는 경우를 이미 잘 처리하고 있습니다.

Suggested change
onShowErrorSnackBar(IllegalStateException("네트워크 에러가 발생했습니다."))
onShowErrorSnackBar(it)

}
}
}
val memberInfo = viewModel.memberInfoFlow.collectAsStateWithLifecycle()
val friends = viewModel.friendsFlow.collectAsStateWithLifecycle()
val monthlyFriends = viewModel.monthlyFriendFlow.collectAsStateWithLifecycle()
HomeScreen(
Expand All @@ -90,6 +92,7 @@ internal fun HomeRoute(
onAddContactClick = onAddContactClick,
contacts = friends.value,
monthlyFriends = monthlyFriends.value,
memberInfo = memberInfo.value,
)
}

Expand All @@ -101,6 +104,7 @@ internal fun HomeScreen(
onMyPageClick: () -> Unit = {},
onAlarmClick: () -> Unit = {},
onAddContactClick: () -> Unit = {},
memberInfo: MemberInfo?,
contacts: List<FriendSummary>,
monthlyFriends: List<MonthlyFriend>,
) {
Expand Down Expand Up @@ -155,7 +159,7 @@ internal fun HomeScreen(
Text(
text =
buildAnnotatedString {
append("주지스님,\n")
append("${memberInfo?.nickname}님,\n")
withStyle(
SpanStyle(
fontWeight = FontWeight.Bold,
Expand Down Expand Up @@ -392,6 +396,15 @@ internal fun HomeScreenPreview() {
nextContactAt = "2025-09-30",
)
},
memberInfo =
MemberInfo(
memberId = "posidonium",
username = "주지스님",
nickname = "Audra Day",
imageUrl = "https://search.yahoo.com/search?p=class",
notificationAgreedAt = "comprehensam",
providerType = "sumo",
),
)
}
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,51 @@
package com.alarmy.near.presentation.feature.home

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.alarmy.near.data.repository.ContactRepository
import com.alarmy.near.data.repository.FriendRepository
import com.alarmy.near.data.repository.MemberRepository
import com.alarmy.near.model.friendsummary.FriendSummary
import com.alarmy.near.model.member.MemberInfo
import com.alarmy.near.model.monthly.MonthlyFriend
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.forEach
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class HomeViewModel
@Inject
constructor(
friendRepository: FriendRepository,
contactRepository: ContactRepository,
memberRepository: MemberRepository,
) : ViewModel() {
private val _errorEvent = Channel<Throwable?>()

private val deletedFriendIdsFlow = MutableStateFlow<Set<String>>(setOf())

val errorEvent = _errorEvent.receiveAsFlow()
val memberInfoFlow: StateFlow<MemberInfo?> =
memberRepository.getMyInfo().stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5_000),
null,
)

val friendsFlow: StateFlow<List<FriendSummary>> =
friendRepository
.fetchFriends()
combine(
friendRepository
.fetchFriends(),
deletedFriendIdsFlow,
) { friends, deletedIds ->
friends.filter { it.id !in deletedIds }
}
.catch {
_errorEvent.send(it)
}.stateIn(
Expand All @@ -49,4 +65,10 @@ class HomeViewModel
started = SharingStarted.WhileSubscribed(5_000),
initialValue = emptyList(),
)

fun deleteFriend(friendId: String) {
viewModelScope.launch {
deletedFriendIdsFlow.emit(deletedFriendIdsFlow.value + friendId)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package com.alarmy.near.presentation.feature.home.navigation

import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
import com.alarmy.near.model.Friend
import com.alarmy.near.presentation.feature.friendprofile.FriendProfileViewModel
import com.alarmy.near.presentation.feature.friendprofileedittor.navigation.FRIEND_PROFILE_EDIT_COMPLETE_KEY
import com.alarmy.near.presentation.feature.home.HomeRoute
import com.alarmy.near.presentation.feature.home.HomeViewModel
import kotlinx.serialization.Serializable

const val HOME_FRIEND_DELETE_COMPLETE_KEY = "HOME_FRIEND_DELETE_COMPLETE_KEY"

@Serializable
object RouteHome

Expand All @@ -25,6 +32,12 @@ fun NavGraphBuilder.homeNavGraph(
onAddContactClick: () -> Unit = {},
) {
composable<RouteHome> { backStackEntry ->
val viewModel: HomeViewModel = hiltViewModel()
val friendId: String? = backStackEntry.savedStateHandle.get<String>(HOME_FRIEND_DELETE_COMPLETE_KEY)
friendId?.let {
viewModel.deleteFriend(it)
}
friendId

Choose a reason for hiding this comment

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

medium

40번째 줄의 friendId 표현식은 아무런 동작을 하지 않는 불필요한 코드(dead code)로 보입니다. 디버깅 과정에서 남은 코드로 추측되며, 코드 가독성을 위해 제거하는 것이 좋겠습니다.

HomeRoute(
onShowErrorSnackBar = onShowErrorSnackBar,
onContactClick = onContactClick,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import com.alarmy.near.presentation.feature.friendprofile.navigation.navigateToF
import com.alarmy.near.presentation.feature.friendprofileedittor.navigation.FRIEND_PROFILE_EDIT_COMPLETE_KEY
import com.alarmy.near.presentation.feature.friendprofileedittor.navigation.friendProfileEditorNavGraph
import com.alarmy.near.presentation.feature.friendprofileedittor.navigation.navigateToFriendProfileEditor
import com.alarmy.near.presentation.feature.home.navigation.HOME_FRIEND_DELETE_COMPLETE_KEY
import com.alarmy.near.presentation.feature.home.navigation.homeNavGraph
import com.alarmy.near.presentation.feature.home.navigation.navigateToHome
import com.alarmy.near.presentation.feature.login.navigation.loginNavGraph
Expand Down Expand Up @@ -137,6 +138,12 @@ internal fun NearNavHost(
},
),
)
}, onDeleteFriendSuccess = {
navController.previousBackStackEntry?.savedStateHandle?.set(
HOME_FRIEND_DELETE_COMPLETE_KEY,
it,
)
navController.popBackStack()
})

// 친구 프로필 편집 화면 NavGraph
Expand Down