From 95e1da5b2069f91e6bdf6fd9c33e44c8ab6c93ef Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 16:43:55 +0900 Subject: [PATCH 01/23] =?UTF-8?q?refactor:=20IntroActivity=20=EC=83=88?= =?UTF-8?q?=EB=A1=9C=EC=9A=B4=20Intent=20=EA=B5=AC=EC=A1=B0=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../alarm/EatSsuFirebaseMessagingService.kt | 4 +- .../android/alarm/NotificationReceiver.kt | 8 +++- .../presentation/base/ActivityCompanion.kt | 39 +++++++++++++++++++ .../presentation/intro/IntroActivity.kt | 17 ++++---- .../presentation/widget/ui/MealWidget.kt | 8 +++- .../presentation/widget/util/launchApp.kt | 15 ------- 6 files changed, 62 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt delete mode 100644 app/src/main/java/com/eatssu/android/presentation/widget/util/launchApp.kt diff --git a/app/src/main/java/com/eatssu/android/alarm/EatSsuFirebaseMessagingService.kt b/app/src/main/java/com/eatssu/android/alarm/EatSsuFirebaseMessagingService.kt index e973b2ea5..6a5f05e8a 100644 --- a/app/src/main/java/com/eatssu/android/alarm/EatSsuFirebaseMessagingService.kt +++ b/app/src/main/java/com/eatssu/android/alarm/EatSsuFirebaseMessagingService.kt @@ -7,6 +7,7 @@ import android.content.Intent import androidx.core.app.NotificationCompat import com.eatssu.android.R import com.eatssu.android.presentation.intro.IntroActivity +import com.eatssu.common.enums.LaunchPath.REMOTE_NOTIFICATION import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage import timber.log.Timber @@ -44,8 +45,7 @@ class EatSsuFirebaseMessagingService : FirebaseMessagingService() { } notificationManager.createNotificationChannel(channel) - val intent = Intent(this, IntroActivity::class.java).apply { - putExtra("launch_path", "remote_notification") + val intent = IntroActivity.intent(this, IntroActivity.IntentOptions(REMOTE_NOTIFICATION)) { flags = Intent.FLAG_ACTIVITY_CLEAR_TOP } diff --git a/app/src/main/java/com/eatssu/android/alarm/NotificationReceiver.kt b/app/src/main/java/com/eatssu/android/alarm/NotificationReceiver.kt index d153249fa..2af8e239e 100644 --- a/app/src/main/java/com/eatssu/android/alarm/NotificationReceiver.kt +++ b/app/src/main/java/com/eatssu/android/alarm/NotificationReceiver.kt @@ -9,6 +9,7 @@ import android.content.Intent import androidx.core.app.NotificationCompat import com.eatssu.android.R import com.eatssu.android.presentation.intro.IntroActivity +import com.eatssu.common.enums.LaunchPath import java.time.DayOfWeek import java.time.LocalDateTime @@ -39,14 +40,17 @@ class NotificationReceiver : BroadcastReceiver() { notificationManager.createNotificationChannel(channel) - val intent = Intent(context, IntroActivity::class.java).apply { + val intent = IntroActivity.intent( + context, + IntroActivity.IntentOptions(LaunchPath.LOCAL_NOTIFICATION) + ) { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } val pendingIntent = PendingIntent.getActivity( context, 0, - intent.putExtra("launch_path", "local_notification"), + intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) diff --git a/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt b/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt new file mode 100644 index 000000000..70a0c5d56 --- /dev/null +++ b/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt @@ -0,0 +1,39 @@ +package com.eatssu.android.presentation.base + +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.os.Build +import android.os.Parcelable +import kotlin.reflect.KClass + +abstract class ActivityCompanion( + private val activityClass: KClass, + private val optionsClass: KClass +) where IntentOptions : Parcelable { + companion object { + private const val INTENT_OPTIONS_KEY = "intent_options" + } + + fun intent( + context: Context, + options: IntentOptions, + intentBuilder: Intent.() -> Unit = {} + ): Intent = + Intent(context, activityClass.java).apply { + putExtra(INTENT_OPTIONS_KEY, options) + intentBuilder() + } + + fun start(context: Context, options: IntentOptions, intentBuilder: Intent.() -> Unit = {}) { + context.startActivity(intent(context, options, intentBuilder)) + } + + val Activity.intentOptions: IntentOptions? + get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + this.intent.getParcelableExtra(INTENT_OPTIONS_KEY, optionsClass.java) + } else { + @Suppress("DEPRECATION") + this.intent.getParcelableExtra(INTENT_OPTIONS_KEY) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/presentation/intro/IntroActivity.kt b/app/src/main/java/com/eatssu/android/presentation/intro/IntroActivity.kt index e4d40fc4f..f3471a012 100644 --- a/app/src/main/java/com/eatssu/android/presentation/intro/IntroActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/intro/IntroActivity.kt @@ -1,6 +1,7 @@ package com.eatssu.android.presentation.intro import android.os.Bundle +import android.os.Parcelable import androidx.activity.enableEdgeToEdge import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity @@ -9,6 +10,7 @@ import com.eatssu.android.databinding.ActivityIntroBinding import com.eatssu.android.presentation.MainActivity import com.eatssu.android.presentation.UiEvent import com.eatssu.android.presentation.UiState +import com.eatssu.android.presentation.base.ActivityCompanion import com.eatssu.android.presentation.login.LoginActivity import com.eatssu.android.presentation.util.showToast import com.eatssu.android.presentation.util.startActivity @@ -18,10 +20,15 @@ import com.eatssu.common.enums.ScreenId import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import kotlinx.parcelize.Parcelize @AndroidEntryPoint class IntroActivity : AppCompatActivity() { + @Parcelize + data class IntentOptions(val launchPath: LaunchPath) : Parcelable + companion object : ActivityCompanion(IntroActivity::class, IntentOptions::class) + private val introViewModel: IntroViewModel by viewModels() private lateinit var binding: ActivityIntroBinding @@ -62,14 +69,8 @@ class IntroActivity : AppCompatActivity() { } private fun log() { - val launchPath = intent.getStringExtra("launch_path") - when (launchPath) { - "widget" -> EventLogger.appLaunch(LaunchPath.WIDGET) - "local_notification" -> EventLogger.appLaunch(LaunchPath.LOCAL_NOTIFICATION) - "remote_notification" -> EventLogger.appLaunch(LaunchPath.REMOTE_NOTIFICATION) - // launch_path가 없으면 일반적인 앱 아이콘 클릭으로 간주 - else -> EventLogger.appLaunch(LaunchPath.ICON) - } + val launchPath = intentOptions?.launchPath ?: LaunchPath.ICON + EventLogger.appLaunch(launchPath) } override fun onResume() { diff --git a/app/src/main/java/com/eatssu/android/presentation/widget/ui/MealWidget.kt b/app/src/main/java/com/eatssu/android/presentation/widget/ui/MealWidget.kt index 0ebba1249..75d533515 100644 --- a/app/src/main/java/com/eatssu/android/presentation/widget/ui/MealWidget.kt +++ b/app/src/main/java/com/eatssu/android/presentation/widget/ui/MealWidget.kt @@ -1,6 +1,7 @@ package com.eatssu.android.presentation.widget.ui import android.content.Context +import android.content.Intent import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -42,12 +43,13 @@ import androidx.glance.text.TextStyle import com.eatssu.android.R import com.eatssu.android.domain.model.WidgetMealInfo import com.eatssu.android.domain.usecase.widget.LoadRestaurantByFileKeyUseCase +import com.eatssu.android.presentation.intro.IntroActivity import com.eatssu.android.presentation.widget.MealInfoStateDefinition import com.eatssu.android.presentation.widget.MealWorker import com.eatssu.android.presentation.widget.theme.EATSSUWidgetColorScheme import com.eatssu.android.presentation.widget.util.MealTime import com.eatssu.android.presentation.widget.util.WidgetDataDisplayManager -import com.eatssu.android.presentation.widget.util.launchApp +import com.eatssu.common.enums.LaunchPath import com.eatssu.common.enums.Restaurant import dagger.hilt.EntryPoint import dagger.hilt.InstallIn @@ -255,7 +257,9 @@ class MealWidget : GlanceAppWidget() { .cornerRadius(20.dp) .clickable { Timber.d("위젯 클릭") - context.launchApp() + IntroActivity.start(context, IntroActivity.IntentOptions(LaunchPath.WIDGET)) { + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + } }, ) { Row( diff --git a/app/src/main/java/com/eatssu/android/presentation/widget/util/launchApp.kt b/app/src/main/java/com/eatssu/android/presentation/widget/util/launchApp.kt deleted file mode 100644 index 1b19b4b38..000000000 --- a/app/src/main/java/com/eatssu/android/presentation/widget/util/launchApp.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.eatssu.android.presentation.widget.util - -import android.content.Context -import android.content.Intent -import android.net.Uri - -fun Context.launchApp() { - val deepLinkUri = Uri.parse("eatssu://root") - val intent = Intent(Intent.ACTION_VIEW, deepLinkUri) - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - // 위젯에서 온 것을 표시하는 플래그 추가 - intent.putExtra("launch_path", "widget") - - runCatching { this.startActivity(intent) } -} \ No newline at end of file From ccea94a614cd5f8dd98dcafd8593c6353793be84 Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 16:56:20 +0900 Subject: [PATCH 02/23] =?UTF-8?q?chore:=20companion=20object=20private=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD,=20androidx.core.content.IntentCompat=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/base/ActivityCompanion.kt | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt b/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt index 70a0c5d56..4c8169876 100644 --- a/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt +++ b/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt @@ -3,15 +3,15 @@ package com.eatssu.android.presentation.base import android.app.Activity import android.content.Context import android.content.Intent -import android.os.Build import android.os.Parcelable +import androidx.core.content.IntentCompat.getParcelableExtra import kotlin.reflect.KClass abstract class ActivityCompanion( private val activityClass: KClass, private val optionsClass: KClass ) where IntentOptions : Parcelable { - companion object { + private companion object { private const val INTENT_OPTIONS_KEY = "intent_options" } @@ -30,10 +30,9 @@ abstract class ActivityCompanion( } val Activity.intentOptions: IntentOptions? - get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - this.intent.getParcelableExtra(INTENT_OPTIONS_KEY, optionsClass.java) - } else { - @Suppress("DEPRECATION") - this.intent.getParcelableExtra(INTENT_OPTIONS_KEY) - } + get() = getParcelableExtra( + this.intent, + INTENT_OPTIONS_KEY, + optionsClass.java + ) } \ No newline at end of file From 76a1f20d3956709dfd055e4281466bdb979e13f1 Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:02:06 +0900 Subject: [PATCH 03/23] =?UTF-8?q?feat:=20ActivityCompanion,=20ActivityComp?= =?UTF-8?q?anionWithArgs=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../alarm/EatSsuFirebaseMessagingService.kt | 2 +- .../android/alarm/NotificationReceiver.kt | 2 +- .../presentation/base/ActivityCompanion.kt | 41 +++++++++++++------ .../presentation/intro/IntroActivity.kt | 6 +-- .../presentation/widget/ui/MealWidget.kt | 2 +- 5 files changed, 35 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/alarm/EatSsuFirebaseMessagingService.kt b/app/src/main/java/com/eatssu/android/alarm/EatSsuFirebaseMessagingService.kt index 6a5f05e8a..435b31938 100644 --- a/app/src/main/java/com/eatssu/android/alarm/EatSsuFirebaseMessagingService.kt +++ b/app/src/main/java/com/eatssu/android/alarm/EatSsuFirebaseMessagingService.kt @@ -45,7 +45,7 @@ class EatSsuFirebaseMessagingService : FirebaseMessagingService() { } notificationManager.createNotificationChannel(channel) - val intent = IntroActivity.intent(this, IntroActivity.IntentOptions(REMOTE_NOTIFICATION)) { + val intent = IntroActivity.intent(this, IntroActivity.Args(REMOTE_NOTIFICATION)) { flags = Intent.FLAG_ACTIVITY_CLEAR_TOP } diff --git a/app/src/main/java/com/eatssu/android/alarm/NotificationReceiver.kt b/app/src/main/java/com/eatssu/android/alarm/NotificationReceiver.kt index 2af8e239e..4002c183f 100644 --- a/app/src/main/java/com/eatssu/android/alarm/NotificationReceiver.kt +++ b/app/src/main/java/com/eatssu/android/alarm/NotificationReceiver.kt @@ -42,7 +42,7 @@ class NotificationReceiver : BroadcastReceiver() { val intent = IntroActivity.intent( context, - IntroActivity.IntentOptions(LaunchPath.LOCAL_NOTIFICATION) + IntroActivity.Args(LaunchPath.LOCAL_NOTIFICATION) ) { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } diff --git a/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt b/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt index 4c8169876..1c658cf84 100644 --- a/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt +++ b/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt @@ -7,32 +7,49 @@ import android.os.Parcelable import androidx.core.content.IntentCompat.getParcelableExtra import kotlin.reflect.KClass -abstract class ActivityCompanion( +abstract class ActivityCompanion( private val activityClass: KClass, - private val optionsClass: KClass -) where IntentOptions : Parcelable { +) { + fun intent( + context: Context, + intentBuilder: Intent.() -> Unit = {} + ): Intent = + Intent(context, activityClass.java).apply { + intentBuilder() + } + + fun start(context: Context, intentBuilder: Intent.() -> Unit = {}) { + context.startActivity(intent(context, intentBuilder)) + } + +} + +abstract class ActivityCompanionWithArgs( + private val activityClass: KClass, + private val argsClass: KClass +) where TArgs : Parcelable { private companion object { - private const val INTENT_OPTIONS_KEY = "intent_options" + private const val INTENT_ARGS_KEY = "intent_args" } fun intent( context: Context, - options: IntentOptions, + args: TArgs, intentBuilder: Intent.() -> Unit = {} ): Intent = Intent(context, activityClass.java).apply { - putExtra(INTENT_OPTIONS_KEY, options) + putExtra(INTENT_ARGS_KEY, args) intentBuilder() } - fun start(context: Context, options: IntentOptions, intentBuilder: Intent.() -> Unit = {}) { - context.startActivity(intent(context, options, intentBuilder)) + fun start(context: Context, args: TArgs, intentBuilder: Intent.() -> Unit = {}) { + context.startActivity(intent(context, args, intentBuilder)) } - val Activity.intentOptions: IntentOptions? + val Activity.intentOptions: TArgs? get() = getParcelableExtra( this.intent, - INTENT_OPTIONS_KEY, - optionsClass.java + INTENT_ARGS_KEY, + argsClass.java ) -} \ No newline at end of file +} diff --git a/app/src/main/java/com/eatssu/android/presentation/intro/IntroActivity.kt b/app/src/main/java/com/eatssu/android/presentation/intro/IntroActivity.kt index f3471a012..b51502a94 100644 --- a/app/src/main/java/com/eatssu/android/presentation/intro/IntroActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/intro/IntroActivity.kt @@ -10,7 +10,7 @@ import com.eatssu.android.databinding.ActivityIntroBinding import com.eatssu.android.presentation.MainActivity import com.eatssu.android.presentation.UiEvent import com.eatssu.android.presentation.UiState -import com.eatssu.android.presentation.base.ActivityCompanion +import com.eatssu.android.presentation.base.ActivityCompanionWithArgs import com.eatssu.android.presentation.login.LoginActivity import com.eatssu.android.presentation.util.showToast import com.eatssu.android.presentation.util.startActivity @@ -26,8 +26,8 @@ import kotlinx.parcelize.Parcelize class IntroActivity : AppCompatActivity() { @Parcelize - data class IntentOptions(val launchPath: LaunchPath) : Parcelable - companion object : ActivityCompanion(IntroActivity::class, IntentOptions::class) + data class Args(val launchPath: LaunchPath) : Parcelable + companion object : ActivityCompanionWithArgs(IntroActivity::class, Args::class) private val introViewModel: IntroViewModel by viewModels() private lateinit var binding: ActivityIntroBinding diff --git a/app/src/main/java/com/eatssu/android/presentation/widget/ui/MealWidget.kt b/app/src/main/java/com/eatssu/android/presentation/widget/ui/MealWidget.kt index 75d533515..5f96de1fa 100644 --- a/app/src/main/java/com/eatssu/android/presentation/widget/ui/MealWidget.kt +++ b/app/src/main/java/com/eatssu/android/presentation/widget/ui/MealWidget.kt @@ -257,7 +257,7 @@ class MealWidget : GlanceAppWidget() { .cornerRadius(20.dp) .clickable { Timber.d("위젯 클릭") - IntroActivity.start(context, IntroActivity.IntentOptions(LaunchPath.WIDGET)) { + IntroActivity.start(context, IntroActivity.Args(LaunchPath.WIDGET)) { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } }, From 7786e8e029edee7575f56d95f3b68b5b0f2b0fa1 Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:18:46 +0900 Subject: [PATCH 04/23] =?UTF-8?q?refactor:=20WebViewActivity=20=EC=83=88?= =?UTF-8?q?=20Intent=20=EA=B5=AC=EC=A1=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/mypage/MyPageFragment.kt | 20 ++++++------- .../mypage/terms/WebViewActivity.kt | 30 +++++++++++-------- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt index e9dec35e6..ba4c799dd 100644 --- a/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt @@ -154,11 +154,11 @@ class MyPageFragment : BaseFragment(ScreenId.MYPAGE_MAIN) binding.llSignout.setOnClickListener { // 현재 Success 상태에서 안전하게 닉네임 추출 - val nickname = (myPageViewModel.uiState.value as? UiState.Success)?.data?.nickname - Intent(requireContext(), SignOutActivity::class.java).apply { - putExtra("nickname", nickname) - startActivity(this) - } + val nickname = (myPageViewModel.uiState.value as? UiState.Success)?.data?.nickname ?: "" + SignOutActivity.start( + requireContext(), + SignOutActivity.Args(nickname) + ) } binding.llDeveloper.setOnClickListener { @@ -246,11 +246,9 @@ class MyPageFragment : BaseFragment(ScreenId.MYPAGE_MAIN) } private fun startWebView(url: String, title: String, screenId: ScreenId) { - val intent = Intent(requireContext(), WebViewActivity::class.java).apply { - putExtra("URL", url) - putExtra("TITLE", title) - putExtra("SCREEN_ID", screenId.name) - } - startActivity(intent) + WebViewActivity.start( + requireContext(), + WebViewActivity.Args(url, title, screenId) + ) } } diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/terms/WebViewActivity.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/terms/WebViewActivity.kt index c049d92f3..2f38eec7a 100644 --- a/app/src/main/java/com/eatssu/android/presentation/mypage/terms/WebViewActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/terms/WebViewActivity.kt @@ -1,11 +1,14 @@ package com.eatssu.android.presentation.mypage.terms import android.os.Bundle +import android.os.Parcelable import android.webkit.WebViewClient import com.eatssu.android.databinding.ActivityWebviewBinding +import com.eatssu.android.presentation.base.ActivityCompanionWithArgs import com.eatssu.android.presentation.base.BaseActivity import com.eatssu.common.EventLogger import com.eatssu.common.enums.ScreenId +import kotlinx.parcelize.Parcelize import timber.log.Timber @@ -15,15 +18,18 @@ class WebViewActivity : ScreenId.EXTERNAL_INQUIRE // shouldLogScreenId가 false라 미사용 ) { + @Parcelize + data class Args( + val url: String, + val title: String, + val screenId: ScreenId + ) : Parcelable - private var URL = "" - private var TITLE = "" + companion object : ActivityCompanionWithArgs(WebViewActivity::class, Args::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - - binding.webview.apply { webViewClient = WebViewClient() @@ -38,14 +44,14 @@ class WebViewActivity : useWideViewPort = true // 화면 크기에 맞게 웹 페이지를 조정 } - URL = intent.getStringExtra("URL") ?: "" //Todo 뷰모델 사용하도록 수정? - TITLE = intent.getStringExtra("TITLE") ?: "" + val title = intentOptions?.title ?: "" + val url = intentOptions?.url ?: "" - toolbarTitle.text = TITLE - Timber.d(URL + TITLE) + toolbarTitle.text = title + Timber.d("%s %s", url, title) if (savedInstanceState != null) restoreState(savedInstanceState) - else loadUrl(URL) + else loadUrl(url) } } @@ -62,11 +68,9 @@ class WebViewActivity : override fun onResume() { super.onResume() - val screenIdString = intent.getStringExtra("SCREEN_ID") ?: return - val screenId = ScreenId.entries.find { it.name == screenIdString } ?: return - + val screenId = intentOptions?.screenId ?: return EventLogger.screenView(screenId) - Timber.d("WebViewActivity screen view logging: $screenId") + Timber.d("WebViewActivity screen view logging: ${screenId}") } override fun shouldLogScreenId() = false From e54505f1bae2d9936ed3d7fb3ff62e9d871a6729 Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:25:10 +0900 Subject: [PATCH 05/23] =?UTF-8?q?refactor:=20ForceUpdateDialogActivity=20?= =?UTF-8?q?=EC=83=88=20Intent=20=EA=B5=AC=EC=A1=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/eatssu/android/presentation/base/BaseActivity.kt | 3 +-- .../eatssu/android/presentation/common/ForceUpdateActivity.kt | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/base/BaseActivity.kt b/app/src/main/java/com/eatssu/android/presentation/base/BaseActivity.kt index 3f1760db6..a5820655c 100644 --- a/app/src/main/java/com/eatssu/android/presentation/base/BaseActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/base/BaseActivity.kt @@ -169,8 +169,7 @@ abstract class BaseActivity( } private fun showForceUpdateDialog() { - val intent = Intent(this, ForceUpdateDialogActivity::class.java) - startActivity(intent) + ForceUpdateDialogActivity.start(this) } override fun onResume() { diff --git a/app/src/main/java/com/eatssu/android/presentation/common/ForceUpdateActivity.kt b/app/src/main/java/com/eatssu/android/presentation/common/ForceUpdateActivity.kt index 4e241bbaa..52f2ab10e 100644 --- a/app/src/main/java/com/eatssu/android/presentation/common/ForceUpdateActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/common/ForceUpdateActivity.kt @@ -6,10 +6,13 @@ import android.content.Intent import android.net.Uri import android.os.Bundle import androidx.appcompat.app.AppCompatActivity +import com.eatssu.android.presentation.base.ActivityCompanion class ForceUpdateDialogActivity : AppCompatActivity() { + companion object : ActivityCompanion(ForceUpdateDialogActivity::class) + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) showForceUpdateDialog() From 27029a2a8110516dc47e7693ba0053b329c6754d Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:27:54 +0900 Subject: [PATCH 06/23] =?UTF-8?q?refactor:=20LoginActivity=20=EC=83=88=20I?= =?UTF-8?q?ntent=20=EA=B5=AC=EC=A1=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/eatssu/android/presentation/MainActivity.kt | 2 +- .../java/com/eatssu/android/presentation/base/BaseActivity.kt | 4 ++-- .../com/eatssu/android/presentation/intro/IntroActivity.kt | 2 +- .../com/eatssu/android/presentation/login/LoginActivity.kt | 3 +++ .../com/eatssu/android/presentation/mypage/MyPageFragment.kt | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/MainActivity.kt b/app/src/main/java/com/eatssu/android/presentation/MainActivity.kt index d5fab44bf..d4e0a516d 100644 --- a/app/src/main/java/com/eatssu/android/presentation/MainActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/MainActivity.kt @@ -154,7 +154,7 @@ class MainActivity : BaseActivity( } is MainState.LoggedOut -> { - startActivity() + LoginActivity.start(this@MainActivity) finishAffinity() } diff --git a/app/src/main/java/com/eatssu/android/presentation/base/BaseActivity.kt b/app/src/main/java/com/eatssu/android/presentation/base/BaseActivity.kt index a5820655c..287b82650 100644 --- a/app/src/main/java/com/eatssu/android/presentation/base/BaseActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/base/BaseActivity.kt @@ -136,9 +136,9 @@ abstract class BaseActivity( } private fun navigateToLogin() { - startActivity(Intent(this, LoginActivity::class.java).apply { + LoginActivity.start(this) { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK - }) + } finishAffinity() } diff --git a/app/src/main/java/com/eatssu/android/presentation/intro/IntroActivity.kt b/app/src/main/java/com/eatssu/android/presentation/intro/IntroActivity.kt index b51502a94..184dbdc54 100644 --- a/app/src/main/java/com/eatssu/android/presentation/intro/IntroActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/intro/IntroActivity.kt @@ -49,7 +49,7 @@ class IntroActivity : AppCompatActivity() { is UiState.Error -> { // 로그인 액티비티로 이동 - startActivity() + LoginActivity.start(this@IntroActivity) finish() } diff --git a/app/src/main/java/com/eatssu/android/presentation/login/LoginActivity.kt b/app/src/main/java/com/eatssu/android/presentation/login/LoginActivity.kt index 3abc4e64b..337f81c6c 100644 --- a/app/src/main/java/com/eatssu/android/presentation/login/LoginActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/login/LoginActivity.kt @@ -11,6 +11,7 @@ import com.eatssu.android.databinding.ActivityLoginBinding import com.eatssu.android.presentation.MainActivity import com.eatssu.android.presentation.UiEvent import com.eatssu.android.presentation.UiState +import com.eatssu.android.presentation.base.ActivityCompanion import com.eatssu.android.presentation.base.BaseActivity import com.eatssu.android.presentation.util.showToast import com.eatssu.android.presentation.util.startActivity @@ -30,6 +31,8 @@ class LoginActivity : ScreenId.LOGIN_LOGIN ) { + companion object : ActivityCompanion(LoginActivity::class) + private val loginViewModel: LoginViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt index ba4c799dd..c17485e08 100644 --- a/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt @@ -212,7 +212,7 @@ class MyPageFragment : BaseFragment(ScreenId.MYPAGE_MAIN) .setMessage("로그아웃 하시겠습니까?") .setPositiveButton("로그아웃") { _, _ -> mainViewModel.logOut() // 로그아웃은 메인 액티비티에서 처리하도록 수정 - startActivity(Intent(requireContext(), LoginActivity::class.java)) + LoginActivity.start(requireContext()) } .setNegativeButton("취소", null) .show() From c79d3d118ffc0681ca94514d504c85cbaa3e4250 Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:32:50 +0900 Subject: [PATCH 07/23] =?UTF-8?q?refactor:=20MainActivity=20=EC=83=88=20In?= =?UTF-8?q?tent=20=EA=B5=AC=EC=A1=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/eatssu/android/presentation/MainActivity.kt | 3 +++ .../com/eatssu/android/presentation/intro/IntroActivity.kt | 3 +-- .../com/eatssu/android/presentation/login/LoginActivity.kt | 3 +-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/MainActivity.kt b/app/src/main/java/com/eatssu/android/presentation/MainActivity.kt index d4e0a516d..43790a71c 100644 --- a/app/src/main/java/com/eatssu/android/presentation/MainActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/MainActivity.kt @@ -16,6 +16,7 @@ import androidx.navigation.fragment.NavHostFragment import androidx.work.WorkManager import com.eatssu.android.R import com.eatssu.android.databinding.ActivityMainBinding +import com.eatssu.android.presentation.base.ActivityCompanion import com.eatssu.android.presentation.base.BaseActivity import com.eatssu.android.presentation.login.LoginActivity import com.eatssu.android.presentation.mypage.MyPageViewModel @@ -38,6 +39,8 @@ class MainActivity : BaseActivity( ScreenId.HOME_MAIN ) { + companion object : ActivityCompanion(MainActivity::class) + @Inject lateinit var workManager: WorkManager diff --git a/app/src/main/java/com/eatssu/android/presentation/intro/IntroActivity.kt b/app/src/main/java/com/eatssu/android/presentation/intro/IntroActivity.kt index 184dbdc54..70c3e8e7c 100644 --- a/app/src/main/java/com/eatssu/android/presentation/intro/IntroActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/intro/IntroActivity.kt @@ -13,7 +13,6 @@ import com.eatssu.android.presentation.UiState import com.eatssu.android.presentation.base.ActivityCompanionWithArgs import com.eatssu.android.presentation.login.LoginActivity import com.eatssu.android.presentation.util.showToast -import com.eatssu.android.presentation.util.startActivity import com.eatssu.common.EventLogger import com.eatssu.common.enums.LaunchPath import com.eatssu.common.enums.ScreenId @@ -43,7 +42,7 @@ class IntroActivity : AppCompatActivity() { introViewModel.uiState.collectLatest { state -> when (state) { is UiState.Success -> { - startActivity() + MainActivity.start(this@IntroActivity) finish() } diff --git a/app/src/main/java/com/eatssu/android/presentation/login/LoginActivity.kt b/app/src/main/java/com/eatssu/android/presentation/login/LoginActivity.kt index 337f81c6c..4c324a80d 100644 --- a/app/src/main/java/com/eatssu/android/presentation/login/LoginActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/login/LoginActivity.kt @@ -14,7 +14,6 @@ import com.eatssu.android.presentation.UiState import com.eatssu.android.presentation.base.ActivityCompanion import com.eatssu.android.presentation.base.BaseActivity import com.eatssu.android.presentation.util.showToast -import com.eatssu.android.presentation.util.startActivity import com.eatssu.common.enums.ScreenId import com.kakao.sdk.common.model.ClientError import com.kakao.sdk.common.model.ClientErrorCause @@ -100,7 +99,7 @@ class LoginActivity : when (state) { is UiState.Loading -> showLoading(true) is UiState.Success -> { - startActivity() + MainActivity.start(this@LoginActivity) finishAffinity() } else -> { From f9373c6a40d519840b25b2ee2036c3c45c688a4d Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:33:40 +0900 Subject: [PATCH 08/23] chore: ActivityUtil.kt startActivity deprecate --- .../com/eatssu/android/presentation/util/ActivityUtil.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/com/eatssu/android/presentation/util/ActivityUtil.kt b/app/src/main/java/com/eatssu/android/presentation/util/ActivityUtil.kt index b40d27a41..a715f5d63 100644 --- a/app/src/main/java/com/eatssu/android/presentation/util/ActivityUtil.kt +++ b/app/src/main/java/com/eatssu/android/presentation/util/ActivityUtil.kt @@ -4,6 +4,11 @@ import android.app.Activity import android.content.Intent import androidx.appcompat.app.AppCompatActivity +@Deprecated( + message = "Use Activity companion object pattern instead. Example: MainActivity.start(context)", + replaceWith = ReplaceWith("ActivityName.start(this)"), + level = DeprecationLevel.WARNING +) inline fun AppCompatActivity.startActivity(block: Intent.() -> Unit = {}) { startActivity(Intent(this, T::class.java).apply(block)) } \ No newline at end of file From f3cbe9a097915ba99ba2e55f176272da5b91d8d0 Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:34:06 +0900 Subject: [PATCH 09/23] =?UTF-8?q?feat:=20=EA=B8=B0=EB=B3=B8=EA=B0=92?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=A7=8C=EB=93=A4=20=EC=88=98=20=EC=9E=88?= =?UTF-8?q?=EB=8A=94=20ActivityCompanionWithArgsDefault=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/base/ActivityCompanion.kt | 54 ++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt b/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt index 1c658cf84..cc81aba1e 100644 --- a/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt +++ b/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt @@ -7,16 +7,16 @@ import android.os.Parcelable import androidx.core.content.IntentCompat.getParcelableExtra import kotlin.reflect.KClass +private const val INTENT_ARGS_KEY = "intent_args" + abstract class ActivityCompanion( - private val activityClass: KClass, + protected val activityClass: KClass, ) { fun intent( - context: Context, - intentBuilder: Intent.() -> Unit = {} - ): Intent = - Intent(context, activityClass.java).apply { - intentBuilder() - } + context: Context, intentBuilder: Intent.() -> Unit = {} + ): Intent = Intent(context, activityClass.java).apply { + intentBuilder() + } fun start(context: Context, intentBuilder: Intent.() -> Unit = {}) { context.startActivity(intent(context, intentBuilder)) @@ -25,22 +25,15 @@ abstract class ActivityCompanion( } abstract class ActivityCompanionWithArgs( - private val activityClass: KClass, - private val argsClass: KClass + protected val activityClass: KClass, + protected val argsClass: KClass, ) where TArgs : Parcelable { - private companion object { - private const val INTENT_ARGS_KEY = "intent_args" - } - fun intent( - context: Context, - args: TArgs, - intentBuilder: Intent.() -> Unit = {} - ): Intent = - Intent(context, activityClass.java).apply { - putExtra(INTENT_ARGS_KEY, args) - intentBuilder() - } + context: Context, args: TArgs, intentBuilder: Intent.() -> Unit = {} + ): Intent = Intent(context, activityClass.java).apply { + putExtra(INTENT_ARGS_KEY, args) + intentBuilder() + } fun start(context: Context, args: TArgs, intentBuilder: Intent.() -> Unit = {}) { context.startActivity(intent(context, args, intentBuilder)) @@ -48,8 +41,21 @@ abstract class ActivityCompanionWithArgs( val Activity.intentOptions: TArgs? get() = getParcelableExtra( - this.intent, - INTENT_ARGS_KEY, - argsClass.java + this.intent, INTENT_ARGS_KEY, argsClass.java ) } + +abstract class ActivityCompanionWithArgsDefault( + activityClass: KClass, + argsClass: KClass, + private val defaultArgs: (Context) -> TArgs, +) : ActivityCompanionWithArgs(activityClass, argsClass) where TArgs : Parcelable { + + fun intent( + context: Context, intentBuilder: Intent.() -> Unit = {} + ): Intent = Intent(context, activityClass.java).apply { + putExtra(INTENT_ARGS_KEY, defaultArgs(context)) + intentBuilder() + } + +} From 2b0584782faf77e9244d3220273474306d552a6b Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:36:10 +0900 Subject: [PATCH 10/23] =?UTF-8?q?refactor:=20SignOutActivity=20=EC=83=88?= =?UTF-8?q?=20Intent=20=EA=B5=AC=EC=A1=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../android/presentation/mypage/MyPageFragment.kt | 2 +- .../android/presentation/mypage/SignOutActivity.kt | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt index c17485e08..e5970031e 100644 --- a/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt @@ -133,7 +133,7 @@ class MyPageFragment : BaseFragment(ScreenId.MYPAGE_MAIN) private fun setOnClickListener() { binding.llMyInfo.setOnClickListener { - startActivity(Intent(requireContext(), UserInfoActivity::class.java)) + UserInfoActivity.start(requireContext(), UserInfoActivity.Args()) } binding.llInquire.setOnClickListener { diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/SignOutActivity.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/SignOutActivity.kt index e2b56f8f6..e2066f53f 100644 --- a/app/src/main/java/com/eatssu/android/presentation/mypage/SignOutActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/SignOutActivity.kt @@ -2,12 +2,14 @@ package com.eatssu.android.presentation.mypage import android.content.Intent import android.os.Bundle +import android.os.Parcelable import androidx.activity.viewModels import androidx.core.widget.doAfterTextChanged import androidx.lifecycle.lifecycleScope import com.eatssu.android.databinding.ActivitySignOutBinding import com.eatssu.android.presentation.UiEvent import com.eatssu.android.presentation.UiState +import com.eatssu.android.presentation.base.ActivityCompanionWithArgs import com.eatssu.android.presentation.base.BaseActivity import com.eatssu.android.presentation.login.LoginActivity import com.eatssu.android.presentation.util.showToast @@ -15,6 +17,7 @@ import com.eatssu.common.enums.ScreenId import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import kotlinx.parcelize.Parcelize @AndroidEntryPoint class SignOutActivity : @@ -24,6 +27,11 @@ class SignOutActivity : ) { //TODO 현재 dev서버 탈퇴하기 500 + @Parcelize + data class Args(val nickname: String) : Parcelable + + companion object : ActivityCompanionWithArgs(SignOutActivity::class, Args::class) + private val signOutViewModel: SignOutViewModel by viewModels() private var inputNickname: String = "" @@ -32,7 +40,7 @@ class SignOutActivity : super.onCreate(savedInstanceState) toolbarTitle.text = "탈퇴하기" // 툴바 제목 설정 - val nickname = intent.getStringExtra("nickname")?.trim() ?: "" + val nickname = intentOptions?.nickname?.trim() ?: "" binding.btnSignOut.isEnabled = false From 9e2860df866651ac0d18e543195d829e91088867 Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:37:17 +0900 Subject: [PATCH 11/23] =?UTF-8?q?refactor:=20WebViewActivity=20=ED=98=B8?= =?UTF-8?q?=EC=B6=9C=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/mypage/DeveloperActivity.kt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/DeveloperActivity.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/DeveloperActivity.kt index 89c44c0e8..c5f2a7503 100644 --- a/app/src/main/java/com/eatssu/android/presentation/mypage/DeveloperActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/DeveloperActivity.kt @@ -31,12 +31,14 @@ class DeveloperActivity : private fun clickRecruiting() { binding.imgRecruitingBanner.setOnClickListener { - val intent = Intent(this, WebViewActivity::class.java).apply { - putExtra("TITLE", "Who’s next?") - putExtra("URL", getString(R.string.recruiting_url)) - putExtra("SCREEN_ID", ScreenId.EXTERNAL_RECRUIT.name) - } - startActivity(intent) + WebViewActivity.start( + this, + WebViewActivity.Args( + url = getString(R.string.recruiting_url), + title = "Who's next?", + screenId = ScreenId.EXTERNAL_RECRUIT + ) + ) } } } \ No newline at end of file From 07a00fa40f3a6944bf8f2c7756d2c6447649510c Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:37:47 +0900 Subject: [PATCH 12/23] =?UTF-8?q?refactor:=20DeveloperActivity=20=EC=83=88?= =?UTF-8?q?=20Intent=20=EA=B5=AC=EC=A1=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../eatssu/android/presentation/mypage/DeveloperActivity.kt | 4 +++- .../com/eatssu/android/presentation/mypage/MyPageFragment.kt | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/DeveloperActivity.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/DeveloperActivity.kt index c5f2a7503..eb78d81f4 100644 --- a/app/src/main/java/com/eatssu/android/presentation/mypage/DeveloperActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/DeveloperActivity.kt @@ -1,11 +1,11 @@ package com.eatssu.android.presentation.mypage -import android.content.Intent import android.os.Bundle import androidx.core.graphics.drawable.toDrawable import androidx.core.graphics.toColorInt import com.eatssu.android.R import com.eatssu.android.databinding.ActivityDeveloperBinding +import com.eatssu.android.presentation.base.ActivityCompanion import com.eatssu.android.presentation.base.BaseActivity import com.eatssu.android.presentation.mypage.terms.WebViewActivity import com.eatssu.common.enums.ScreenId @@ -17,6 +17,8 @@ class DeveloperActivity : ActivityDeveloperBinding::inflate, ScreenId.MYPAGE_DEVELOPER ) { + + companion object : ActivityCompanion(DeveloperActivity::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt index e5970031e..97e64da2f 100644 --- a/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt @@ -162,7 +162,7 @@ class MyPageFragment : BaseFragment(ScreenId.MYPAGE_MAIN) } binding.llDeveloper.setOnClickListener { - startActivity(Intent(requireContext(), DeveloperActivity::class.java)) + DeveloperActivity.start(requireContext()) } binding.llOss.setOnClickListener { moveToOss() } From 6e9601429a0445d1ed627221ea5a001cc0850467 Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:38:00 +0900 Subject: [PATCH 13/23] =?UTF-8?q?refactor:=20MyReviewListActivity=20?= =?UTF-8?q?=EC=83=88=20Intent=20=EA=B5=AC=EC=A1=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/eatssu/android/presentation/mypage/MyPageFragment.kt | 2 +- .../presentation/mypage/myreview/MyReviewListActivity.kt | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt index 97e64da2f..29e49fdda 100644 --- a/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt @@ -145,7 +145,7 @@ class MyPageFragment : BaseFragment(ScreenId.MYPAGE_MAIN) } binding.llMyReview.setOnClickListener { - startActivity(Intent(requireContext(), MyReviewListActivity::class.java)) + MyReviewListActivity.start(requireContext()) } binding.tvLogout.setOnClickListener { diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewListActivity.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewListActivity.kt index fa0e96307..a89ba63d8 100644 --- a/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewListActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewListActivity.kt @@ -9,6 +9,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.eatssu.android.R import com.eatssu.android.databinding.ActivityMyReviewListBinding import com.eatssu.android.domain.model.Review +import com.eatssu.android.presentation.base.ActivityCompanion import com.eatssu.android.presentation.base.BaseActivity import com.eatssu.android.presentation.common.MyReviewBottomSheetFragment import com.eatssu.common.enums.ScreenId @@ -22,6 +23,8 @@ class MyReviewListActivity : BaseActivity( ScreenId.MYPAGE_REVIEWS, ), MyReviewBottomSheetFragment.OnReviewDeletedListener { + companion object : ActivityCompanion(MyReviewListActivity::class) + private val myReviewViewModel: MyReviewViewModel by viewModels() lateinit var menu: String From a03b597d074e9d2432906e0b19f774dfa46673c0 Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:39:17 +0900 Subject: [PATCH 14/23] =?UTF-8?q?refactor:=20AndroidMessageDialogActivity?= =?UTF-8?q?=20=EC=83=88=20Intent=20=EA=B5=AC=EC=A1=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/AndroidMessageDialogActivity.kt | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/common/AndroidMessageDialogActivity.kt b/app/src/main/java/com/eatssu/android/presentation/common/AndroidMessageDialogActivity.kt index b76ceb6d9..c5d48a1e2 100644 --- a/app/src/main/java/com/eatssu/android/presentation/common/AndroidMessageDialogActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/common/AndroidMessageDialogActivity.kt @@ -3,12 +3,21 @@ package com.eatssu.android.presentation.common import android.app.AlertDialog import android.os.Bundle -import android.util.Log +import android.os.Parcelable import androidx.appcompat.app.AppCompatActivity +import com.eatssu.android.presentation.base.ActivityCompanionWithArgs +import kotlinx.parcelize.Parcelize +import timber.log.Timber class AndroidMessageDialogActivity : AppCompatActivity() { + @Parcelize + data class Args(val message: String) : Parcelable + + companion object : + ActivityCompanionWithArgs(AndroidMessageDialogActivity::class, Args::class) + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) showDialog() @@ -18,9 +27,9 @@ class AndroidMessageDialogActivity : AppCompatActivity() { val builder = AlertDialog.Builder(this) builder.setTitle("공지") - val message = intent.getStringExtra("message") - Log.d("message",message.toString()) - builder.setMessage(intent.getStringExtra("message")) + val message = intentOptions?.message + Timber.tag("message").d(message.toString()) + builder.setMessage(message) builder.setPositiveButton("확인") { dialog, which -> // Google Play Store의 앱 페이지로 이동하여 업데이트를 다운로드합니다. From a9a8bc9cbff8adb825ec1dba1dc0e2ee306c7613 Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:40:37 +0900 Subject: [PATCH 15/23] =?UTF-8?q?chore:=20Default=20start=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/eatssu/android/presentation/base/ActivityCompanion.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt b/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt index cc81aba1e..dc1c55b56 100644 --- a/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt +++ b/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt @@ -58,4 +58,8 @@ abstract class ActivityCompanionWithArgsDefault( intentBuilder() } + fun start(context: Context, intentBuilder: Intent.() -> Unit = {}) { + context.startActivity(intent(context, intentBuilder)) + } + } From a096d628fec43cf91aed6be02e32d119963a7b75 Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:41:43 +0900 Subject: [PATCH 16/23] =?UTF-8?q?refactor:=20UserInfoActivity=20=EC=83=88?= =?UTF-8?q?=20Intent=20=EA=B5=AC=EC=A1=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/eatssu/android/presentation/MainActivity.kt | 7 ++++--- .../android/presentation/map/MapFragmentView.kt | 4 +--- .../presentation/mypage/userinfo/UserInfoActivity.kt | 11 +++++++++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/MainActivity.kt b/app/src/main/java/com/eatssu/android/presentation/MainActivity.kt index 43790a71c..438df610a 100644 --- a/app/src/main/java/com/eatssu/android/presentation/MainActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/MainActivity.kt @@ -22,7 +22,6 @@ import com.eatssu.android.presentation.login.LoginActivity import com.eatssu.android.presentation.mypage.MyPageViewModel import com.eatssu.android.presentation.mypage.userinfo.UserInfoActivity import com.eatssu.android.presentation.util.showToast -import com.eatssu.android.presentation.util.startActivity import com.eatssu.common.enums.ScreenId import com.google.android.material.bottomnavigation.BottomNavigationView import dagger.hilt.android.AndroidEntryPoint @@ -152,8 +151,10 @@ class MainActivity : BaseActivity( if (state is UiState.Success) { when (state.data) { is MainState.NicknameNull -> { - intent.putExtra("force", true) - startActivity() + UserInfoActivity.start( + this@MainActivity, + UserInfoActivity.Args(force = true) + ) } is MainState.LoggedOut -> { diff --git a/app/src/main/java/com/eatssu/android/presentation/map/MapFragmentView.kt b/app/src/main/java/com/eatssu/android/presentation/map/MapFragmentView.kt index 1cab2000d..7d0be3af2 100644 --- a/app/src/main/java/com/eatssu/android/presentation/map/MapFragmentView.kt +++ b/app/src/main/java/com/eatssu/android/presentation/map/MapFragmentView.kt @@ -4,7 +4,6 @@ import android.Manifest import android.app.Activity import android.content.Context import android.content.ContextWrapper -import android.content.Intent import android.content.pm.PackageManager import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult @@ -240,8 +239,7 @@ fun MapFragmentComposeView( onDismiss = { viewModel.toggleDepartmentBottomSheet() }, onInputClick = { viewModel.toggleDepartmentBottomSheet() - val intent = Intent(context, UserInfoActivity::class.java) - context.startActivity(intent) + UserInfoActivity.start(context) }, sheetState = sheetState ) diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/userinfo/UserInfoActivity.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/userinfo/UserInfoActivity.kt index 8841e221a..d4b1ffc38 100644 --- a/app/src/main/java/com/eatssu/android/presentation/mypage/userinfo/UserInfoActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/userinfo/UserInfoActivity.kt @@ -1,6 +1,7 @@ package com.eatssu.android.presentation.mypage.userinfo import android.os.Bundle +import android.os.Parcelable import android.text.Editable import android.text.TextWatcher import android.view.LayoutInflater @@ -15,12 +16,14 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.eatssu.android.R import com.eatssu.android.databinding.ActivityUserInfoBinding +import com.eatssu.android.presentation.base.ActivityCompanionWithArgsDefault import com.eatssu.android.presentation.base.BaseActivity import com.eatssu.android.presentation.util.showToast import com.eatssu.common.enums.ScreenId import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import kotlinx.parcelize.Parcelize @AndroidEntryPoint class UserInfoActivity : @@ -29,7 +32,11 @@ class UserInfoActivity : ScreenId.MYPAGE_USERINFO ) { - companion object { + @Parcelize + data class Args(val force: Boolean = false) : Parcelable + + companion object : + ActivityCompanionWithArgsDefault(UserInfoActivity::class, Args::class, { Args() }) { private const val MIN_NICKNAME_LENGTH = 2 private const val MAX_NICKNAME_LENGTH = 16 } @@ -50,7 +57,7 @@ class UserInfoActivity : // 현재 설정된 유저 정보 가져오기 userInfoViewModel.loadUserInfo() - force = intent.getBooleanExtra("force", false) + force = intentOptions?.force ?: false binding.btnCheckNicknameDuplication.isEnabled = false binding.btnComplete.isEnabled = false From 18e60affbab2f9a9da4ef628e562526a2d45cac2 Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:43:03 +0900 Subject: [PATCH 17/23] =?UTF-8?q?refactor:=20ReportActivity=20=EC=83=88=20?= =?UTF-8?q?Intent=20=EA=B5=AC=EC=A1=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cafeteria/review/report/ReportActivity.kt | 10 +++++++++- .../presentation/common/OthersBottomSheetFragment.kt | 9 ++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/report/ReportActivity.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/report/ReportActivity.kt index dec710a88..fbbb28623 100644 --- a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/report/ReportActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/report/ReportActivity.kt @@ -1,11 +1,13 @@ package com.eatssu.android.presentation.cafeteria.review.report import android.os.Bundle +import android.os.Parcelable import android.text.Editable import android.text.TextWatcher import androidx.activity.viewModels import androidx.lifecycle.lifecycleScope import com.eatssu.android.databinding.ActivityReportBinding +import com.eatssu.android.presentation.base.ActivityCompanionWithArgs import com.eatssu.android.presentation.base.BaseActivity import com.eatssu.android.presentation.util.showToast import com.eatssu.common.enums.ReportType @@ -13,6 +15,7 @@ import com.eatssu.common.enums.ScreenId import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import kotlinx.parcelize.Parcelize @AndroidEntryPoint @@ -20,6 +23,11 @@ class ReportActivity : BaseActivity( ActivityReportBinding::inflate, ScreenId.REVIEW_REPORT ) { + @Parcelize + data class Args(val reviewId: Long) : Parcelable + + companion object : ActivityCompanionWithArgs(ReportActivity::class, Args::class) + private val reportViewModel: ReportViewModel by viewModels() private var reviewId = -1L @@ -34,7 +42,7 @@ class ReportActivity : BaseActivity( super.onCreate(savedInstanceState) toolbarTitle.text = "신고하기" // 툴바 제목 설정 - reviewId = intent.getLongExtra("reviewId", -1L) + reviewId = intentOptions?.reviewId ?: -1L binding.etReportComment.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} diff --git a/app/src/main/java/com/eatssu/android/presentation/common/OthersBottomSheetFragment.kt b/app/src/main/java/com/eatssu/android/presentation/common/OthersBottomSheetFragment.kt index 501482877..34837341e 100644 --- a/app/src/main/java/com/eatssu/android/presentation/common/OthersBottomSheetFragment.kt +++ b/app/src/main/java/com/eatssu/android/presentation/common/OthersBottomSheetFragment.kt @@ -1,6 +1,5 @@ package com.eatssu.android.presentation.common -import android.content.Intent import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -39,11 +38,11 @@ class OthersBottomSheetFragment : BottomSheetDialogFragment() { Timber.d("넘겨받은 리뷰 정보: $reviewId $menu") binding.llReport.setOnClickListener { - - val intent = Intent(requireContext(), ReportActivity::class.java) - intent.putExtra("reviewId", reviewId) Timber.d("reviewId $reviewId") - startActivity(intent) + ReportActivity.start( + requireContext(), + ReportActivity.Args(reviewId) + ) dismiss() } } From 3371d2ef37b2e0fbc66ba3314d5d31d2d25d6260 Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:43:26 +0900 Subject: [PATCH 18/23] =?UTF-8?q?refactor:=20ModifyReviewActivity=20?= =?UTF-8?q?=EC=83=88=20Intent=20=EA=B5=AC=EC=A1=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../review/modify/ModifyReviewActivity.kt | 33 ++++++++++++++----- .../common/MyReviewBottomSheetFragment.kt | 26 +++++++-------- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/modify/ModifyReviewActivity.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/modify/ModifyReviewActivity.kt index 82c14586f..073e08fb9 100644 --- a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/modify/ModifyReviewActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/modify/ModifyReviewActivity.kt @@ -1,16 +1,19 @@ package com.eatssu.android.presentation.cafeteria.review.modify import android.os.Bundle +import android.os.Parcelable import androidx.activity.viewModels import androidx.lifecycle.lifecycleScope import com.eatssu.android.data.dto.request.ModifyReviewRequest import com.eatssu.android.databinding.ActivityFixMenuBinding +import com.eatssu.android.presentation.base.ActivityCompanionWithArgs import com.eatssu.android.presentation.base.BaseActivity import com.eatssu.android.presentation.util.showToast import com.eatssu.common.enums.ScreenId import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import kotlinx.parcelize.Parcelize import timber.log.Timber @AndroidEntryPoint @@ -19,6 +22,18 @@ class ModifyReviewActivity : BaseActivity( ScreenId.REVIEW_V1_MODIFY ) { + @Parcelize + data class Args( + val reviewId: Long, + val menu: String, + val content: String, + val mainGrade: Int, + val amountGrade: Int, + val tasteGrade: Int + ) : Parcelable + + companion object : ActivityCompanionWithArgs(ModifyReviewActivity::class, Args::class) + private val modifyViewModel: ModifyViewModel by viewModels() private var reviewId = -1L @@ -48,14 +63,14 @@ class ModifyReviewActivity : BaseActivity( private fun getIndex() { + val args = intentOptions + reviewId = args?.reviewId ?: -1L + menu = args?.menu ?: "" + content = args?.content ?: "" - reviewId = intent.getLongExtra("reviewId", -1L) - menu = intent.getStringExtra("menu").toString() - content = intent.getStringExtra("content").toString() - - main = intent.getIntExtra("mainGrade", 0) - amount = intent.getIntExtra("amountGrade", 0) - taste = intent.getIntExtra("tasteGrade", 0) + main = args?.mainGrade ?: 0 + amount = args?.amountGrade ?: 0 + taste = args?.tasteGrade ?: 0 Timber.tag("ReviewFixedActivity") .d("reviewID: %s, menu: %s, content: %s", reviewId.toString(), menu, content) @@ -65,8 +80,8 @@ class ModifyReviewActivity : BaseActivity( binding.menu.text = menu binding.etReview2Comment.setText(content) binding.rbMain.rating = main.toFloat() - binding.rbAmount.rating = intent.getIntExtra("amountGrade", 0).toFloat() - binding.rbTaste.rating = intent.getIntExtra("tasteGrade", 0).toFloat() + binding.rbAmount.rating = amount.toFloat() + binding.rbTaste.rating = taste.toFloat() } private fun postData(reviewId: Long) { diff --git a/app/src/main/java/com/eatssu/android/presentation/common/MyReviewBottomSheetFragment.kt b/app/src/main/java/com/eatssu/android/presentation/common/MyReviewBottomSheetFragment.kt index 2d4220c59..95ccd4b6f 100644 --- a/app/src/main/java/com/eatssu/android/presentation/common/MyReviewBottomSheetFragment.kt +++ b/app/src/main/java/com/eatssu/android/presentation/common/MyReviewBottomSheetFragment.kt @@ -1,6 +1,5 @@ package com.eatssu.android.presentation.common -import android.content.Intent import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -11,8 +10,8 @@ import androidx.lifecycle.lifecycleScope import com.eatssu.android.App import com.eatssu.android.R import com.eatssu.android.databinding.FragmentBottomsheetMyReviewBinding -import com.eatssu.android.presentation.mypage.myreview.MyReviewViewModel import com.eatssu.android.presentation.cafeteria.review.modify.ModifyReviewActivity +import com.eatssu.android.presentation.mypage.myreview.MyReviewViewModel import com.eatssu.android.presentation.util.showToast import com.google.android.material.bottomsheet.BottomSheetDialogFragment import dagger.hilt.android.AndroidEntryPoint @@ -64,18 +63,17 @@ class MyReviewBottomSheetFragment : BottomSheetDialogFragment() { Timber.d("넘겨받은 리뷰 정보: $reviewId $menu $content $reviewId") binding.llModify.setOnClickListener { - val intent = Intent(requireContext(), ModifyReviewActivity::class.java) - - intent.let { - it.putExtra("reviewId", reviewId) - it.putExtra("menu", menu) - it.putExtra("content", content) - it.putExtra("mainGrade", mainGrade) - it.putExtra("amountGrade", amountGrade) - it.putExtra("tasteGrade", tasteGrade) - } - - startActivity(intent) + ModifyReviewActivity.start( + requireContext(), + ModifyReviewActivity.Args( + reviewId = reviewId, + menu = menu, + content = content, + mainGrade = mainGrade, + amountGrade = amountGrade, + tasteGrade = tasteGrade + ) + ) dismiss() } From b6f4318a72089bb3b97b6fa64515a43f672ea2b5 Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:45:36 +0900 Subject: [PATCH 19/23] =?UTF-8?q?refactor:=20ReviewActivity=20=EC=83=88=20?= =?UTF-8?q?Intent=20=EA=B5=AC=EC=A1=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cafeteria/menu/MenuSubAdapter.kt | 34 ++++------- .../cafeteria/review/list/ReviewActivity.kt | 56 ++++++++++--------- 2 files changed, 43 insertions(+), 47 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/cafeteria/menu/MenuSubAdapter.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/menu/MenuSubAdapter.kt index ef2092677..b4ab78e81 100644 --- a/app/src/main/java/com/eatssu/android/presentation/cafeteria/menu/MenuSubAdapter.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/menu/MenuSubAdapter.kt @@ -1,17 +1,14 @@ package com.eatssu.android.presentation.cafeteria.menu -import android.content.Intent -import android.util.Log import android.view.LayoutInflater import android.view.ViewGroup -import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import com.eatssu.android.databinding.ItemMenuBinding import com.eatssu.android.domain.model.Menu import com.eatssu.android.presentation.cafeteria.review.list.ReviewActivity import com.eatssu.common.EventLogger -import com.eatssu.common.enums.MenuType import com.eatssu.common.enums.Restaurant +import timber.log.Timber class MenuSubAdapter( @@ -47,24 +44,17 @@ class MenuSubAdapter( //intent 사용 holder.itemView.setOnClickListener { - val intent = Intent(holder.itemView.context, ReviewActivity::class.java) - - when (restaurant.menuType) { - MenuType.FIXED -> { - Log.d("SubMenuAdapter", "고정메뉴${dataList[position].name}") - intent.putExtra("itemId", dataList[position].id) - intent.putExtra("itemName", dataList[position].name) - intent.putExtra("menuType", MenuType.FIXED.toString()) - } - - MenuType.VARIABLE -> { - Log.d("SubMenuAdapter", "변동메뉴${dataList[position].name}") - intent.putExtra("itemId", dataList[position].id) - intent.putExtra("itemName", dataList[position].name) - intent.putExtra("menuType", MenuType.VARIABLE.toString()) - } - } - ContextCompat.startActivity(holder.itemView.context, intent, null) + val menuType = restaurant.menuType.toString() + Timber.d("SubMenuAdapter - ${restaurant.menuType}메뉴${dataList[position].name}") + + ReviewActivity.start( + holder.itemView.context, + ReviewActivity.Args( + menuType = menuType, + itemId = dataList[position].id, + itemName = dataList[position].name + ) + ) EventLogger.clickMenu(restaurant) } } diff --git a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/list/ReviewActivity.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/list/ReviewActivity.kt index f6f6f38a5..f06c708b5 100644 --- a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/list/ReviewActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/list/ReviewActivity.kt @@ -1,7 +1,7 @@ package com.eatssu.android.presentation.cafeteria.review.list -import android.content.Intent import android.os.Bundle +import android.os.Parcelable import android.view.View import androidx.activity.viewModels import androidx.fragment.app.DialogFragment @@ -10,6 +10,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.eatssu.android.R import com.eatssu.android.databinding.ActivityReviewBinding import com.eatssu.android.domain.model.Review +import com.eatssu.android.presentation.base.ActivityCompanionWithArgs import com.eatssu.android.presentation.base.BaseActivity import com.eatssu.android.presentation.cafeteria.review.write.ReviewWriteRateActivity import com.eatssu.android.presentation.cafeteria.review.write.menu.ReviewWriteMenuActivity @@ -21,26 +22,34 @@ import com.eatssu.common.enums.ScreenId import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import kotlinx.parcelize.Parcelize import timber.log.Timber -import kotlin.properties.Delegates @AndroidEntryPoint class ReviewActivity : BaseActivity(ActivityReviewBinding::inflate, ScreenId.REVIEW_V1_VIEW), MyReviewBottomSheetFragment.OnReviewDeletedListener { - private val reviewViewModel: ReviewViewModel by viewModels() + @Parcelize + data class Args( + val menuType: String, + val itemId: Long, + val itemName: String + ) : Parcelable + + companion object : ActivityCompanionWithArgs(ReviewActivity::class, Args::class) - private lateinit var menuType: String - private var itemId by Delegates.notNull() + private val reviewViewModel: ReviewViewModel by viewModels() - private lateinit var itemName: String + private val menuType by lazy { intentOptions?.menuType ?: "" } + private val itemId by lazy { intentOptions?.itemId ?: 0 } + private val itemName by lazy { intentOptions?.itemName?.replace(Regex("[\\[\\]]"), "") ?: "" } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) toolbarTitle.text = "리뷰" // 툴바 제목 설정 - getIndex() + Timber.d("메뉴는 $itemName $menuType $itemId") lodeData() bindData() setClickListener() @@ -56,15 +65,6 @@ class ReviewActivity : } - private fun getIndex() { - //get menuId - menuType = intent.getStringExtra("menuType").toString() - itemId = intent.getLongExtra("itemId", 0) - itemName = intent.getStringExtra("itemName").toString().replace(Regex("[\\[\\]]"), "") - - Timber.d("메뉴는 $itemName $menuType $itemId") - } - private fun lodeData() { //Todo 여기서는 메뉴 타입이 뭔지 몰라도 됨. 추상화 해도 됨 @@ -150,21 +150,27 @@ class ReviewActivity : when (menuType) { MenuType.FIXED.name -> { binding.btnNextReview.setOnClickListener { - val intent = Intent(this, ReviewWriteRateActivity::class.java) - intent.putExtra("itemId", itemId) - intent.putExtra("itemName", itemName) - intent.putExtra("menuType", menuType) - startActivity(intent) + ReviewWriteRateActivity.start( + this, + ReviewWriteRateActivity.Args( + itemName = itemName, + itemId = itemId, + menuType = menuType + ) + ) EventLogger.writeReview() } } MenuType.VARIABLE.name -> { binding.btnNextReview.setOnClickListener { - val intent = Intent(this, ReviewWriteMenuActivity::class.java) - intent.putExtra("itemId", itemId) - intent.putExtra("menuType", menuType) - startActivity(intent) + ReviewWriteMenuActivity.start( + this, + ReviewWriteMenuActivity.Args( + itemId = itemId, + menuType = menuType + ) + ) EventLogger.writeReview() } } From 20db1c52f62b221692fe64572f25a8116a7dc2bc Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:46:25 +0900 Subject: [PATCH 20/23] =?UTF-8?q?refactor:=20ReviewWriteRateActivity=20?= =?UTF-8?q?=EC=83=88=20Intent=20=EA=B5=AC=EC=A1=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../review/write/ReviewWriteRateActivity.kt | 23 ++++++++---- .../write/menu/ReviewWriteMenuActivity.kt | 36 +++++++++++-------- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/ReviewWriteRateActivity.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/ReviewWriteRateActivity.kt index 53dc53a0b..ccdde25b6 100644 --- a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/ReviewWriteRateActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/ReviewWriteRateActivity.kt @@ -2,6 +2,7 @@ package com.eatssu.android.presentation.cafeteria.review.write import android.net.Uri import android.os.Bundle +import android.os.Parcelable import android.text.Editable import android.text.TextWatcher import android.view.View @@ -18,6 +19,7 @@ import com.eatssu.android.data.dto.request.WriteReviewRequest import com.eatssu.android.databinding.ActivityReviewWriteRateBinding import com.eatssu.android.presentation.UiEvent import com.eatssu.android.presentation.UiState +import com.eatssu.android.presentation.base.ActivityCompanionWithArgs import com.eatssu.android.presentation.base.BaseActivity import com.eatssu.android.presentation.util.showToast import com.eatssu.common.EventLogger @@ -25,6 +27,7 @@ import com.eatssu.common.enums.ScreenId import dagger.hilt.android.AndroidEntryPoint import id.zelory.compressor.Compressor import kotlinx.coroutines.launch +import kotlinx.parcelize.Parcelize import timber.log.Timber import java.io.File @@ -35,11 +38,21 @@ class ReviewWriteRateActivity : ScreenId.REVIEW_V1_WRITE_RATE ) { + @Parcelize + data class Args( + val itemName: String, + val itemId: Long, + val itemCount: Long = 1L, + val menuType: String? = null + ) : Parcelable + + companion object : ActivityCompanionWithArgs(ReviewWriteRateActivity::class, Args::class) + private val viewModel: UploadReviewViewModel by viewModels() - private var itemId: Long = 0 - private lateinit var itemName: String - private var itemCount = 1L + private val itemId by lazy { intentOptions?.itemId ?: -1L } + private val itemName by lazy { intentOptions?.itemName ?: "" } + private val itemCount by lazy { intentOptions?.itemCount ?: 1L } private var comment: String? = "" private var imageFile: File? = null @@ -49,12 +62,8 @@ class ReviewWriteRateActivity : toolbarTitle.text = "리뷰 남기기" // 툴바 제목 설정 binding.viewModel = viewModel - itemName = intent.getStringExtra("itemName").toString() Timber.d("고정메뉴 $itemName") - itemId = intent.getLongExtra("itemId", -1) - itemCount = intent.getLongExtra("itemCount", 1) - // 현재 메뉴명을 표시합니다. binding.menu.text = itemName diff --git a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/menu/ReviewWriteMenuActivity.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/menu/ReviewWriteMenuActivity.kt index a1267f073..2e264867f 100644 --- a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/menu/ReviewWriteMenuActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/menu/ReviewWriteMenuActivity.kt @@ -1,17 +1,19 @@ package com.eatssu.android.presentation.cafeteria.review.write.menu -import android.content.Intent import android.os.Bundle +import android.os.Parcelable import androidx.activity.viewModels import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import com.eatssu.android.databinding.ActivityReviewWriteMenuBinding +import com.eatssu.android.presentation.base.ActivityCompanionWithArgs import com.eatssu.android.presentation.base.BaseActivity import com.eatssu.android.presentation.cafeteria.review.write.ReviewWriteRateActivity import com.eatssu.common.enums.ScreenId import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import kotlinx.parcelize.Parcelize import timber.log.Timber @AndroidEntryPoint @@ -21,8 +23,16 @@ class ReviewWriteMenuActivity : ScreenId.REVIEW_V1_WRITE ) { + @Parcelize + data class Args( + val itemId: Long, + val menuType: String? = null + ) : Parcelable + + companion object : ActivityCompanionWithArgs(ReviewWriteMenuActivity::class, Args::class) + private val viewModel: VariableMenuViewModel by viewModels() - private var mealId: Long = -1 + private val mealId by lazy { intentOptions?.itemId ?: -1 } private lateinit var variableMenuPickAdapter: VariableMenuPickAdapter @@ -30,16 +40,11 @@ class ReviewWriteMenuActivity : super.onCreate(savedInstanceState) toolbarTitle.text = "리뷰 남기기" // 툴바 제목 설정 - getIndex() loadData() bindData() setClickListener() } - fun getIndex() { - mealId = intent.getLongExtra("itemId", -1) - } - fun loadData() { viewModel.findMenuItemByMealId(mealId) } @@ -76,14 +81,15 @@ class ReviewWriteMenuActivity : val currentItem = items[i] - // 다음 아이템을 전달하기 위해 Intent 생성 - val intent = Intent(this, ReviewWriteRateActivity::class.java) - intent.putExtra("itemName", currentItem.first) - intent.putExtra("itemId", currentItem.second) - intent.putExtra("itemCount", items.size.toLong()) - - // BActivity 실행 - startActivity(intent) + // 다음 아이템을 전달하기 위해 새로운 companion 패턴 사용 + ReviewWriteRateActivity.start( + this, + ReviewWriteRateActivity.Args( + itemName = currentItem.first, + itemId = currentItem.second, + itemCount = items.size.toLong() + ) + ) // 만약 마지막 아이템이면 현재 액티비티 종료 if (i == items.size - 1) { From dec1a514ffc6c2066e8e60e75384f2f4e2ac4151 Mon Sep 17 00:00:00 2001 From: PeraSite Date: Fri, 17 Oct 2025 17:57:50 +0900 Subject: [PATCH 21/23] =?UTF-8?q?refactor:=20type-safe=ED=95=9C=20Fragment?= =?UTF-8?q?=20arguments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/base/FragmentCompanion.kt | 36 +++++++++++++ .../cafeteria/review/list/ReviewActivity.kt | 37 +++++++------- .../common/MyReviewBottomSheetFragment.kt | 50 ++++++++++--------- .../common/OthersBottomSheetFragment.kt | 26 ++++++---- .../mypage/myreview/MyReviewListActivity.kt | 24 ++++----- 5 files changed, 111 insertions(+), 62 deletions(-) create mode 100644 app/src/main/java/com/eatssu/android/presentation/base/FragmentCompanion.kt diff --git a/app/src/main/java/com/eatssu/android/presentation/base/FragmentCompanion.kt b/app/src/main/java/com/eatssu/android/presentation/base/FragmentCompanion.kt new file mode 100644 index 000000000..f83d7fa86 --- /dev/null +++ b/app/src/main/java/com/eatssu/android/presentation/base/FragmentCompanion.kt @@ -0,0 +1,36 @@ +package com.eatssu.android.presentation.base + +import android.os.Bundle +import android.os.Parcelable +import androidx.core.os.BundleCompat +import androidx.fragment.app.Fragment +import kotlin.reflect.KClass + +private const val FRAGMENT_ARGS_KEY = "fragment_args" + +abstract class FragmentCompanion( + private val fragmentBuilder: () -> Fragment, +) { + fun newInstance(): Fragment { + return fragmentBuilder() + } +} + +abstract class FragmentCompanionWithArgs( + private val fragmentBuilder: () -> Fragment, + private val argsClass: KClass +) where TArgs : Parcelable { + + fun newInstance(args: TArgs): Fragment { + return fragmentBuilder().apply { + arguments = Bundle().apply { + putParcelable(FRAGMENT_ARGS_KEY, args) + } + } + } + + val Fragment.fragmentOptions: TArgs? + get() = arguments?.let { + BundleCompat.getParcelable(it, FRAGMENT_ARGS_KEY, argsClass.java) + } +} diff --git a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/list/ReviewActivity.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/list/ReviewActivity.kt index f06c708b5..0d1ee0390 100644 --- a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/list/ReviewActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/list/ReviewActivity.kt @@ -183,17 +183,18 @@ class ReviewActivity : fun onMyReviewClicked(review: Review) { - val modalBottomSheet = MyReviewBottomSheetFragment().apply { - arguments = Bundle().apply { - putLong("reviewId", review.reviewId) - putString("menu", review.menu) - putString("content", review.content) - putInt("mainGrade", review.mainGrade) - putInt("amountGrade", review.amountGrade) - putInt("tasteGrade", review.tasteGrade) - } - onReviewDeletedListener = this@ReviewActivity - } + val modalBottomSheet = MyReviewBottomSheetFragment.newInstance( + MyReviewBottomSheetFragment.Args( + reviewId = review.reviewId, + menu = review.menu, + content = review.content, + mainGrade = review.mainGrade, + amountGrade = review.amountGrade, + tasteGrade = review.tasteGrade + ) + ) as MyReviewBottomSheetFragment + + modalBottomSheet.onReviewDeletedListener = this@ReviewActivity modalBottomSheet.setStyle( DialogFragment.STYLE_NORMAL, R.style.RoundCornerBottomSheetDialogTheme @@ -202,17 +203,17 @@ class ReviewActivity : } fun onOthersReviewClicked(reviewData: Review) { - val modalBottomSheet = OthersBottomSheetFragment() + val modalBottomSheet = OthersBottomSheetFragment.newInstance( + OthersBottomSheetFragment.Args( + reviewId = reviewData.reviewId, + menu = reviewData.menu + ) + ) as OthersBottomSheetFragment + modalBottomSheet.setStyle( DialogFragment.STYLE_NORMAL, R.style.RoundCornerBottomSheetDialogTheme ) - - modalBottomSheet.arguments = Bundle().apply { - putLong("reviewId", reviewData.reviewId) - putString("menu", reviewData.menu) - } - modalBottomSheet.show(supportFragmentManager, "Open Bottom Sheet") } diff --git a/app/src/main/java/com/eatssu/android/presentation/common/MyReviewBottomSheetFragment.kt b/app/src/main/java/com/eatssu/android/presentation/common/MyReviewBottomSheetFragment.kt index 95ccd4b6f..196d9cf2c 100644 --- a/app/src/main/java/com/eatssu/android/presentation/common/MyReviewBottomSheetFragment.kt +++ b/app/src/main/java/com/eatssu/android/presentation/common/MyReviewBottomSheetFragment.kt @@ -1,6 +1,7 @@ package com.eatssu.android.presentation.common import android.os.Bundle +import android.os.Parcelable import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -10,6 +11,7 @@ import androidx.lifecycle.lifecycleScope import com.eatssu.android.App import com.eatssu.android.R import com.eatssu.android.databinding.FragmentBottomsheetMyReviewBinding +import com.eatssu.android.presentation.base.FragmentCompanionWithArgs import com.eatssu.android.presentation.cafeteria.review.modify.ModifyReviewActivity import com.eatssu.android.presentation.mypage.myreview.MyReviewViewModel import com.eatssu.android.presentation.util.showToast @@ -17,6 +19,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import kotlinx.parcelize.Parcelize import timber.log.Timber @AndroidEntryPoint @@ -24,6 +27,21 @@ class MyReviewBottomSheetFragment : BottomSheetDialogFragment() { private var _binding: FragmentBottomsheetMyReviewBinding? = null private val binding get() = _binding!! + @Parcelize + data class Args( + val reviewId: Long, + val menu: String, + val content: String, + val mainGrade: Int, + val amountGrade: Int, + val tasteGrade: Int + ) : Parcelable + + companion object : FragmentCompanionWithArgs( + ::MyReviewBottomSheetFragment, + Args::class + ) + interface OnReviewDeletedListener { fun onReviewDeleted() } @@ -32,13 +50,6 @@ class MyReviewBottomSheetFragment : BottomSheetDialogFragment() { private val viewModel: MyReviewViewModel by activityViewModels() - var reviewId = -1L - var menu = "" - var content = "" - var mainGrade = -1 - var amountGrade = -1 - var tasteGrade = -1 - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -51,27 +62,20 @@ class MyReviewBottomSheetFragment : BottomSheetDialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - arguments?.let { - reviewId = it.getLong("reviewId") - menu = it.getString("menu").toString() - content = it.getString("content").toString() - mainGrade = it.getInt("mainGrade") - amountGrade = it.getInt("amountGrade") - tasteGrade = it.getInt("tasteGrade") - } + val args = fragmentOptions ?: return - Timber.d("넘겨받은 리뷰 정보: $reviewId $menu $content $reviewId") + Timber.d("넘겨받은 리뷰 정보: ${args.reviewId} ${args.menu} ${args.content}") binding.llModify.setOnClickListener { ModifyReviewActivity.start( requireContext(), ModifyReviewActivity.Args( - reviewId = reviewId, - menu = menu, - content = content, - mainGrade = mainGrade, - amountGrade = amountGrade, - tasteGrade = tasteGrade + reviewId = args.reviewId, + menu = args.menu, + content = args.content, + mainGrade = args.mainGrade, + amountGrade = args.amountGrade, + tasteGrade = args.tasteGrade ) ) dismiss() @@ -85,7 +89,7 @@ class MyReviewBottomSheetFragment : BottomSheetDialogFragment() { activity?.showToast(App.appContext.getString(R.string.delete_undo)) } setPositiveButton("삭제") { _, _ -> - viewModel.deleteReview(reviewId) + viewModel.deleteReview(args.reviewId) lifecycleScope.launch { viewModel.uiState.collectLatest { if (it.isDeleted) { diff --git a/app/src/main/java/com/eatssu/android/presentation/common/OthersBottomSheetFragment.kt b/app/src/main/java/com/eatssu/android/presentation/common/OthersBottomSheetFragment.kt index 34837341e..8ebddef51 100644 --- a/app/src/main/java/com/eatssu/android/presentation/common/OthersBottomSheetFragment.kt +++ b/app/src/main/java/com/eatssu/android/presentation/common/OthersBottomSheetFragment.kt @@ -1,13 +1,16 @@ package com.eatssu.android.presentation.common import android.os.Bundle +import android.os.Parcelable import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.eatssu.android.databinding.FragmentBottomsheetOthersBinding +import com.eatssu.android.presentation.base.FragmentCompanionWithArgs import com.eatssu.android.presentation.cafeteria.review.report.ReportActivity import com.google.android.material.bottomsheet.BottomSheetDialogFragment import dagger.hilt.android.AndroidEntryPoint +import kotlinx.parcelize.Parcelize import timber.log.Timber @AndroidEntryPoint @@ -15,8 +18,16 @@ class OthersBottomSheetFragment : BottomSheetDialogFragment() { private var _binding: FragmentBottomsheetOthersBinding? = null private val binding get() = _binding!! - var reviewId = -1L - var menu = "" + @Parcelize + data class Args( + val reviewId: Long, + val menu: String + ) : Parcelable + + companion object : FragmentCompanionWithArgs( + ::OthersBottomSheetFragment, + Args::class + ) override fun onCreateView( inflater: LayoutInflater, @@ -30,18 +41,15 @@ class OthersBottomSheetFragment : BottomSheetDialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - arguments?.let { - reviewId = it.getLong("reviewId") - menu = it.getString("menu").toString() - } + val args = fragmentOptions ?: return - Timber.d("넘겨받은 리뷰 정보: $reviewId $menu") + Timber.d("넘겨받은 리뷰 정보: ${args.reviewId} ${args.menu}") binding.llReport.setOnClickListener { - Timber.d("reviewId $reviewId") + Timber.d("reviewId ${args.reviewId}") ReportActivity.start( requireContext(), - ReportActivity.Args(reviewId) + ReportActivity.Args(args.reviewId) ) dismiss() } diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewListActivity.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewListActivity.kt index a89ba63d8..95a2b3ac6 100644 --- a/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewListActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/myreview/MyReviewListActivity.kt @@ -84,18 +84,18 @@ class MyReviewListActivity : BaseActivity( } fun onMyReviewClicked(review: Review) { - - val modalBottomSheet = MyReviewBottomSheetFragment().apply { - arguments = Bundle().apply { - putLong("reviewId", review.reviewId) - putString("menu", review.menu) - putString("content", review.content) - putInt("mainGrade", review.mainGrade) - putInt("amountGrade", review.amountGrade) - putInt("tasteGrade", review.tasteGrade) - } - onReviewDeletedListener = this@MyReviewListActivity - } + val modalBottomSheet = MyReviewBottomSheetFragment.newInstance( + MyReviewBottomSheetFragment.Args( + reviewId = review.reviewId, + menu = review.menu, + content = review.content, + mainGrade = review.mainGrade, + amountGrade = review.amountGrade, + tasteGrade = review.tasteGrade + ) + ) as MyReviewBottomSheetFragment + + modalBottomSheet.onReviewDeletedListener = this@MyReviewListActivity modalBottomSheet.setStyle( DialogFragment.STYLE_NORMAL, R.style.RoundCornerBottomSheetDialogTheme From 5a127055b7db0e4acdab671a5072160b3ccb48b8 Mon Sep 17 00:00:00 2001 From: PeraSite Date: Mon, 20 Oct 2025 18:01:04 +0900 Subject: [PATCH 22/23] =?UTF-8?q?docs:=20ActivityCompanion,=20FragmentComp?= =?UTF-8?q?anion=20=EC=A3=BC=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/base/ActivityCompanion.kt | 135 ++++++++++++++++++ .../presentation/base/FragmentCompanion.kt | 62 ++++++++ 2 files changed, 197 insertions(+) diff --git a/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt b/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt index dc1c55b56..069d3fea8 100644 --- a/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt +++ b/app/src/main/java/com/eatssu/android/presentation/base/ActivityCompanion.kt @@ -9,25 +9,102 @@ import kotlin.reflect.KClass private const val INTENT_ARGS_KEY = "intent_args" +/** + * ActivityCompanion 패턴: Extra 정보가 필요한 Intent를 type-safe 하게 생성하고 한 가지 공통된 방법으로 Activity를 실행하기 위해 사용합니다. + * + * @see ActivityCompanion 인자가 없는 기본 타입 + * @see ActivityCompanionWithArgs 인자가 필요한 타입 + * @see ActivityCompanionWithArgsDefault 기본 인자를 제공하는 타입 + */ + +/** + * 인자가 없는 Activity를 위한 Companion 클래스 + * + * ## 사용 예시 + * ```kotlin + * class MainActivity : AppCompatActivity() { + * companion object : ActivityCompanion(MainActivity::class) + * } + * + * // 다른 곳에서 사용 + * MainActivity.start(context) + * val intent = MainActivity.intent(context) + * ``` + * + * @property activityClass 실행할 Activity의 KClass + */ abstract class ActivityCompanion( protected val activityClass: KClass, ) { + /** + * Intent를 생성합니다. + * + * @param context Context + * @param intentBuilder Intent에 추가 설정을 할 수 있는 람다 (예: flags 설정) + * @return 생성된 Intent + */ fun intent( context: Context, intentBuilder: Intent.() -> Unit = {} ): Intent = Intent(context, activityClass.java).apply { intentBuilder() } + /** + * Activity를 실행합니다. + * + * @param context Context + * @param intentBuilder Intent에 추가 설정을 할 수 있는 람다 + */ fun start(context: Context, intentBuilder: Intent.() -> Unit = {}) { context.startActivity(intent(context, intentBuilder)) } } +/** + * 타입 안전한 인자를 받는 Activity를 위한 Companion 클래스 + * Args 타입은 Activity 내에 선언해 DetailActivity.Args 처럼 사용하는 것을 권장합니다. + * 필요하다면 intentOptions의 필드를 lazy 프로퍼티로 감싸 사용하세요. + * + * ## 사용 예시 + * ```kotlin + * class DetailActivity : AppCompatActivity() { + * @Parcelize + * data class Args(val id: Int, val title: String) : Parcelable + * + * companion object : ActivityCompanionWithArgs( + * DetailActivity::class, + * Args::class + * ) + * + * private val args by lazy { intentOptions } + * + * override fun onCreate(savedInstanceState: Bundle?) { + * super.onCreate(savedInstanceState) + * val id = args?.id // type-safe하게 인자 접근 + * } + * } + * + * // 다른 곳에서 사용 + * DetailActivity.start(context, DetailActivity.Args(id = 1, title = "제목")) + * ``` + * + * @property activityClass 실행할 Activity의 KClass + * @property argsClass 인자로 전달할 Parcelable 데이터 클래스의 KClass + * @param TArgs Parcelable을 구현한 인자 타입 + */ abstract class ActivityCompanionWithArgs( protected val activityClass: KClass, protected val argsClass: KClass, ) where TArgs : Parcelable { + /** + * 타입 안전한 인자를 포함한 Intent를 생성합니다. + * + * @param context Context + * @param args Activity에 전달할 Parcelable 인자 + * @param intentBuilder Intent에 추가 설정을 할 수 있는 람다 + * @return 인자가 포함된 Intent + */ fun intent( context: Context, args: TArgs, intentBuilder: Intent.() -> Unit = {} ): Intent = Intent(context, activityClass.java).apply { @@ -35,22 +112,74 @@ abstract class ActivityCompanionWithArgs( intentBuilder() } + /** + * 타입 안전한 인자와 함께 Activity를 실행합니다. + * + * @param context Context + * @param args Activity에 전달할 Parcelable 인자 + * @param intentBuilder Intent에 추가 설정을 할 수 있는 람다 + */ fun start(context: Context, args: TArgs, intentBuilder: Intent.() -> Unit = {}) { context.startActivity(intent(context, args, intentBuilder)) } + /** + * Activity 내부에서 전달받은 인자를 타입 안전하게 꺼내는 확장 프로퍼티 + * + * 사용 예시: + * ```kotlin + * private val postId by lazy { intentOptions?.postId } + * ``` + */ val Activity.intentOptions: TArgs? get() = getParcelableExtra( this.intent, INTENT_ARGS_KEY, argsClass.java ) } +/** + * 커스텀 인자와 기본 인자가 필요한 Activity를 위한 Companion 클래스 + * + * ActivityCompanionWithArgs를 상속하여 기본 인자로 실행하는 오버로드를 추가로 제공합니다. + * - `start(context)` - 기본 인자로 실행 + * - `start(context, customArgs)` - 커스텀 인자로 실행 + * + * ## 사용 예시 + * ```kotlin + * class SettingsActivity : AppCompatActivity() { + * @Parcelize + * data class Args(val section: String = "general") : Parcelable + * + * companion object : ActivityCompanionWithArgsDefault( + * SettingsActivity::class, + * Args::class, + * { Args() } + * ) + * } + * + * // 기본 인자로 실행: SettingsArgs(section = "general") + * SettingsActivity.start(context) + * + * // 커스텀 인자로 실행: SettingsArgs(section = "privacy") + * SettingsActivity.start(context, SettingsActivity.Args(section = "privacy")) + * ``` + * + * @property defaultArgs Context를 받아 기본 인자를 생성하는 람다 + * @param TArgs Parcelable을 구현한 인자 타입 + */ abstract class ActivityCompanionWithArgsDefault( activityClass: KClass, argsClass: KClass, private val defaultArgs: (Context) -> TArgs, ) : ActivityCompanionWithArgs(activityClass, argsClass) where TArgs : Parcelable { + /** + * 기본 인자로 Intent를 생성합니다. + * + * @param context Context + * @param intentBuilder Intent에 추가 설정을 할 수 있는 람다 + * @return 기본 인자가 포함된 Intent + */ fun intent( context: Context, intentBuilder: Intent.() -> Unit = {} ): Intent = Intent(context, activityClass.java).apply { @@ -58,6 +187,12 @@ abstract class ActivityCompanionWithArgsDefault( intentBuilder() } + /** + * 기본 인자로 Activity를 실행합니다. + * + * @param context Context + * @param intentBuilder Intent에 추가 설정을 할 수 있는 람다 + */ fun start(context: Context, intentBuilder: Intent.() -> Unit = {}) { context.startActivity(intent(context, intentBuilder)) } diff --git a/app/src/main/java/com/eatssu/android/presentation/base/FragmentCompanion.kt b/app/src/main/java/com/eatssu/android/presentation/base/FragmentCompanion.kt index f83d7fa86..6557dd56a 100644 --- a/app/src/main/java/com/eatssu/android/presentation/base/FragmentCompanion.kt +++ b/app/src/main/java/com/eatssu/android/presentation/base/FragmentCompanion.kt @@ -8,6 +8,28 @@ import kotlin.reflect.KClass private const val FRAGMENT_ARGS_KEY = "fragment_args" +/** + * FragmentCompanion 패턴: Arguments 정보가 필요한 Fragment를 type-safe 하게 생성하고 한 가지 공통된 방법으로 인스턴스를 만들기 위해 사용합니다. + * + * @see FragmentCompanion 인자가 없는 기본 타입 + * @see FragmentCompanionWithArgs 인자가 필요한 타입 + */ + +/** + * 인자가 없는 Fragment를 위한 Companion 클래스 + * + * ## 사용 예시 + * ```kotlin + * class HomeFragment : Fragment() { + * companion object : FragmentCompanion(::HomeFragment) + * } + * + * // 다른 곳에서 사용 + * val fragment = HomeFragment.newInstance() + * ``` + * + * @property fragmentBuilder Fragment 인스턴스를 생성하는 람다 + */ abstract class FragmentCompanion( private val fragmentBuilder: () -> Fragment, ) { @@ -16,6 +38,38 @@ abstract class FragmentCompanion( } } +/** + * 타입 안전한 인자를 받는 Fragment를 위한 Companion 클래스 + * Args 타입은 Fragment 내에 선언해 DetailFragment.Args 처럼 사용하는 것을 권장합니다. + * 필요하다면 fragmentOptions의 필드를 lazy 프로퍼티로 감싸 사용하세요. + * + * ## 사용 예시 + * ```kotlin + * class DetailFragment : Fragment() { + * @Parcelize + * data class Args(val id: Int, val title: String) : Parcelable + * + * companion object : FragmentCompanionWithArgs( + * ::DetailFragment, + * Args::class + * ) + * + * private val args by lazy { fragmentOptions } + * + * override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + * super.onViewCreated(view, savedInstanceState) + * val id = args?.id // type-safe하게 인자 접근 + * } + * } + * + * // 다른 곳에서 사용 + * val fragment = DetailFragment.newInstance(DetailFragment.Args(id = 1, title = "제목")) + * ``` + * + * @property fragmentBuilder Fragment 인스턴스를 생성하는 람다 + * @property argsClass 인자로 전달할 Parcelable 데이터 클래스의 KClass + * @param TArgs Parcelable을 구현한 인자 타입 + */ abstract class FragmentCompanionWithArgs( private val fragmentBuilder: () -> Fragment, private val argsClass: KClass @@ -29,6 +83,14 @@ abstract class FragmentCompanionWithArgs( } } + /** + * Fragment 내부에서 전달받은 인자를 타입 안전하게 꺼내는 확장 프로퍼티 + * + * 사용 예시: + * ```kotlin + * private val postId by lazy { fragmentOptions?.postId } + * ``` + */ val Fragment.fragmentOptions: TArgs? get() = arguments?.let { BundleCompat.getParcelable(it, FRAGMENT_ARGS_KEY, argsClass.java) From 49eabf78281f705a41bb5433bee375c881ead1d3 Mon Sep 17 00:00:00 2001 From: PeraSite Date: Mon, 20 Oct 2025 18:02:15 +0900 Subject: [PATCH 23/23] =?UTF-8?q?feat:=20FragmentCompanionWithArgsDefault?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/base/FragmentCompanion.kt | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/app/src/main/java/com/eatssu/android/presentation/base/FragmentCompanion.kt b/app/src/main/java/com/eatssu/android/presentation/base/FragmentCompanion.kt index 6557dd56a..a436c9c45 100644 --- a/app/src/main/java/com/eatssu/android/presentation/base/FragmentCompanion.kt +++ b/app/src/main/java/com/eatssu/android/presentation/base/FragmentCompanion.kt @@ -96,3 +96,50 @@ abstract class FragmentCompanionWithArgs( BundleCompat.getParcelable(it, FRAGMENT_ARGS_KEY, argsClass.java) } } + +/** + * 커스텀 인자와 기본 인자가 필요한 Fragment를 위한 Companion 클래스 + * + * FragmentCompanionWithArgs를 상속하여 기본 인자로 실행하는 오버로드를 추가로 제공합니다. + * - `newInstance()` - 기본 인자로 생성 + * - `newInstance(customArgs)` - 커스텀 인자로 생성 + * + * ## 사용 예시 + * ```kotlin + * class SettingsFragment : Fragment() { + * @Parcelize + * data class Args(val section: String = "general") : Parcelable + * + * companion object : FragmentCompanionWithArgsDefault( + * ::SettingsFragment, + * Args::class, + * { Args() } + * ) + * } + * + * // 기본 인자로 생성: Args(section = "general") + * SettingsFragment.newInstance() + * + * // 커스텀 인자로 생성: Args(section = "privacy") + * SettingsFragment.newInstance(SettingsFragment.Args(section = "privacy")) + * ``` + * + * @property defaultArgs 기본 인자를 생성하는 람다 + * @param TArgs Parcelable을 구현한 인자 타입 + */ +abstract class FragmentCompanionWithArgsDefault( + fragmentBuilder: () -> Fragment, + argsClass: KClass, + private val defaultArgs: () -> TArgs, +) : FragmentCompanionWithArgs(fragmentBuilder, argsClass) where TArgs : Parcelable { + + /** + * 기본 인자로 Fragment의 새 인스턴스를 생성합니다. + * + * @return 기본 인자가 포함된 Fragment 인스턴스 + */ + fun newInstance(): Fragment { + return newInstance(defaultArgs()) + } + +}