From f1680fd4bc19c3aa4ee0c91cdcae81ab60c16976 Mon Sep 17 00:00:00 2001 From: juhwankim-dev Date: Mon, 22 Dec 2025 01:28:03 +0900 Subject: [PATCH] =?UTF-8?q?NR-122=20=ED=83=80=EC=9D=B4=EB=A8=B8,=20?= =?UTF-8?q?=ED=9E=8C=ED=8A=B8=20=ED=99=94=EB=A9=B4=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EA=B4=80=EB=A6=AC=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EB=B0=A9=EB=B2=95=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 왜? 힌트 화면에서 진행률만 확인하고 힌트 차감없이 되돌아가는 기능이 새로 개발될 예정임 기존에는 힌트를 차감하고 다음 화면으로 넘어가는 방식이였으나 앞으로는 힌트 화면에서 데이터의 변경을 담당하게 될거임. 근데 이걸 setFragmentResult로 하면 다소 코드가 너저분해지고 나중에 기능이 확장될 것을 생각하면 이 방식은 누가 누구에게 무엇을 넘겼는지 파악하기 어려워짐 어떻게? argument를 넘기는 방식에서 graph viewModel을 사용해 관리하는 방법으로 변경 --- .../presentation/ui/hint/HintFragment.kt | 19 ++++++++ .../presentation/ui/hint/HintViewModel.kt | 23 +++++---- .../presentation/ui/main/GameViewModel.kt | 48 +++++++++++++++++++ .../presentation/ui/main/TimerEvent.kt | 4 +- .../presentation/ui/main/TimerFragment.kt | 5 +- .../presentation/ui/main/TimerViewModel.kt | 3 +- .../main/res/navigation/game_navigation.xml | 15 +----- 7 files changed, 89 insertions(+), 28 deletions(-) create mode 100644 presentation/src/main/java/com/nextroom/nextroom/presentation/ui/main/GameViewModel.kt diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/hint/HintFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/hint/HintFragment.kt index cdf313a6..83bd9cd9 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/hint/HintFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/hint/HintFragment.kt @@ -5,6 +5,7 @@ import android.view.View import androidx.core.os.bundleOf import androidx.core.view.isVisible import androidx.fragment.app.viewModels +import androidx.hilt.navigation.fragment.hiltNavGraphViewModels import androidx.navigation.fragment.findNavController import androidx.viewpager2.widget.ViewPager2 import com.google.firebase.analytics.FirebaseAnalytics @@ -29,6 +30,9 @@ import timber.log.Timber class HintFragment : BaseFragment(FragmentHintBinding::inflate) { private val viewModel: HintViewModel by viewModels() + private val gameSharedViewModel: com.nextroom.nextroom.presentation.ui.main.GameSharedViewModel by hiltNavGraphViewModels( + R.id.game_navigation + ) private val state: HintState get() = viewModel.container.stateFlow.value @@ -43,6 +47,21 @@ class HintFragment : BaseFragment(FragmentHintBinding::infl override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) FirebaseAnalytics.getInstance(requireContext()).logEvent("screen_view", bundleOf("screen_name" to "hint")) + + // Shared ViewModel에서 hint 수집 + viewLifecycleOwner.repeatOnStarted { + gameSharedViewModel.currentHint.collect { hint -> + hint?.let { viewModel.setHint(it) } + } + } + + // Shared ViewModel에서 subscribeStatus 수집 + viewLifecycleOwner.repeatOnStarted { + gameSharedViewModel.subscribeStatus.collect { subscribeStatus -> + viewModel.setSubscribeStatus(subscribeStatus) + } + } + initViews() viewModel.observe(viewLifecycleOwner, state = ::render, sideEffect = ::handleEvent) } diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/hint/HintViewModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/hint/HintViewModel.kt index 8912962c..890dbe41 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/hint/HintViewModel.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/hint/HintViewModel.kt @@ -1,6 +1,5 @@ package com.nextroom.nextroom.presentation.ui.hint -import androidx.lifecycle.SavedStateHandle import com.mangbaam.commonutil.DateTimeUtil import com.nextroom.nextroom.domain.repository.AdminRepository import com.nextroom.nextroom.domain.repository.DataStoreRepository @@ -18,7 +17,6 @@ import javax.inject.Inject @HiltViewModel class HintViewModel @Inject constructor( - savedStateHandle: SavedStateHandle, private val timerRepository: TimerRepository, private val statsRepository: StatisticsRepository, private val adminRepository: AdminRepository, @@ -26,12 +24,7 @@ class HintViewModel @Inject constructor( ) : BaseViewModel() { override val container: Container = - container( - HintState( - hint = savedStateHandle.get("hint") ?: Hint(), - userSubscribeStatus = HintFragmentArgs.fromSavedStateHandle(savedStateHandle).subscribeStatus, - ) - ) + container(HintState()) private val state: HintState get() = container.stateFlow.value @@ -60,6 +53,20 @@ class HintViewModel @Inject constructor( reduce { state.copy(networkDisconnectedCount = count) } } + /** + * Called by HintFragment when hint is received from GameSharedViewModel + */ + fun setHint(hint: Hint) = intent { + reduce { state.copy(hint = hint) } + } + + /** + * Called by HintFragment when subscribeStatus is received from GameSharedViewModel + */ + fun setSubscribeStatus(subscribeStatus: com.nextroom.nextroom.domain.model.SubscribeStatus) = intent { + reduce { state.copy(userSubscribeStatus = subscribeStatus) } + } + fun openAnswer() = intent { reduce { state.copy(hint = state.hint.copy(answerOpened = true)) } // 정답 오픈 시간 통계 집계 diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/main/GameViewModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/main/GameViewModel.kt new file mode 100644 index 00000000..d5c28604 --- /dev/null +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/main/GameViewModel.kt @@ -0,0 +1,48 @@ +package com.nextroom.nextroom.presentation.ui.main + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import com.nextroom.nextroom.domain.model.SubscribeStatus +import com.nextroom.nextroom.presentation.model.Hint +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import javax.inject.Inject + +@HiltViewModel +class GameSharedViewModel @Inject constructor( + savedStateHandle: SavedStateHandle +) : ViewModel() { + + // subscribeStatus는 상위 navigation에서 전달받음 + private val _subscribeStatus = MutableStateFlow( + TimerFragmentArgs.fromSavedStateHandle(savedStateHandle).subscribeStatus + ) + val subscribeStatus: StateFlow = _subscribeStatus.asStateFlow() + + // hint는 TimerFragment에서 설정 + private val _currentHint = MutableStateFlow(null) + val currentHint: StateFlow = _currentHint.asStateFlow() + + /** + * Called by TimerFragment when user opens a hint + */ + fun setCurrentHint(hint: Hint) { + _currentHint.value = hint + } + + /** + * Called when HintFragment updates hint state (e.g., answer opened) + */ + fun updateCurrentHint(hint: Hint) { + _currentHint.value = hint + } + + /** + * Clear hint when returning to timer screen + */ + fun clearCurrentHint() { + _currentHint.value = null + } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/main/TimerEvent.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/main/TimerEvent.kt index 9a6d776f..47d8e382 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/main/TimerEvent.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/main/TimerEvent.kt @@ -1,12 +1,10 @@ package com.nextroom.nextroom.presentation.ui.main -import com.nextroom.nextroom.domain.model.SubscribeStatus import com.nextroom.nextroom.presentation.model.Hint sealed interface TimerEvent { data class OnOpenHint( - val hint: Hint, - val subscribeStatus: SubscribeStatus + val hint: Hint ) : TimerEvent data object TimerFinish : TimerEvent diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/main/TimerFragment.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/main/TimerFragment.kt index 4be8a308..1f047e2c 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/main/TimerFragment.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/main/TimerFragment.kt @@ -12,6 +12,7 @@ import androidx.core.view.isVisible import androidx.fragment.app.activityViewModels import androidx.fragment.app.setFragmentResultListener import androidx.fragment.app.viewModels +import androidx.hilt.navigation.fragment.hiltNavGraphViewModels import androidx.navigation.fragment.findNavController import com.bumptech.glide.Glide import com.bumptech.glide.load.DataSource @@ -50,6 +51,7 @@ class TimerFragment : BaseFragment(FragmentTimerBinding::i private val viewModel: TimerViewModel by viewModels() private val painterViewModel: PainterViewModel by activityViewModels() + private val gameSharedViewModel: GameSharedViewModel by hiltNavGraphViewModels(R.id.game_navigation) private var gameStartConfirmDialog: NRDialog? = null @@ -266,7 +268,8 @@ class TimerFragment : BaseFragment(FragmentTimerBinding::i when (event) { is TimerEvent.ClearHintCode -> binding.customCodeInput.setCode("") is TimerEvent.OnOpenHint -> { - val action = TimerFragmentDirections.moveToHintFragment(event.hint, event.subscribeStatus) + gameSharedViewModel.setCurrentHint(event.hint) + val action = TimerFragmentDirections.moveToHintFragment() findNavController().safeNavigate(action) viewModel.clearHintCode() } diff --git a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/main/TimerViewModel.kt b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/main/TimerViewModel.kt index 21dc38c0..de3e5907 100644 --- a/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/main/TimerViewModel.kt +++ b/presentation/src/main/java/com/nextroom/nextroom/presentation/ui/main/TimerViewModel.kt @@ -208,8 +208,7 @@ class TimerViewModel @Inject constructor( answerOpened = state.answerOpenedHints.contains(hint.id), hintImageUrlList = hint.hintImageUrlList.toList(), answerImageUrlList = hint.answerImageUrlList.toList() - ), - TimerFragmentArgs.fromSavedStateHandle(savedStateHandle).subscribeStatus + ) ), ) setGameState() diff --git a/presentation/src/main/res/navigation/game_navigation.xml b/presentation/src/main/res/navigation/game_navigation.xml index 995be402..46fcd5c3 100644 --- a/presentation/src/main/res/navigation/game_navigation.xml +++ b/presentation/src/main/res/navigation/game_navigation.xml @@ -12,14 +12,7 @@ - - - + app:destination="@id/hint_fragment" /> @@ -43,12 +36,6 @@ - -