Skip to content

Commit 65ee4fc

Browse files
committed
refactor: MainActivity companion object 안티패턴 제거, 화면 간 통신을 SharedFlow 이벤트 버스로 전환
- ScreenRefreshEventBus 도입: Fragment 직접 참조 대신 SharedFlow 기반 이벤트 통신 - VisitorModeManager 도입: static mutable 변수 대신 Hilt Singleton으로 방문자 모드 관리 - MainActivity.companion에서 Fragment 인스턴스 참조, isVisitorMode, updateXxxScreen() 제거 - DiscoverFragment/StorageScrapFragment의 self-registration(onAttach/onDestroy) 제거 - Adapter에 isVisitorMode 람다 파라미터 전달로 정적 참조 제거
1 parent f6db01e commit 65ee4fc

15 files changed

Lines changed: 160 additions & 82 deletions

app/src/main/java/com/runnect/runnect/binding/BaseVisitorFragment.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,23 @@ import androidx.annotation.LayoutRes
88
import androidx.core.view.isVisible
99
import androidx.databinding.ViewDataBinding
1010
import com.runnect.runnect.R
11-
import com.runnect.runnect.presentation.MainActivity
11+
import com.runnect.runnect.presentation.event.VisitorModeManager
1212
import com.runnect.runnect.presentation.login.LoginActivity
13+
import javax.inject.Inject
1314

