From 8a175a1201cf90e669acbc15666ad3cf79245c50 Mon Sep 17 00:00:00 2001 From: kwakjoohyeong Date: Sat, 6 Dec 2025 15:43:14 +0900 Subject: [PATCH 1/4] =?UTF-8?q?fix:=20=EC=B1=99=EA=B9=80=20=EA=B8=B0?= =?UTF-8?q?=EB=A1=9D=20=EC=8B=9C=EC=97=90=20=EA=B8=B0=EB=A1=9D=20=EB=82=A0?= =?UTF-8?q?=EC=A7=9C=20=EB=B0=8F=20=EB=B2=84=ED=8A=BC=20=EB=B9=84=ED=99=9C?= =?UTF-8?q?=EC=84=B1=ED=99=94=EA=B0=80=20=EC=95=88=EB=90=98=EB=8A=94=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/friendprofile/FriendProfileViewModel.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Near/app/src/main/java/com/alarmy/near/presentation/feature/friendprofile/FriendProfileViewModel.kt b/Near/app/src/main/java/com/alarmy/near/presentation/feature/friendprofile/FriendProfileViewModel.kt index 90926c87..4e22eb26 100644 --- a/Near/app/src/main/java/com/alarmy/near/presentation/feature/friendprofile/FriendProfileViewModel.kt +++ b/Near/app/src/main/java/com/alarmy/near/presentation/feature/friendprofile/FriendProfileViewModel.kt @@ -113,14 +113,14 @@ class FriendProfileViewModel } if (friendFlow.value is FriendState.Success) { _friendFlow.update { + val updatedLastContactAt = getTodayDashFormat() (it as FriendState.Success).copy( friend = it.friend.copy( - lastContactAt = getTodayDashFormat(), - lastContactFormat = it.friend.lastContactAt?.contactFormat(), + lastContactAt = updatedLastContactAt, + lastContactFormat = updatedLastContactAt.contactFormat(), isContactToday = - it.friend.lastContactAt?.isToday() - ?: false, + updatedLastContactAt.isToday(), ), ) } @@ -163,5 +163,5 @@ class FriendProfileViewModel val targetDate = LocalDate.parse(this, formatter) val today = LocalDate.now() return targetDate == today + } } -} From fd4bae200ea20baca6df31be8f0a084461e1cfd8 Mon Sep 17 00:00:00 2001 From: kwakjoohyeong Date: Sun, 7 Dec 2025 23:39:34 +0900 Subject: [PATCH 2/4] =?UTF-8?q?fix:=20=ED=99=88=20=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?=EB=8F=8C=EC=95=84=EC=98=AC=20=EC=8B=9C=20=EC=B1=99=EA=B9=80=20?= =?UTF-8?q?=EC=97=AC=EB=B6=80=20=EC=9D=BC=EC=8B=9C=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../friendprofile/FriendProfileScreen.kt | 46 ++++++---- .../navigation/FriendProfileNavigation.kt | 2 +- .../feature/home/HomeViewModel.kt | 39 +++++++-- .../feature/home/navigation/HomeNavigation.kt | 32 ++++++- .../presentation/feature/main/NearNavHost.kt | 87 +++++++++++-------- 5 files changed, 147 insertions(+), 59 deletions(-) diff --git a/Near/app/src/main/java/com/alarmy/near/presentation/feature/friendprofile/FriendProfileScreen.kt b/Near/app/src/main/java/com/alarmy/near/presentation/feature/friendprofile/FriendProfileScreen.kt index 9ca3720d..f5e6261e 100644 --- a/Near/app/src/main/java/com/alarmy/near/presentation/feature/friendprofile/FriendProfileScreen.kt +++ b/Near/app/src/main/java/com/alarmy/near/presentation/feature/friendprofile/FriendProfileScreen.kt @@ -1,5 +1,6 @@ package com.alarmy.near.presentation.feature.friendprofile +import androidx.activity.compose.BackHandler import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.tween @@ -79,7 +80,7 @@ import kotlinx.coroutines.launch fun FriendProfileRoute( viewModel: FriendProfileViewModel = hiltViewModel(), onShowErrorSnackBar: (throwable: Throwable?) -> Unit, - onClickBackButton: () -> Unit = {}, + onClickBackButton: (Friend?) -> Unit = {}, onEditFriendInfo: (Friend) -> Unit = {}, onClickCallButton: (phoneNumber: String) -> Unit = {}, onClickMessageButton: (phoneNumber: String) -> Unit = {}, @@ -107,6 +108,11 @@ fun FriendProfileRoute( } } } + BackHandler { + // 다이얼로그 등이 있으면 해당 백 처리를 우선 수행 + onClickBackButton((friendState.value as? FriendState.Success)?.friend) + } + FriendProfileScreen( friendState = friendState.value, friendShipRecordState = friendShipRecordState.value, @@ -129,7 +135,7 @@ fun FriendProfileScreen( friendState: FriendState, friendShipRecordState: FriendShipRecordState, recordSuccessDialogState: Boolean = false, - onClickBackButton: () -> Unit = {}, + onClickBackButton: (Friend) -> Unit = {}, onEditFriendInfo: (Friend) -> Unit = {}, onClickCallButton: (phoneNumber: String) -> Unit = {}, onClickMessageButton: (phoneNumber: String) -> Unit = {}, @@ -190,7 +196,9 @@ fun FriendProfileScreen( // (1) 상단 AppBar — 고정 NearTopAppbar( title = stringResource(R.string.friend_profile_title), - onClickBackButton = onClickBackButton, + onClickBackButton = { + onClickBackButton(friend) + }, menuButton = { Column(modifier = Modifier.padding(end = 20.dp)) { Image( @@ -345,7 +353,7 @@ fun FriendProfileScreen( NearTheme.colors.GRAY01_888888.copy( alpha = 0.3f, ), - selected = currentTabPosition.intValue == 0, + selected = currentTabPosition.intValue == 0, onClick = { currentTabPosition.intValue = 0 }, ) { Text( @@ -375,9 +383,10 @@ fun FriendProfileScreen( .height(50.dp), selected = currentTabPosition.intValue == 1, onClick = { currentTabPosition.intValue = 1 }, - selectedContentColor = NearTheme.colors.GRAY01_888888.copy( - alpha = 0.3f - ), + selectedContentColor = + NearTheme.colors.GRAY01_888888.copy( + alpha = 0.3f, + ), ) { Text( text = stringResource(R.string.friend_profile_tab_text_record), @@ -424,14 +433,21 @@ fun FriendProfileScreen( // (3) 하단 고정 버튼 Box( modifier = - Modifier.fillMaxWidth().background( - brush = - Brush.linearGradient( - colors = listOf(Color(0x00FFFFFF), Color(0xFFFFFFFF)), // 파랑 → 밝은 하늘색 - start = Offset(0f, 0f), // 위쪽 시작 - end = Offset(0f, Float.POSITIVE_INFINITY), - ), - ), + Modifier + .fillMaxWidth() + .background( + brush = + Brush.linearGradient( + colors = + listOf( + Color(0x00FFFFFF), + Color(0xFFFFFFFF), + ), + // 파랑 → 밝은 하늘색 + start = Offset(0f, 0f), // 위쪽 시작 + end = Offset(0f, Float.POSITIVE_INFINITY), + ), + ), ) { NearSolidTypeButton( modifier = diff --git a/Near/app/src/main/java/com/alarmy/near/presentation/feature/friendprofile/navigation/FriendProfileNavigation.kt b/Near/app/src/main/java/com/alarmy/near/presentation/feature/friendprofile/navigation/FriendProfileNavigation.kt index 2012a998..96f1a837 100644 --- a/Near/app/src/main/java/com/alarmy/near/presentation/feature/friendprofile/navigation/FriendProfileNavigation.kt +++ b/Near/app/src/main/java/com/alarmy/near/presentation/feature/friendprofile/navigation/FriendProfileNavigation.kt @@ -37,7 +37,7 @@ fun NavController.navigateToFriendProfile( fun NavGraphBuilder.friendProfileNavGraph( onShowErrorSnackBar: (throwable: Throwable?) -> Unit, - onClickBackButton: () -> Unit, + onClickBackButton: (Friend?) -> Unit, onEditFriendInfo: (Friend) -> Unit = {}, onClickCallButton: (phoneNumber: String) -> Unit = {}, onClickMessageButton: (phoneNumber: String) -> Unit = {}, diff --git a/Near/app/src/main/java/com/alarmy/near/presentation/feature/home/HomeViewModel.kt b/Near/app/src/main/java/com/alarmy/near/presentation/feature/home/HomeViewModel.kt index 96b35ec4..1e09a448 100644 --- a/Near/app/src/main/java/com/alarmy/near/presentation/feature/home/HomeViewModel.kt +++ b/Near/app/src/main/java/com/alarmy/near/presentation/feature/home/HomeViewModel.kt @@ -1,5 +1,6 @@ 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.FriendRepository @@ -75,13 +76,13 @@ class HomeViewModel monthlyFriends.filter { it.friendId !in deletedIds } }.catch { _errorEvent.send(it) - }.collect { - _uiState.update { state -> - state.copy( - monthlyFriendUIState = MonthlyFriendUIState.Success(it), - ) - } + }.collect { + _uiState.update { state -> + state.copy( + monthlyFriendUIState = MonthlyFriendUIState.Success(it), + ) } + } } } } @@ -91,4 +92,30 @@ class HomeViewModel deletedFriendIdsFlow.emit(deletedFriendIdsFlow.value + friendId) } } + + fun updateFriendReminder( + friendId: String, + friendReminderUpdatedAt: String?, + ) { + _uiState.update { state -> + val current = state.myFriendUIState + + if (current is MyFriendUIState.Success) { + val updatedList = + current.myFriends.map { friend -> + if (friend.id == friendId) { + friend.copy(lastContactedAt = friendReminderUpdatedAt) + } else { + friend + } + } + + return@update state.copy( + myFriendUIState = MyFriendUIState.Success(updatedList), + ) + } + + state + } + } } diff --git a/Near/app/src/main/java/com/alarmy/near/presentation/feature/home/navigation/HomeNavigation.kt b/Near/app/src/main/java/com/alarmy/near/presentation/feature/home/navigation/HomeNavigation.kt index 61d1b03e..ed8a8483 100644 --- a/Near/app/src/main/java/com/alarmy/near/presentation/feature/home/navigation/HomeNavigation.kt +++ b/Near/app/src/main/java/com/alarmy/near/presentation/feature/home/navigation/HomeNavigation.kt @@ -1,5 +1,6 @@ package com.alarmy.near.presentation.feature.home.navigation +import android.os.Parcelable import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder @@ -7,13 +8,30 @@ import androidx.navigation.NavOptions import androidx.navigation.compose.composable import com.alarmy.near.presentation.feature.home.HomeRoute import com.alarmy.near.presentation.feature.home.HomeViewModel +import kotlinx.parcelize.Parcelize import kotlinx.serialization.Serializable const val HOME_FRIEND_DELETE_COMPLETE_KEY = "HOME_FRIEND_DELETE_COMPLETE_KEY" +const val HOME_RESULT_EVENT = "HOME_RESULT_EVENT" @Serializable object RouteHome +sealed interface HomeNavigationEvent : Parcelable { + @Parcelize + @Serializable + data class FriendDeleted( + val friendId: String, + ) : HomeNavigationEvent + + @Parcelize + @Serializable + data class FriendReminderUpdated( + val friendId: String, + val friendReminderUpdatedAt: String?, + ) : HomeNavigationEvent +} + /* * 추후 홈으로 화면 이동이 필요할 때 이 함수를 사용합니다. * */ @@ -31,10 +49,18 @@ fun NavGraphBuilder.homeNavGraph( ) { composable { backStackEntry -> val viewModel: HomeViewModel = hiltViewModel() - val friendId: String? = backStackEntry.savedStateHandle.get(HOME_FRIEND_DELETE_COMPLETE_KEY) - friendId?.let { - viewModel.deleteFriend(it) + val homeEvent = backStackEntry.savedStateHandle.get(HOME_RESULT_EVENT) + when (homeEvent) { + is HomeNavigationEvent.FriendDeleted -> { + viewModel.deleteFriend(homeEvent.friendId) + } + + is HomeNavigationEvent.FriendReminderUpdated -> { + viewModel.updateFriendReminder(homeEvent.friendId, homeEvent.friendReminderUpdatedAt) + } + null -> Unit } + HomeRoute( onShowErrorSnackBar = onShowErrorSnackBar, onContactClick = onContactClick, diff --git a/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/NearNavHost.kt b/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/NearNavHost.kt index c8012d1f..e6587a9c 100644 --- a/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/NearNavHost.kt +++ b/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/NearNavHost.kt @@ -8,6 +8,7 @@ import androidx.core.net.toUri import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.navOptions +import com.alarmy.near.model.Friend import com.alarmy.near.presentation.feature.contact.navigation.CONTACT_SELECTION_COMPLETE_KEY import com.alarmy.near.presentation.feature.contact.navigation.contactNavGraph import com.alarmy.near.presentation.feature.contact.navigation.navigateToContact @@ -18,7 +19,8 @@ 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.HOME_RESULT_EVENT +import com.alarmy.near.presentation.feature.home.navigation.HomeNavigationEvent 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 @@ -119,40 +121,57 @@ internal fun NearNavHost( ) // 친구 프로필 화면 NavGraph - friendProfileNavGraph(onShowErrorSnackBar = onShowSnackbar, onClickBackButton = { - navController.popBackStack() - }, onClickCallButton = { phoneNumber -> - val intent = - Intent(Intent.ACTION_DIAL).apply { - data = "tel:$phoneNumber".toUri() - } - context.startActivity(intent) - }, onClickMessageButton = { phoneNumber -> - val intent = - Intent(Intent.ACTION_VIEW).apply { - data = "sms:$phoneNumber".toUri() + friendProfileNavGraph( + onShowErrorSnackBar = onShowSnackbar, + onClickBackButton = { friend: Friend? -> + friend?.let { + navController.previousBackStackEntry?.savedStateHandle?.set( + HOME_RESULT_EVENT, + HomeNavigationEvent.FriendReminderUpdated( + friend.friendId, + friend.lastContactAt, + ), + ) } - context.startActivity(intent) - }, onEditFriendInfo = { - navController.navigateToFriendProfileEditor( - friend = - it.copy( - imageUrl = - it.imageUrl?.let { imageUrl -> - URLEncoder.encode( - imageUrl, - StandardCharsets.UTF_8.toString(), - ) - }, - ), - ) - }, onDeleteFriendSuccess = { - navController.previousBackStackEntry?.savedStateHandle?.set( - HOME_FRIEND_DELETE_COMPLETE_KEY, - it, - ) - navController.popBackStack() - }) + + navController.popBackStack() + }, + onClickCallButton = { phoneNumber -> + val intent = + Intent(Intent.ACTION_DIAL).apply { + data = "tel:$phoneNumber".toUri() + } + context.startActivity(intent) + }, + onClickMessageButton = { phoneNumber -> + val intent = + Intent(Intent.ACTION_VIEW).apply { + data = "sms:$phoneNumber".toUri() + } + context.startActivity(intent) + }, + onEditFriendInfo = { + navController.navigateToFriendProfileEditor( + friend = + it.copy( + imageUrl = + it.imageUrl?.let { imageUrl -> + URLEncoder.encode( + imageUrl, + StandardCharsets.UTF_8.toString(), + ) + }, + ), + ) + }, + onDeleteFriendSuccess = { + navController.previousBackStackEntry?.savedStateHandle?.set( + HOME_RESULT_EVENT, + HomeNavigationEvent.FriendDeleted(it), + ) + navController.popBackStack() + }, + ) // 친구 프로필 편집 화면 NavGraph friendProfileEditorNavGraph(onShowErrorSnackBar = onShowSnackbar, onClickBackButton = { From 657ab80908603a07c98c1146aa4482371cabb371 Mon Sep 17 00:00:00 2001 From: kwakjoohyeong Date: Tue, 9 Dec 2025 00:20:47 +0900 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20=EC=9D=B4=EB=B2=88=EB=8B=AC=20?= =?UTF-8?q?=EC=B1=99=EA=B8=B8=20=EC=82=AC=EB=9E=8C=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=B1=99=EA=B8=B8=20=EC=8B=9C=EC=97=90=20=EC=B1=99=EA=B9=80=20?= =?UTF-8?q?=EB=82=A0=EC=A7=9C=EB=A1=9C=20=EB=B0=98=EC=98=81=EB=90=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mothlyreminderall/MonthlyReminderAllViewModel.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Near/app/src/main/java/com/alarmy/near/presentation/feature/mothlyreminderall/MonthlyReminderAllViewModel.kt b/Near/app/src/main/java/com/alarmy/near/presentation/feature/mothlyreminderall/MonthlyReminderAllViewModel.kt index 08aa4205..deeb63ed 100644 --- a/Near/app/src/main/java/com/alarmy/near/presentation/feature/mothlyreminderall/MonthlyReminderAllViewModel.kt +++ b/Near/app/src/main/java/com/alarmy/near/presentation/feature/mothlyreminderall/MonthlyReminderAllViewModel.kt @@ -22,6 +22,7 @@ import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import java.time.LocalDate +import java.time.format.DateTimeFormatter import javax.inject.Inject @HiltViewModel @@ -92,6 +93,7 @@ class MonthlyReminderAllViewModel } } + // 챙김시에 기념일이 나와야 함 fun onRecordFriendShip(friendId: String) { friendRepository .recordContact(friendId) @@ -103,7 +105,14 @@ class MonthlyReminderAllViewModel if (recordedFriend != null) { monthlyReminders.value = monthlyReminders.value.filter { it.friendId != friendId } - completedReminders.value = listOf(recordedFriend) + completedReminders.value + completedReminders.value = listOf( + recordedFriend.copy( + nextContactAt = + LocalDate + .now() + .format(DateTimeFormatter.ofPattern("yy.MM.dd")), + ), + ) + completedReminders.value combineRemindersToUIState() } }.handleError(viewModelScope, _uiEvent) { exception -> From d48afd9ebccbfb4705574ff3ec1947df61c01262 Mon Sep 17 00:00:00 2001 From: kwakjoohyeong Date: Sun, 14 Dec 2025 17:42:50 +0900 Subject: [PATCH 4/4] =?UTF-8?q?fix:=20recomposition=20=EC=95=88=EB=90=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/home/navigation/HomeNavigation.kt | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Near/app/src/main/java/com/alarmy/near/presentation/feature/home/navigation/HomeNavigation.kt b/Near/app/src/main/java/com/alarmy/near/presentation/feature/home/navigation/HomeNavigation.kt index ed8a8483..ed1cdafe 100644 --- a/Near/app/src/main/java/com/alarmy/near/presentation/feature/home/navigation/HomeNavigation.kt +++ b/Near/app/src/main/java/com/alarmy/near/presentation/feature/home/navigation/HomeNavigation.kt @@ -1,7 +1,10 @@ package com.alarmy.near.presentation.feature.home.navigation import android.os.Parcelable +import android.util.Log +import androidx.compose.runtime.LaunchedEffect import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions @@ -50,15 +53,17 @@ fun NavGraphBuilder.homeNavGraph( composable { backStackEntry -> val viewModel: HomeViewModel = hiltViewModel() val homeEvent = backStackEntry.savedStateHandle.get(HOME_RESULT_EVENT) - when (homeEvent) { - is HomeNavigationEvent.FriendDeleted -> { - viewModel.deleteFriend(homeEvent.friendId) - } + LaunchedEffect(homeEvent) { + when (homeEvent) { + is HomeNavigationEvent.FriendDeleted -> { + viewModel.deleteFriend(homeEvent.friendId) + } - is HomeNavigationEvent.FriendReminderUpdated -> { - viewModel.updateFriendReminder(homeEvent.friendId, homeEvent.friendReminderUpdatedAt) + is HomeNavigationEvent.FriendReminderUpdated -> { + viewModel.updateFriendReminder(homeEvent.friendId, homeEvent.friendReminderUpdatedAt) + } + null -> Unit } - null -> Unit } HomeRoute(