From 65ee4fc811c20153ae6fb65dbcd376e1eceebd52 Mon Sep 17 00:00:00 2001 From: unam98 Date: Fri, 3 Apr 2026 02:04:27 +0900 Subject: [PATCH 1/2] =?UTF-8?q?refactor:=20MainActivity=20companion=20obje?= =?UTF-8?q?ct=20=EC=95=88=ED=8B=B0=ED=8C=A8=ED=84=B4=20=EC=A0=9C=EA=B1=B0,?= =?UTF-8?q?=20=ED=99=94=EB=A9=B4=20=EA=B0=84=20=ED=86=B5=EC=8B=A0=EC=9D=84?= =?UTF-8?q?=20SharedFlow=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EB=B2=84?= =?UTF-8?q?=EC=8A=A4=EB=A1=9C=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ScreenRefreshEventBus 도입: Fragment 직접 참조 대신 SharedFlow 기반 이벤트 통신 - VisitorModeManager 도입: static mutable 변수 대신 Hilt Singleton으로 방문자 모드 관리 - MainActivity.companion에서 Fragment 인스턴스 참조, isVisitorMode, updateXxxScreen() 제거 - DiscoverFragment/StorageScrapFragment의 self-registration(onAttach/onDestroy) 제거 - Adapter에 isVisitorMode 람다 파라미터 전달로 정적 참조 제거 --- .../runnect/binding/BaseVisitorFragment.kt | 13 +++--- .../runnect/presentation/MainActivity.kt | 34 +++++--------- .../runnect/runnect/presentation/MainPager.kt | 4 +- .../detail/CourseDetailActivity.kt | 18 +++++++- .../presentation/discover/DiscoverFragment.kt | 44 ++++++++++--------- .../adapter/DiscoverMarathonAdapter.kt | 8 ++-- .../adapter/DiscoverRecommendAdapter.kt | 10 +++-- .../multiview/DiscoverMultiViewAdapter.kt | 2 + .../multiview/DiscoverMultiViewHolder.kt | 9 ++-- .../DiscoverMultiViewHolderFactory.kt | 5 ++- .../discover/upload/DiscoverUploadActivity.kt | 12 ++++- .../runnect/presentation/draw/DrawActivity.kt | 7 ++- .../event/ScreenRefreshEventBus.kt | 22 ++++++++++ .../presentation/event/VisitorModeManager.kt | 19 ++++++++ .../storage/StorageScrapFragment.kt | 35 ++++++++------- 15 files changed, 160 insertions(+), 82 deletions(-) create mode 100644 app/src/main/java/com/runnect/runnect/presentation/event/ScreenRefreshEventBus.kt create mode 100644 app/src/main/java/com/runnect/runnect/presentation/event/VisitorModeManager.kt diff --git a/app/src/main/java/com/runnect/runnect/binding/BaseVisitorFragment.kt b/app/src/main/java/com/runnect/runnect/binding/BaseVisitorFragment.kt index db1bdad57..620dd389c 100644 --- a/app/src/main/java/com/runnect/runnect/binding/BaseVisitorFragment.kt +++ b/app/src/main/java/com/runnect/runnect/binding/BaseVisitorFragment.kt @@ -8,20 +8,23 @@ import androidx.annotation.LayoutRes import androidx.core.view.isVisible import androidx.databinding.ViewDataBinding import com.runnect.runnect.R -import com.runnect.runnect.presentation.MainActivity +import com.runnect.runnect.presentation.event.VisitorModeManager import com.runnect.runnect.presentation.login.LoginActivity +import javax.inject.Inject abstract class BaseVisitorFragment( @LayoutRes private val layoutRes: Int ) : BindingFragment(layoutRes) { - + @Inject + lateinit var visitorModeManager: VisitorModeManager + abstract val visitorContainer: View abstract val contentViews: List - + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - - if (MainActivity.isVisitorMode) { + + if (visitorModeManager.isVisitorMode) { showVisitorMode() } else { showContent() diff --git a/app/src/main/java/com/runnect/runnect/presentation/MainActivity.kt b/app/src/main/java/com/runnect/runnect/presentation/MainActivity.kt index 63aa4f3b8..6fad22d24 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/MainActivity.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/MainActivity.kt @@ -12,17 +12,18 @@ import com.runnect.runnect.BuildConfig.REMOTE_KEY_APP_VERSION import com.runnect.runnect.R import com.runnect.runnect.binding.BindingActivity import com.runnect.runnect.databinding.ActivityMainBinding -import com.runnect.runnect.presentation.discover.DiscoverFragment -import com.runnect.runnect.presentation.storage.StorageScrapFragment +import com.runnect.runnect.presentation.event.VisitorModeManager import com.runnect.runnect.util.analytics.Analytics import com.runnect.runnect.util.analytics.EventName import com.runnect.runnect.util.analytics.EventName.EVENT_VIEW_HOME -import com.runnect.runnect.util.preference.AuthUtil.getAccessToken -import com.runnect.runnect.util.preference.StatusType.LoginStatus import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint class MainActivity : BindingActivity(R.layout.activity_main) { + @Inject + lateinit var visitorModeManager: VisitorModeManager + private var isChangeToStorage: Boolean = false private var isChangeToDiscover: Boolean = false private var fragmentReplacementDirection: String? = null @@ -40,9 +41,7 @@ class MainActivity : BindingActivity(R.layout.activity_main } private fun checkVisitorMode() { - val accessToken = this.getAccessToken() - val loginStatus = LoginStatus.getLoginStatus(accessToken) - isVisitorMode = loginStatus == LoginStatus.VISITOR + // isVisitorMode is now managed by VisitorModeManager via Hilt } private fun checkIntentValue() { @@ -102,12 +101,13 @@ class MainActivity : BindingActivity(R.layout.activity_main } private fun logClickEvent(menuItemId: Int) { + val isVisitor = visitorModeManager.isVisitorMode with(EventName) { when (menuItemId) { - R.id.menu_main_drawing -> if (isVisitorMode) EVENT_CLICK_JOIN_IN_COURSE_DRAWING else EVENT_CLICK_NAV_COURSE_DRAWING - R.id.menu_main_storage -> if (isVisitorMode) EVENT_CLICK_JOIN_IN_STORAGE else EVENT_CLICK_NAV_STORAGE - R.id.menu_main_discover -> if (isVisitorMode) EVENT_CLICK_JOIN_IN_COURSE_DISCOVERY else EVENT_CLICK_NAV_COURSE_DISCOVERY - R.id.menu_main_my_page -> if (isVisitorMode) EVENT_CLICK_JOIN_IN_MY_PAGE else EVENT_CLICK_NAV_MY_PAGE + R.id.menu_main_drawing -> if (isVisitor) EVENT_CLICK_JOIN_IN_COURSE_DRAWING else EVENT_CLICK_NAV_COURSE_DRAWING + R.id.menu_main_storage -> if (isVisitor) EVENT_CLICK_JOIN_IN_STORAGE else EVENT_CLICK_NAV_STORAGE + R.id.menu_main_discover -> if (isVisitor) EVENT_CLICK_JOIN_IN_COURSE_DISCOVERY else EVENT_CLICK_NAV_COURSE_DISCOVERY + R.id.menu_main_my_page -> if (isVisitor) EVENT_CLICK_JOIN_IN_MY_PAGE else EVENT_CLICK_NAV_MY_PAGE else -> "" }.let(Analytics::logClickedItemEvent) } @@ -169,17 +169,5 @@ class MainActivity : BindingActivity(R.layout.activity_main companion object { const val REMOTE_CONFIG_FETCH_INTERVAL_SECONDS = 3600L const val EXTRA_FRAGMENT_REPLACEMENT_DIRECTION = "fragmentReplacementDirection" - - var isVisitorMode = false - var discoverFragment: DiscoverFragment? = null - var storageScrapFragment: StorageScrapFragment? = null - - fun updateCourseDiscoverScreen() { - discoverFragment?.refreshDiscoverCourses() - } - - fun updateStorageScrapScreen() { - storageScrapFragment?.getMyScrapCourses() - } } } diff --git a/app/src/main/java/com/runnect/runnect/presentation/MainPager.kt b/app/src/main/java/com/runnect/runnect/presentation/MainPager.kt index 04fef6695..4b6ad0f96 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/MainPager.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/MainPager.kt @@ -19,9 +19,7 @@ class MainPager(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragm when (position) { 0 -> CourseMainFragment() 1 -> StorageMainFragment() - 2 -> DiscoverFragment().apply { - MainActivity.discoverFragment = this - } + 2 -> DiscoverFragment() 3 -> MyPageFragment() else -> CourseMainFragment() diff --git a/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailActivity.kt b/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailActivity.kt index 314a5600e..cbf88c9a7 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailActivity.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailActivity.kt @@ -11,6 +11,7 @@ import android.widget.EditText import androidx.activity.OnBackPressedCallback import androidx.activity.viewModels import androidx.core.view.isVisible +import androidx.lifecycle.lifecycleScope import coil3.load import com.google.firebase.dynamiclinks.DynamicLink import com.google.firebase.dynamiclinks.FirebaseDynamicLinks @@ -23,6 +24,9 @@ import com.runnect.runnect.domain.entity.CourseDetail import com.runnect.runnect.domain.entity.EditableCourseDetail import com.runnect.runnect.presentation.MainActivity import com.runnect.runnect.presentation.countdown.CountDownActivity +import com.runnect.runnect.presentation.event.ScreenRefreshEvent +import com.runnect.runnect.presentation.event.ScreenRefreshEventBus +import com.runnect.runnect.presentation.event.VisitorModeManager import com.runnect.runnect.presentation.detail.CourseDetailRootScreen.COURSE_DISCOVER import com.runnect.runnect.presentation.detail.CourseDetailRootScreen.COURSE_DISCOVER_SEARCH import com.runnect.runnect.presentation.detail.CourseDetailRootScreen.COURSE_STORAGE_SCRAP @@ -56,12 +60,20 @@ import com.runnect.runnect.util.extension.showWebBrowser import com.runnect.runnect.util.mode.ScreenMode.EditMode import com.runnect.runnect.util.mode.ScreenMode.ReadOnlyMode import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch +import javax.inject.Inject @AndroidEntryPoint class CourseDetailActivity : BindingActivity(R.layout.activity_course_detail) { + @Inject + lateinit var visitorModeManager: VisitorModeManager + + @Inject + lateinit var screenRefreshEventBus: ScreenRefreshEventBus + private val viewModel: CourseDetailViewModel by viewModels() - private val isVisitorMode: Boolean = MainActivity.isVisitorMode + private val isVisitorMode: Boolean get() = visitorModeManager.isVisitorMode private var isFromDeepLink: Boolean = false // 인텐트 부가 데이터 @@ -385,7 +397,9 @@ class CourseDetailActivity : } when (rootScreen) { - COURSE_STORAGE_SCRAP -> MainActivity.updateStorageScrapScreen() + COURSE_STORAGE_SCRAP -> lifecycleScope.launch { + screenRefreshEventBus.emit(ScreenRefreshEvent.RefreshStorageScrap) + } COURSE_DISCOVER -> setActivityResult() COURSE_DISCOVER_SEARCH -> setActivityResult() MY_PAGE_UPLOAD_COURSE -> setActivityResult() diff --git a/app/src/main/java/com/runnect/runnect/presentation/discover/DiscoverFragment.kt b/app/src/main/java/com/runnect/runnect/presentation/discover/DiscoverFragment.kt index ccfdf6edb..1c2a1229d 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/discover/DiscoverFragment.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/discover/DiscoverFragment.kt @@ -18,8 +18,10 @@ import com.runnect.runnect.binding.BindingFragment import com.runnect.runnect.databinding.FragmentDiscoverBinding import com.runnect.runnect.domain.entity.DiscoverBanner import com.runnect.runnect.presentation.MainActivity -import com.runnect.runnect.presentation.MainActivity.Companion.isVisitorMode import com.runnect.runnect.presentation.detail.CourseDetailActivity +import com.runnect.runnect.presentation.event.ScreenRefreshEvent +import com.runnect.runnect.presentation.event.ScreenRefreshEventBus +import com.runnect.runnect.presentation.event.VisitorModeManager import com.runnect.runnect.presentation.detail.CourseDetailRootScreen import com.runnect.runnect.presentation.discover.adapter.BannerAdapter import com.runnect.runnect.presentation.discover.adapter.multiview.DiscoverMultiViewAdapter @@ -28,7 +30,6 @@ import com.runnect.runnect.presentation.discover.model.EditableDiscoverCourse import com.runnect.runnect.presentation.discover.pick.DiscoverPickActivity import com.runnect.runnect.presentation.discover.search.DiscoverSearchActivity import com.runnect.runnect.presentation.state.UiStateV2 -import com.runnect.runnect.presentation.storage.StorageScrapFragment import com.runnect.runnect.util.analytics.Analytics import com.runnect.runnect.util.analytics.EventName.EVENT_CLICK_DATE import com.runnect.runnect.util.analytics.EventName.EVENT_CLICK_SCRAP @@ -46,9 +47,16 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.launch import timber.log.Timber +import javax.inject.Inject @AndroidEntryPoint class DiscoverFragment : BindingFragment(R.layout.fragment_discover) { + @Inject + lateinit var visitorModeManager: VisitorModeManager + + @Inject + lateinit var screenRefreshEventBus: ScreenRefreshEventBus + private val viewModel: DiscoverViewModel by viewModels() private lateinit var bannerAdapter: BannerAdapter @@ -57,7 +65,6 @@ class DiscoverFragment : BindingFragment(R.layout.fragm private var bannerItemCount = 0 private lateinit var multiViewAdapter: DiscoverMultiViewAdapter - private var isFromStorageScrap = StorageScrapFragment.isFromStorageScrap private val resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> @@ -88,6 +95,17 @@ class DiscoverFragment : BindingFragment(R.layout.fragm addListener() addObserver() registerCallback() + collectScreenRefreshEvents() + } + + private fun collectScreenRefreshEvents() { + viewLifeCycleScope.launch { + screenRefreshEventBus.events.collect { event -> + if (event is ScreenRefreshEvent.RefreshDiscoverCourses) { + refreshDiscoverCourses() + } + } + } } private fun initView() { @@ -106,6 +124,7 @@ class DiscoverFragment : BindingFragment(R.layout.fragm handleVisitorMode = { context?.let { showCourseScrapWarningToast(it) } }, + isVisitorMode = { visitorModeManager.isVisitorMode }, onSortButtonClick = { criteria -> viewModel.sortRecommendCourses(criteria) Analytics.logClickedItemEvent(returnEventName(criteria)) @@ -277,7 +296,7 @@ class DiscoverFragment : BindingFragment(R.layout.fragm private fun navigateToCourseUploadScreen() { val context = context ?: return - if (isVisitorMode) { + if (visitorModeManager.isVisitorMode) { showCourseUploadWarningToast(context) return } @@ -491,10 +510,7 @@ class DiscoverFragment : BindingFragment(R.layout.fragm } private fun checkFromStorageScrap() { - if (isFromStorageScrap) { - StorageScrapFragment.isFromStorageScrap = false - MainActivity.updateStorageScrapScreen() - } + // No longer needed — screen refresh is handled via ScreenRefreshEventBus } private fun registerRefreshLayoutScrollUpCallback() { @@ -509,18 +525,6 @@ class DiscoverFragment : BindingFragment(R.layout.fragm return layoutManager.findFirstCompletelyVisibleItemPosition() > 0 } - override fun onAttach(context: Context) { - super.onAttach(context) - if (context is MainActivity) { - MainActivity.discoverFragment = this - } - } - - override fun onDestroy() { - super.onDestroy() - MainActivity.discoverFragment = null - } - companion object { private const val BANNER_SCROLL_DELAY_TIME = 5000L private const val CENTER_POS_OF_INFINITE_BANNERS = Int.MAX_VALUE / 2 diff --git a/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/DiscoverMarathonAdapter.kt b/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/DiscoverMarathonAdapter.kt index b0d4186b3..0204f9fb2 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/DiscoverMarathonAdapter.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/DiscoverMarathonAdapter.kt @@ -8,7 +8,6 @@ import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import com.runnect.runnect.databinding.ItemDiscoverMarathonBinding import com.runnect.runnect.domain.entity.DiscoverMultiViewItem -import com.runnect.runnect.presentation.MainActivity import com.runnect.runnect.presentation.discover.model.EditableDiscoverCourse import com.runnect.runnect.util.callback.diff.ItemDiffCallback @@ -16,6 +15,7 @@ class DiscoverMarathonAdapter( private val onHeartButtonClick: (Int, Boolean) -> Unit, private val onCourseItemClick: (Int) -> Unit, private val handleVisitorMode: () -> Unit, + private val isVisitorMode: () -> Boolean, ) : ListAdapter(diffUtil) { @@ -28,7 +28,8 @@ class DiscoverMarathonAdapter( ), onHeartButtonClick, onCourseItemClick, - handleVisitorMode + handleVisitorMode, + isVisitorMode ) } @@ -41,6 +42,7 @@ class DiscoverMarathonAdapter( private val onHeartButtonClick: (Int, Boolean) -> Unit, private val onCourseItemClick: (Int) -> Unit, private val handleVisitorMode: () -> Unit, + private val isVisitorMode: () -> Boolean, ) : RecyclerView.ViewHolder(binding.root) { fun bind(course: DiscoverMultiViewItem.MarathonCourse) { with(binding) { @@ -57,7 +59,7 @@ class DiscoverMarathonAdapter( course: DiscoverMultiViewItem.MarathonCourse ) { imageView.setOnClickListener { view -> - if (MainActivity.isVisitorMode) { + if (isVisitorMode()) { handleVisitorMode.invoke() return@setOnClickListener } diff --git a/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/DiscoverRecommendAdapter.kt b/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/DiscoverRecommendAdapter.kt index 99f5f836c..83463c29c 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/DiscoverRecommendAdapter.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/DiscoverRecommendAdapter.kt @@ -8,7 +8,6 @@ import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import com.runnect.runnect.databinding.ItemDiscoverRecommendBinding import com.runnect.runnect.domain.entity.DiscoverMultiViewItem -import com.runnect.runnect.presentation.MainActivity import com.runnect.runnect.presentation.discover.model.EditableDiscoverCourse import com.runnect.runnect.util.callback.diff.ItemDiffCallback import timber.log.Timber @@ -17,6 +16,7 @@ class DiscoverRecommendAdapter( private val onHeartButtonClick: (Int, Boolean) -> Unit, private val onCourseItemClick: (Int) -> Unit, private val handleVisitorMode: () -> Unit, + private val isVisitorMode: () -> Boolean, ) : ListAdapter(diffUtil) { @@ -29,7 +29,8 @@ class DiscoverRecommendAdapter( ), onHeartButtonClick, onCourseItemClick, - handleVisitorMode + handleVisitorMode, + isVisitorMode ) } @@ -41,7 +42,8 @@ class DiscoverRecommendAdapter( private val binding: ItemDiscoverRecommendBinding, private val onHeartButtonClick: (Int, Boolean) -> Unit, private val onCourseItemClick: (Int) -> Unit, - private val handleVisitorMode: () -> Unit + private val handleVisitorMode: () -> Unit, + private val isVisitorMode: () -> Boolean ) : RecyclerView.ViewHolder(binding.root) { fun bind(course: DiscoverMultiViewItem.RecommendCourse) { with(binding) { @@ -58,7 +60,7 @@ class DiscoverRecommendAdapter( course: DiscoverMultiViewItem.RecommendCourse ) { imageView.setOnClickListener { view -> - if (MainActivity.isVisitorMode) { + if (isVisitorMode()) { handleVisitorMode.invoke() return@setOnClickListener } diff --git a/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/multiview/DiscoverMultiViewAdapter.kt b/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/multiview/DiscoverMultiViewAdapter.kt index d4e52e6ff..b072087b6 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/multiview/DiscoverMultiViewAdapter.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/multiview/DiscoverMultiViewAdapter.kt @@ -10,6 +10,7 @@ class DiscoverMultiViewAdapter( private val onHeartButtonClick: (Int, Boolean) -> Unit, private val onCourseItemClick: (Int) -> Unit, private val handleVisitorMode: () -> Unit, + private val isVisitorMode: () -> Boolean, private val onSortButtonClick: (String) -> Unit ) : RecyclerView.Adapter() { private val multiViewHolderFactory by lazy { DiscoverMultiViewHolderFactory() } @@ -24,6 +25,7 @@ class DiscoverMultiViewAdapter( onHeartButtonClick = onHeartButtonClick, onCourseItemClick = onCourseItemClick, handleVisitorMode = handleVisitorMode, + isVisitorMode = isVisitorMode, onSortButtonClick = onSortButtonClick ) } diff --git a/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/multiview/DiscoverMultiViewHolder.kt b/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/multiview/DiscoverMultiViewHolder.kt index 5d480ce10..957122954 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/multiview/DiscoverMultiViewHolder.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/multiview/DiscoverMultiViewHolder.kt @@ -26,11 +26,12 @@ sealed class DiscoverMultiViewHolder(binding: ViewDataBinding) : private val binding: ItemDiscoverMultiviewMarathonBinding, onHeartButtonClick: (Int, Boolean) -> Unit, onCourseItemClick: (Int) -> Unit, - handleVisitorMode: () -> Unit + handleVisitorMode: () -> Unit, + isVisitorMode: () -> Boolean ) : DiscoverMultiViewHolder(binding) { val marathonAdapter by lazy { DiscoverMarathonAdapter( - onHeartButtonClick, onCourseItemClick, handleVisitorMode + onHeartButtonClick, onCourseItemClick, handleVisitorMode, isVisitorMode ) } @@ -69,13 +70,15 @@ sealed class DiscoverMultiViewHolder(binding: ViewDataBinding) : onHeartButtonClick: (Int, Boolean) -> Unit, onCourseItemClick: (Int) -> Unit, handleVisitorMode: () -> Unit, + isVisitorMode: () -> Boolean, private val onSortButtonClick: (String) -> Unit ) : DiscoverMultiViewHolder(binding) { val recommendAdapter by lazy { DiscoverRecommendAdapter( onHeartButtonClick, onCourseItemClick, - handleVisitorMode + handleVisitorMode, + isVisitorMode ) } diff --git a/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/multiview/DiscoverMultiViewHolderFactory.kt b/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/multiview/DiscoverMultiViewHolderFactory.kt index 60fb681bf..c4defbdbf 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/multiview/DiscoverMultiViewHolderFactory.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/multiview/DiscoverMultiViewHolderFactory.kt @@ -16,6 +16,7 @@ class DiscoverMultiViewHolderFactory { onHeartButtonClick: (Int, Boolean) -> Unit, onCourseItemClick: (Int) -> Unit, handleVisitorMode: () -> Unit, + isVisitorMode: () -> Boolean, onSortButtonClick: (String) -> Unit ): DiscoverMultiViewHolder { when (viewType) { @@ -24,7 +25,8 @@ class DiscoverMultiViewHolderFactory { binding = parent.getViewDataBinding(layoutRes = R.layout.item_discover_multiview_marathon), onHeartButtonClick = onHeartButtonClick, onCourseItemClick = onCourseItemClick, - handleVisitorMode = handleVisitorMode + handleVisitorMode = handleVisitorMode, + isVisitorMode = isVisitorMode ) marathonCourseAdapter = viewHolder.marathonAdapter return viewHolder @@ -36,6 +38,7 @@ class DiscoverMultiViewHolderFactory { onHeartButtonClick = onHeartButtonClick, onCourseItemClick = onCourseItemClick, handleVisitorMode = handleVisitorMode, + isVisitorMode = isVisitorMode, onSortButtonClick = onSortButtonClick ) recommendCourseAdapter = viewHolder.recommendAdapter diff --git a/app/src/main/java/com/runnect/runnect/presentation/discover/upload/DiscoverUploadActivity.kt b/app/src/main/java/com/runnect/runnect/presentation/discover/upload/DiscoverUploadActivity.kt index 7ac18237d..aee22f998 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/discover/upload/DiscoverUploadActivity.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/discover/upload/DiscoverUploadActivity.kt @@ -14,6 +14,8 @@ import com.runnect.runnect.databinding.ActivityDiscoverUploadBinding import com.runnect.runnect.domain.entity.DiscoverUploadCourse import com.runnect.runnect.presentation.MainActivity import com.runnect.runnect.presentation.discover.pick.DiscoverPickActivity +import com.runnect.runnect.presentation.event.ScreenRefreshEvent +import com.runnect.runnect.presentation.event.ScreenRefreshEventBus import com.runnect.runnect.presentation.state.UiState import com.runnect.runnect.util.analytics.Analytics import com.runnect.runnect.util.analytics.EventName.EVENT_CLICK_COURSE_UPLOAD @@ -23,11 +25,17 @@ import com.runnect.runnect.util.extension.getCompatibleParcelableExtra import com.runnect.runnect.util.extension.hideKeyboard import com.runnect.runnect.util.extension.showToast import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch +import androidx.lifecycle.lifecycleScope +import javax.inject.Inject import timber.log.Timber @AndroidEntryPoint class DiscoverUploadActivity : BindingActivity(R.layout.activity_discover_upload) { + @Inject + lateinit var screenRefreshEventBus: ScreenRefreshEventBus + private val viewModel: DiscoverUploadViewModel by viewModels() private val uploadCourse: DiscoverUploadCourse? by lazy { intent.getCompatibleParcelableExtra( @@ -113,7 +121,9 @@ class DiscoverUploadActivity : startActivity(this) } - MainActivity.updateCourseDiscoverScreen() + lifecycleScope.launch { + screenRefreshEventBus.emit(ScreenRefreshEvent.RefreshDiscoverCourses) + } applyScreenExitAnimation() } diff --git a/app/src/main/java/com/runnect/runnect/presentation/draw/DrawActivity.kt b/app/src/main/java/com/runnect/runnect/presentation/draw/DrawActivity.kt index b2a958d94..807b92229 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/draw/DrawActivity.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/draw/DrawActivity.kt @@ -44,6 +44,7 @@ import com.runnect.runnect.databinding.BottomsheetRequireCourseNameBinding import com.runnect.runnect.databinding.CustomDialogMakeCourseBinding import com.runnect.runnect.presentation.MainActivity import com.runnect.runnect.presentation.countdown.CountDownActivity +import com.runnect.runnect.presentation.event.VisitorModeManager import com.runnect.runnect.presentation.state.UiState import com.runnect.runnect.util.DepartureSetMode import com.runnect.runnect.util.analytics.Analytics @@ -55,6 +56,7 @@ import com.runnect.runnect.util.extension.setActivityDialog import com.runnect.runnect.util.extension.showToast import com.runnect.runnect.util.multipart.ContentUriRequestBody import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject import kotlinx.coroutines.delay import kotlinx.coroutines.launch import timber.log.Timber @@ -67,6 +69,9 @@ import java.math.RoundingMode @AndroidEntryPoint class DrawActivity : BindingActivity(R.layout.activity_draw), OnMapReadyCallback { + @Inject + lateinit var visitorModeManager: VisitorModeManager + private lateinit var locationSource: FusedLocationSource private lateinit var currentLocation: LatLng private lateinit var fusedLocation: FusedLocationProviderClient // 현재 위치 반환 객체 변수 @@ -95,7 +100,7 @@ class DrawActivity : BindingActivity(R.layout.activity_draw private var distanceSum: Float = 0.0f private var sumList = mutableListOf() private var isMarkerAvailable: Boolean = false - var isVisitorMode: Boolean = MainActivity.isVisitorMode + val isVisitorMode: Boolean get() = visitorModeManager.isVisitorMode var isFirstInit: Boolean = true diff --git a/app/src/main/java/com/runnect/runnect/presentation/event/ScreenRefreshEventBus.kt b/app/src/main/java/com/runnect/runnect/presentation/event/ScreenRefreshEventBus.kt new file mode 100644 index 000000000..8d627e300 --- /dev/null +++ b/app/src/main/java/com/runnect/runnect/presentation/event/ScreenRefreshEventBus.kt @@ -0,0 +1,22 @@ +package com.runnect.runnect.presentation.event + +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.asSharedFlow +import javax.inject.Inject +import javax.inject.Singleton + +sealed interface ScreenRefreshEvent { + data object RefreshDiscoverCourses : ScreenRefreshEvent + data object RefreshStorageScrap : ScreenRefreshEvent +} + +@Singleton +class ScreenRefreshEventBus @Inject constructor() { + private val _events = MutableSharedFlow() + val events: SharedFlow = _events.asSharedFlow() + + suspend fun emit(event: ScreenRefreshEvent) { + _events.emit(event) + } +} diff --git a/app/src/main/java/com/runnect/runnect/presentation/event/VisitorModeManager.kt b/app/src/main/java/com/runnect/runnect/presentation/event/VisitorModeManager.kt new file mode 100644 index 000000000..ff9f30107 --- /dev/null +++ b/app/src/main/java/com/runnect/runnect/presentation/event/VisitorModeManager.kt @@ -0,0 +1,19 @@ +package com.runnect.runnect.presentation.event + +import android.content.Context +import com.runnect.runnect.util.preference.AuthUtil.getAccessToken +import com.runnect.runnect.util.preference.StatusType.LoginStatus +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class VisitorModeManager @Inject constructor( + @ApplicationContext private val context: Context +) { + val isVisitorMode: Boolean + get() { + val accessToken = context.getAccessToken() + return LoginStatus.getLoginStatus(accessToken) == LoginStatus.VISITOR + } +} diff --git a/app/src/main/java/com/runnect/runnect/presentation/storage/StorageScrapFragment.kt b/app/src/main/java/com/runnect/runnect/presentation/storage/StorageScrapFragment.kt index de7288cfb..0e7704c47 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/storage/StorageScrapFragment.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/storage/StorageScrapFragment.kt @@ -1,12 +1,12 @@ package com.runnect.runnect.presentation.storage import android.content.ContentValues -import android.content.Context import android.content.Intent import android.os.Bundle import android.view.View import androidx.core.view.isVisible import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager import com.runnect.runnect.R import com.runnect.runnect.binding.BindingFragment @@ -14,6 +14,8 @@ import com.runnect.runnect.domain.entity.MyScrapCourse import com.runnect.runnect.databinding.FragmentStorageScrapBinding import com.runnect.runnect.presentation.MainActivity import com.runnect.runnect.presentation.detail.CourseDetailActivity +import com.runnect.runnect.presentation.event.ScreenRefreshEvent +import com.runnect.runnect.presentation.event.ScreenRefreshEventBus import com.runnect.runnect.presentation.detail.CourseDetailRootScreen import com.runnect.runnect.presentation.state.UiStateV2 import com.runnect.runnect.presentation.storage.adapter.StorageScrapAdapter @@ -23,7 +25,9 @@ import com.runnect.runnect.util.callback.listener.OnHeartButtonClick import com.runnect.runnect.util.callback.listener.OnScrapItemClick import com.runnect.runnect.util.extension.showSnackbar import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch import timber.log.Timber +import javax.inject.Inject @AndroidEntryPoint class StorageScrapFragment : @@ -31,6 +35,9 @@ class StorageScrapFragment : OnHeartButtonClick, OnScrapItemClick, ItemCount { + @Inject + lateinit var screenRefreshEventBus: ScreenRefreshEventBus + val viewModel: StorageViewModel by viewModels() private lateinit var storageScrapAdapter: StorageScrapAdapter @@ -43,6 +50,17 @@ class StorageScrapFragment : initAdapter() addListener() addObserver() + collectScreenRefreshEvents() + } + + private fun collectScreenRefreshEvents() { + viewLifecycleOwner.lifecycleScope.launch { + screenRefreshEventBus.events.collect { event -> + if (event is ScreenRefreshEvent.RefreshStorageScrap) { + getMyScrapCourses() + } + } + } } fun getMyScrapCourses() { @@ -81,8 +99,6 @@ class StorageScrapFragment : private fun initGoToScrapButtonClickListener() { binding.btnStorageNoScrap.setOnClickListener { - isFromStorageScrap = true - val intent = Intent(activity, MainActivity::class.java).apply { putExtra(EXTRA_FRAGMENT_REPLACEMENT_DIRECTION, "fromMyScrap") } @@ -205,20 +221,7 @@ class StorageScrapFragment : ) } - override fun onAttach(context: Context) { - super.onAttach(context) - if (context is MainActivity) { - MainActivity.storageScrapFragment = this - } - } - - override fun onDestroy() { - super.onDestroy() - MainActivity.storageScrapFragment = null - } - companion object { - var isFromStorageScrap = false const val EXTRA_FRAGMENT_REPLACEMENT_DIRECTION = "fragmentReplacementDirection" const val EXTRA_PUBLIC_COURSE_ID = "publicCourseId" const val EXTRA_ROOT_SCREEN = "rootScreen" From 1356ba1b2a23b51236267587fc3606590d31a588 Mon Sep 17 00:00:00 2001 From: unam98 Date: Fri, 3 Apr 2026 02:24:12 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=EB=A6=AC=EB=B7=B0=20=EB=B0=98?= =?UTF-8?q?=EC=98=81=20=E2=80=94=20dead=20code=20=EC=82=AD=EC=A0=9C,=20obs?= =?UTF-8?q?erver=20=EA=B7=B8=EB=A3=B9=ED=95=91,=20SharedFlow=20replay=3D1,?= =?UTF-8?q?=20emit=20=EC=88=9C=EC=84=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - checkVisitorMode() dead code 삭제 - collectScreenRefreshEvents()를 addObserver() 안으로 이동 - MutableSharedFlow(replay=1)로 이벤트 소실 방지 - DiscoverUploadActivity에서 emit을 startActivity 전으로 이동 --- .../runnect/presentation/MainActivity.kt | 5 ----- .../presentation/discover/DiscoverFragment.kt | 22 +++++++++---------- .../discover/upload/DiscoverUploadActivity.kt | 8 +++---- .../event/ScreenRefreshEventBus.kt | 2 +- .../storage/StorageScrapFragment.kt | 22 +++++++++---------- 5 files changed, 27 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/com/runnect/runnect/presentation/MainActivity.kt b/app/src/main/java/com/runnect/runnect/presentation/MainActivity.kt index 6fad22d24..54c3c8b3b 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/MainActivity.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/MainActivity.kt @@ -34,16 +34,11 @@ class MainActivity : BindingActivity(R.layout.activity_main Analytics.logClickedItemEvent(EVENT_VIEW_HOME) initRemoteConfig() - checkVisitorMode() checkIntentValue() initView() addListener() } - private fun checkVisitorMode() { - // isVisitorMode is now managed by VisitorModeManager via Hilt - } - private fun checkIntentValue() { fragmentReplacementDirection = intent.getStringExtra(EXTRA_FRAGMENT_REPLACEMENT_DIRECTION) diff --git a/app/src/main/java/com/runnect/runnect/presentation/discover/DiscoverFragment.kt b/app/src/main/java/com/runnect/runnect/presentation/discover/DiscoverFragment.kt index 1c2a1229d..2315051ff 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/discover/DiscoverFragment.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/discover/DiscoverFragment.kt @@ -95,17 +95,6 @@ class DiscoverFragment : BindingFragment(R.layout.fragm addListener() addObserver() registerCallback() - collectScreenRefreshEvents() - } - - private fun collectScreenRefreshEvents() { - viewLifeCycleScope.launch { - screenRefreshEventBus.events.collect { event -> - if (event is ScreenRefreshEvent.RefreshDiscoverCourses) { - refreshDiscoverCourses() - } - } - } } private fun initView() { @@ -319,6 +308,17 @@ class DiscoverFragment : BindingFragment(R.layout.fragm setupRecommendCourseNextPageStateObserver() setupRecommendCourseSortStateObserver() setupCourseScrapStateObserver() + collectScreenRefreshEvents() + } + + private fun collectScreenRefreshEvents() { + viewLifeCycleScope.launch { + screenRefreshEventBus.events.collect { event -> + if (event is ScreenRefreshEvent.RefreshDiscoverCourses) { + refreshDiscoverCourses() + } + } + } } private fun setupBannerGetStateObserver() { diff --git a/app/src/main/java/com/runnect/runnect/presentation/discover/upload/DiscoverUploadActivity.kt b/app/src/main/java/com/runnect/runnect/presentation/discover/upload/DiscoverUploadActivity.kt index aee22f998..6d01f379d 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/discover/upload/DiscoverUploadActivity.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/discover/upload/DiscoverUploadActivity.kt @@ -116,14 +116,14 @@ class DiscoverUploadActivity : showToast("업로드 완료!") binding.indeterminateBar.isVisible = false + lifecycleScope.launch { + screenRefreshEventBus.emit(ScreenRefreshEvent.RefreshDiscoverCourses) + } + Intent(this, MainActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP) startActivity(this) } - - lifecycleScope.launch { - screenRefreshEventBus.emit(ScreenRefreshEvent.RefreshDiscoverCourses) - } applyScreenExitAnimation() } diff --git a/app/src/main/java/com/runnect/runnect/presentation/event/ScreenRefreshEventBus.kt b/app/src/main/java/com/runnect/runnect/presentation/event/ScreenRefreshEventBus.kt index 8d627e300..64136421d 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/event/ScreenRefreshEventBus.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/event/ScreenRefreshEventBus.kt @@ -13,7 +13,7 @@ sealed interface ScreenRefreshEvent { @Singleton class ScreenRefreshEventBus @Inject constructor() { - private val _events = MutableSharedFlow() + private val _events = MutableSharedFlow(replay = 1) val events: SharedFlow = _events.asSharedFlow() suspend fun emit(event: ScreenRefreshEvent) { diff --git a/app/src/main/java/com/runnect/runnect/presentation/storage/StorageScrapFragment.kt b/app/src/main/java/com/runnect/runnect/presentation/storage/StorageScrapFragment.kt index 0e7704c47..ae50ca65b 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/storage/StorageScrapFragment.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/storage/StorageScrapFragment.kt @@ -50,17 +50,6 @@ class StorageScrapFragment : initAdapter() addListener() addObserver() - collectScreenRefreshEvents() - } - - private fun collectScreenRefreshEvents() { - viewLifecycleOwner.lifecycleScope.launch { - screenRefreshEventBus.events.collect { event -> - if (event is ScreenRefreshEvent.RefreshStorageScrap) { - getMyScrapCourses() - } - } - } } fun getMyScrapCourses() { @@ -121,6 +110,17 @@ class StorageScrapFragment : setupItemSizeObserver() setupMyScrapCourseGetStateObserver() setupCourseScrapStateObserver() + collectScreenRefreshEvents() + } + + private fun collectScreenRefreshEvents() { + viewLifecycleOwner.lifecycleScope.launch { + screenRefreshEventBus.events.collect { event -> + if (event is ScreenRefreshEvent.RefreshStorageScrap) { + getMyScrapCourses() + } + } + } } private fun setupCourseScrapStateObserver() {