1415
abstract class BaseVisitorFragment<T : ViewDataBinding>(
1516
@LayoutRes private val layoutRes: Int
1617
) : BindingFragment<T>(layoutRes) {
17-
18+
@Inject
19+
lateinit var visitorModeManager: VisitorModeManager
20+
1821
abstract val visitorContainer: View
1922
abstract val contentViews: List<View>
20-
23+
2124
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
2225
super.onViewCreated(view, savedInstanceState)
23-
24-
if (MainActivity.isVisitorMode) {
26+
27+
if (visitorModeManager.isVisitorMode) {
2528
showVisitorMode()
2629
} else {
2730
showContent()

app/src/main/java/com/runnect/runnect/presentation/MainActivity.kt

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,18 @@ import com.runnect.runnect.BuildConfig.REMOTE_KEY_APP_VERSION
1212
import com.runnect.runnect.R
1313
import com.runnect.runnect.binding.BindingActivity
1414
import com.runnect.runnect.databinding.ActivityMainBinding
15-
import com.runnect.runnect.presentation.discover.DiscoverFragment
16-
import com.runnect.runnect.presentation.storage.StorageScrapFragment
15+
import com.runnect.runnect.presentation.event.VisitorModeManager
1716
import com.runnect.runnect.util.analytics.Analytics
1817
import com.runnect.runnect.util.analytics.EventName
1918
import com.runnect.runnect.util.analytics.EventName.EVENT_VIEW_HOME
20-
import com.runnect.runnect.util.preference.AuthUtil.getAccessToken
21-
import com.runnect.runnect.util.preference.StatusType.LoginStatus
2219
import dagger.hilt.android.AndroidEntryPoint
20+
import javax.inject.Inject
2321

2422
@AndroidEntryPoint
2523
class MainActivity : BindingActivity<ActivityMainBinding>(R.layout.activity_main) {
24+
@Inject
25+
lateinit var visitorModeManager: VisitorModeManager
26+
2627
private var isChangeToStorage: Boolean = false
2728
private var isChangeToDiscover: Boolean = false
2829
private var fragmentReplacementDirection: String? = null
@@ -40,9 +41,7 @@ class MainActivity : BindingActivity<ActivityMainBinding>(R.layout.activity_main
4041
}
4142

4243
private fun checkVisitorMode() {
43-
val accessToken = this.getAccessToken()
44-
val loginStatus = LoginStatus.getLoginStatus(accessToken)
45-
isVisitorMode = loginStatus == LoginStatus.VISITOR
44+
// isVisitorMode is now managed by VisitorModeManager via Hilt
4645
}
4746

4847
private fun checkIntentValue() {
@@ -102,12 +101,13 @@ class MainActivity : BindingActivity<ActivityMainBinding>(R.layout.activity_main
102101
}
103102

104103
private fun logClickEvent(menuItemId: Int) {
104+
val isVisitor = visitorModeManager.isVisitorMode
105105
with(EventName) {
106106
when (menuItemId) {
107-
R.id.menu_main_drawing -> if (isVisitorMode) EVENT_CLICK_JOIN_IN_COURSE_DRAWING else EVENT_CLICK_NAV_COURSE_DRAWING
108-
R.id.menu_main_storage -> if (isVisitorMode) EVENT_CLICK_JOIN_IN_STORAGE else EVENT_CLICK_NAV_STORAGE
109-
R.id.menu_main_discover -> if (isVisitorMode) EVENT_CLICK_JOIN_IN_COURSE_DISCOVERY else EVENT_CLICK_NAV_COURSE_DISCOVERY
110-
R.id.menu_main_my_page -> if (isVisitorMode) EVENT_CLICK_JOIN_IN_MY_PAGE else EVENT_CLICK_NAV_MY_PAGE
107+
R.id.menu_main_drawing -> if (isVisitor) EVENT_CLICK_JOIN_IN_COURSE_DRAWING else EVENT_CLICK_NAV_COURSE_DRAWING
108+
R.id.menu_main_storage -> if (isVisitor) EVENT_CLICK_JOIN_IN_STORAGE else EVENT_CLICK_NAV_STORAGE
109+
R.id.menu_main_discover -> if (isVisitor) EVENT_CLICK_JOIN_IN_COURSE_DISCOVERY else EVENT_CLICK_NAV_COURSE_DISCOVERY
110+
R.id.menu_main_my_page -> if (isVisitor) EVENT_CLICK_JOIN_IN_MY_PAGE else EVENT_CLICK_NAV_MY_PAGE
111111
else -> ""
112112
}.let(Analytics::logClickedItemEvent)
113113
}
@@ -169,17 +169,5 @@ class MainActivity : BindingActivity<ActivityMainBinding>(R.layout.activity_main
169169
companion object {
170170
const val REMOTE_CONFIG_FETCH_INTERVAL_SECONDS = 3600L
171171
const val EXTRA_FRAGMENT_REPLACEMENT_DIRECTION = "fragmentReplacementDirection"
172-
173-
var isVisitorMode = false
174-
var discoverFragment: DiscoverFragment? = null
175-
var storageScrapFragment: StorageScrapFragment? = null
176-
177-
fun updateCourseDiscoverScreen() {
178-
discoverFragment?.refreshDiscoverCourses()
179-
}
180-
181-
fun updateStorageScrapScreen() {
182-
storageScrapFragment?.getMyScrapCourses()
183-
}
184172
}
185173
}

app/src/main/java/com/runnect/runnect/presentation/MainPager.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ class MainPager(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragm
1919
when (position) {
2020
0 -> CourseMainFragment()
2121
1 -> StorageMainFragment()
22-
2 -> DiscoverFragment().apply {
23-
MainActivity.discoverFragment = this
24-
}
22+
2 -> DiscoverFragment()
2523

2624
3 -> MyPageFragment()
2725
else -> CourseMainFragment()

app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailActivity.kt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import android.widget.EditText
1111
import androidx.activity.OnBackPressedCallback
1212
import androidx.activity.viewModels
1313
import androidx.core.view.isVisible
14+
import androidx.lifecycle.lifecycleScope
1415
import coil3.load
1516
import com.google.firebase.dynamiclinks.DynamicLink
1617
import com.google.firebase.dynamiclinks.FirebaseDynamicLinks
@@ -23,6 +24,9 @@ import com.runnect.runnect.domain.entity.CourseDetail
2324
import com.runnect.runnect.domain.entity.EditableCourseDetail
2425
import com.runnect.runnect.presentation.MainActivity
2526
import com.runnect.runnect.presentation.countdown.CountDownActivity
27+
import com.runnect.runnect.presentation.event.ScreenRefreshEvent
28+
import com.runnect.runnect.presentation.event.ScreenRefreshEventBus
29+
import com.runnect.runnect.presentation.event.VisitorModeManager
2630
import com.runnect.runnect.presentation.detail.CourseDetailRootScreen.COURSE_DISCOVER
2731
import com.runnect.runnect.presentation.detail.CourseDetailRootScreen.COURSE_DISCOVER_SEARCH
2832
import com.runnect.runnect.presentation.detail.CourseDetailRootScreen.COURSE_STORAGE_SCRAP
@@ -56,12 +60,20 @@ import com.runnect.runnect.util.extension.showWebBrowser
5660
import com.runnect.runnect.util.mode.ScreenMode.EditMode
5761
import com.runnect.runnect.util.mode.ScreenMode.ReadOnlyMode
5862
import dagger.hilt.android.AndroidEntryPoint
63+
import kotlinx.coroutines.launch
64+
import javax.inject.Inject
5965

6066
@AndroidEntryPoint
6167
class CourseDetailActivity :
6268
BindingActivity<ActivityCourseDetailBinding>(R.layout.activity_course_detail) {
69+
@Inject
70+
lateinit var visitorModeManager: VisitorModeManager
71+
72+
@Inject
73+
lateinit var screenRefreshEventBus: ScreenRefreshEventBus
74+
6375
private val viewModel: CourseDetailViewModel by viewModels()
64-
private val isVisitorMode: Boolean = MainActivity.isVisitorMode
76+
private val isVisitorMode: Boolean get() = visitorModeManager.isVisitorMode
6577
private var isFromDeepLink: Boolean = false
6678

6779
// 인텐트 부가 데이터
@@ -385,7 +397,9 @@ class CourseDetailActivity :
385397
}
386398

387399
when (rootScreen) {
388-
COURSE_STORAGE_SCRAP -> MainActivity.updateStorageScrapScreen()
400+
COURSE_STORAGE_SCRAP -> lifecycleScope.launch {
401+
screenRefreshEventBus.emit(ScreenRefreshEvent.RefreshStorageScrap)
402+
}
389403
COURSE_DISCOVER -> setActivityResult<MainActivity>()
390404
COURSE_DISCOVER_SEARCH -> setActivityResult<DiscoverSearchActivity>()
391405
MY_PAGE_UPLOAD_COURSE -> setActivityResult<MyUploadActivity>()

app/src/main/java/com/runnect/runnect/presentation/discover/DiscoverFragment.kt

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ import com.runnect.runnect.binding.BindingFragment
1818
import com.runnect.runnect.databinding.FragmentDiscoverBinding
1919
import com.runnect.runnect.domain.entity.DiscoverBanner
2020
import com.runnect.runnect.presentation.MainActivity
21-
import com.runnect.runnect.presentation.MainActivity.Companion.isVisitorMode
2221
import com.runnect.runnect.presentation.detail.CourseDetailActivity
22+
import com.runnect.runnect.presentation.event.ScreenRefreshEvent
23+
import com.runnect.runnect.presentation.event.ScreenRefreshEventBus
24+
import com.runnect.runnect.presentation.event.VisitorModeManager
2325
import com.runnect.runnect.presentation.detail.CourseDetailRootScreen
2426
import com.runnect.runnect.presentation.discover.adapter.BannerAdapter
2527
import com.runnect.runnect.presentation.discover.adapter.multiview.DiscoverMultiViewAdapter
@@ -28,7 +30,6 @@ import com.runnect.runnect.presentation.discover.model.EditableDiscoverCourse
2830
import com.runnect.runnect.presentation.discover.pick.DiscoverPickActivity
2931
import com.runnect.runnect.presentation.discover.search.DiscoverSearchActivity
3032
import com.runnect.runnect.presentation.state.UiStateV2
31-
import com.runnect.runnect.presentation.storage.StorageScrapFragment
3233
import com.runnect.runnect.util.analytics.Analytics
3334
import com.runnect.runnect.util.analytics.EventName.EVENT_CLICK_DATE
3435
import com.runnect.runnect.util.analytics.EventName.EVENT_CLICK_SCRAP
@@ -46,9 +47,16 @@ import kotlinx.coroutines.Job
4647
import kotlinx.coroutines.delay
4748
import kotlinx.coroutines.launch
4849
import timber.log.Timber
50+
import javax.inject.Inject
4951

5052
@AndroidEntryPoint
5153
class DiscoverFragment : BindingFragment<FragmentDiscoverBinding>(R.layout.fragment_discover) {
54+
@Inject
55+
lateinit var visitorModeManager: VisitorModeManager
56+
57+
@Inject
58+
lateinit var screenRefreshEventBus: ScreenRefreshEventBus
59+
5260
private val viewModel: DiscoverViewModel by viewModels()
5361

5462
private lateinit var bannerAdapter: BannerAdapter
@@ -57,7 +65,6 @@ class DiscoverFragment : BindingFragment<FragmentDiscoverBinding>(R.layout.fragm
5765
private var bannerItemCount = 0
5866

5967
private lateinit var multiViewAdapter: DiscoverMultiViewAdapter
60-
private var isFromStorageScrap = StorageScrapFragment.isFromStorageScrap
6168

6269
private val resultLauncher =
6370
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
@@ -88,6 +95,17 @@ class DiscoverFragment : BindingFragment<FragmentDiscoverBinding>(R.layout.fragm
8895
addListener()
8996
addObserver()
9097
registerCallback()
98+
collectScreenRefreshEvents()
99+
}
100+
101+
private fun collectScreenRefreshEvents() {
102+
viewLifeCycleScope.launch {
103+
screenRefreshEventBus.events.collect { event ->
104+
if (event is ScreenRefreshEvent.RefreshDiscoverCourses) {
105+
refreshDiscoverCourses()
106+
}
107+
}
108+
}
91109
}
92110

93111
private fun initView() {
@@ -106,6 +124,7 @@ class DiscoverFragment : BindingFragment<FragmentDiscoverBinding>(R.layout.fragm
106124
handleVisitorMode = {
107125
context?.let { showCourseScrapWarningToast(it) }
108126
},
127+
isVisitorMode = { visitorModeManager.isVisitorMode },
109128
onSortButtonClick = { criteria ->
110129
viewModel.sortRecommendCourses(criteria)
111130
Analytics.logClickedItemEvent(returnEventName(criteria))
@@ -277,7 +296,7 @@ class DiscoverFragment : BindingFragment<FragmentDiscoverBinding>(R.layout.fragm
277296

278297
private fun navigateToCourseUploadScreen() {
279298
val context = context ?: return
280-
if (isVisitorMode) {
299+
if (visitorModeManager.isVisitorMode) {
281300
showCourseUploadWarningToast(context)
282301
return
283302
}
@@ -491,10 +510,7 @@ class DiscoverFragment : BindingFragment<FragmentDiscoverBinding>(R.layout.fragm
491510
}
492511

493512
private fun checkFromStorageScrap() {
494-
if (isFromStorageScrap) {
495-
StorageScrapFragment.isFromStorageScrap = false
496-
MainActivity.updateStorageScrapScreen()
497-
}
513+
// No longer needed — screen refresh is handled via ScreenRefreshEventBus
498514
}
499515

500516
private fun registerRefreshLayoutScrollUpCallback() {
@@ -509,18 +525,6 @@ class DiscoverFragment : BindingFragment<FragmentDiscoverBinding>(R.layout.fragm
509525
return layoutManager.findFirstCompletelyVisibleItemPosition() > 0
510526
}
511527

512-
override fun onAttach(context: Context) {
513-
super.onAttach(context)
514-
if (context is MainActivity) {
515-
MainActivity.discoverFragment = this
516-
}
517-
}
518-
519-
override fun onDestroy() {
520-
super.onDestroy()
521-
MainActivity.discoverFragment = null
522-
}
523-
524528
companion object {
525529
private const val BANNER_SCROLL_DELAY_TIME = 5000L
526530
private const val CENTER_POS_OF_INFINITE_BANNERS = Int.MAX_VALUE / 2

app/src/main/java/com/runnect/runnect/presentation/discover/adapter/DiscoverMarathonAdapter.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ import androidx.recyclerview.widget.ListAdapter
88
import androidx.recyclerview.widget.RecyclerView
99
import com.runnect.runnect.databinding.ItemDiscoverMarathonBinding
1010
import com.runnect.runnect.domain.entity.DiscoverMultiViewItem
11-
import com.runnect.runnect.presentation.MainActivity
1211
import com.runnect.runnect.presentation.discover.model.EditableDiscoverCourse
1312
import com.runnect.runnect.util.callback.diff.ItemDiffCallback
1413

1514
class DiscoverMarathonAdapter(
1615
private val onHeartButtonClick: (Int, Boolean) -> Unit,
1716
private val onCourseItemClick: (Int) -> Unit,
1817
private val handleVisitorMode: () -> Unit,
18+
private val isVisitorMode: () -> Boolean,
1919
) : ListAdapter<DiscoverMultiViewItem.MarathonCourse,
2020
DiscoverMarathonAdapter.DiscoverMarathonViewHolder>(diffUtil) {
2121

@@ -28,7 +28,8 @@ class DiscoverMarathonAdapter(
2828
),
2929
onHeartButtonClick,
3030
onCourseItemClick,
31-
handleVisitorMode
31+
handleVisitorMode,
32+
isVisitorMode
3233
)
3334
}
3435

@@ -41,6 +42,7 @@ class DiscoverMarathonAdapter(
4142
private val onHeartButtonClick: (Int, Boolean) -> Unit,
4243
private val onCourseItemClick: (Int) -> Unit,
4344
private val handleVisitorMode: () -> Unit,
45+
private val isVisitorMode: () -> Boolean,
4446
) : RecyclerView.ViewHolder(binding.root) {
4547
fun bind(course: DiscoverMultiViewItem.MarathonCourse) {
4648
with(binding) {
@@ -57,7 +59,7 @@ class DiscoverMarathonAdapter(
5759
course: DiscoverMultiViewItem.MarathonCourse
5860
) {
5961
imageView.setOnClickListener { view ->
60-
if (MainActivity.isVisitorMode) {
62+
if (isVisitorMode()) {
6163
handleVisitorMode.invoke()
6264
return@setOnClickListener
6365
}

app/src/main/java/com/runnect/runnect/presentation/discover/adapter/DiscoverRecommendAdapter.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import androidx.recyclerview.widget.ListAdapter
88
import androidx.recyclerview.widget.RecyclerView
99
import com.runnect.runnect.databinding.ItemDiscoverRecommendBinding
1010
import com.runnect.runnect.domain.entity.DiscoverMultiViewItem
11-
import com.runnect.runnect.presentation.MainActivity
1211
import com.runnect.runnect.presentation.discover.model.EditableDiscoverCourse
1312
import com.runnect.runnect.util.callback.diff.ItemDiffCallback
1413
import timber.log.Timber
@@ -17,6 +16,7 @@ class DiscoverRecommendAdapter(
1716
private val onHeartButtonClick: (Int, Boolean) -> Unit,
1817
private val onCourseItemClick: (Int) -> Unit,
1918
private val handleVisitorMode: () -> Unit,
19+
private val isVisitorMode: () -> Boolean,
2020
) : ListAdapter<DiscoverMultiViewItem.RecommendCourse,
2121
DiscoverRecommendAdapter.DiscoverRecommendViewHolder>(diffUtil) {
2222

@@ -29,7 +29,8 @@ class DiscoverRecommendAdapter(
2929
),
3030
onHeartButtonClick,
3131
onCourseItemClick,
32-
handleVisitorMode
32+
handleVisitorMode,
33+
isVisitorMode
3334
)
3435
}
3536

@@ -41,7 +42,8 @@ class DiscoverRecommendAdapter(
4142
private val binding: ItemDiscoverRecommendBinding,
4243
private val onHeartButtonClick: (Int, Boolean) -> Unit,
4344
private val onCourseItemClick: (Int) -> Unit,
44-
private val handleVisitorMode: () -> Unit
45+
private val handleVisitorMode: () -> Unit,
46+
private val isVisitorMode: () -> Boolean
4547
) : RecyclerView.ViewHolder(binding.root) {
4648
fun bind(course: DiscoverMultiViewItem.RecommendCourse) {
4749
with(binding) {
@@ -58,7 +60,7 @@ class DiscoverRecommendAdapter(
5860
course: DiscoverMultiViewItem.RecommendCourse
5961
) {
6062
imageView.setOnClickListener { view ->
61-
if (MainActivity.isVisitorMode) {
63+
if (isVisitorMode()) {
6264
handleVisitorMode.invoke()
6365
return@setOnClickListener
6466
}

app/src/main/java/com/runnect/runnect/presentation/discover/adapter/multiview/DiscoverMultiViewAdapter.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class DiscoverMultiViewAdapter(
1010
private val onHeartButtonClick: (Int, Boolean) -> Unit,
1111
private val onCourseItemClick: (Int) -> Unit,
1212
private val handleVisitorMode: () -> Unit,
13+
private val isVisitorMode: () -> Boolean,
1314
private val onSortButtonClick: (String) -> Unit
1415
) : RecyclerView.Adapter<DiscoverMultiViewHolder>() {
1516
private val multiViewHolderFactory by lazy { DiscoverMultiViewHolderFactory() }
@@ -24,6 +25,7 @@ class DiscoverMultiViewAdapter(
2425
onHeartButtonClick = onHeartButtonClick,
2526
onCourseItemClick = onCourseItemClick,
2627
handleVisitorMode = handleVisitorMode,
28+
isVisitorMode = isVisitorMode,
2729
onSortButtonClick = onSortButtonClick
2830
)
2931
}

0 commit comments

Comments
 (0)