Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
95e1da5
refactor: IntroActivity 새로운 Intent 구조 적용
PeraSite Oct 17, 2025
ccea94a
chore: companion object private 변경, androidx.core.content.IntentCompa…
PeraSite Oct 17, 2025
76a1f20
feat: ActivityCompanion, ActivityCompanionWithArgs 분리
PeraSite Oct 17, 2025
7786e8e
refactor: WebViewActivity 새 Intent 구조 적용
PeraSite Oct 17, 2025
e54505f
refactor: ForceUpdateDialogActivity 새 Intent 구조 적용
PeraSite Oct 17, 2025
27029a2
refactor: LoginActivity 새 Intent 구조 적용
PeraSite Oct 17, 2025
c79d3d1
refactor: MainActivity 새 Intent 구조 적용
PeraSite Oct 17, 2025
f9373c6
chore: ActivityUtil.kt startActivity deprecate
PeraSite Oct 17, 2025
f3cbe9a
feat: 기본값으로 만들 수 있는 ActivityCompanionWithArgsDefault 추가
PeraSite Oct 17, 2025
2b05847
refactor: SignOutActivity 새 Intent 구조 적용
PeraSite Oct 17, 2025
9e2860d
refactor: WebViewActivity 호출 구조 변경
PeraSite Oct 17, 2025
07a00fa
refactor: DeveloperActivity 새 Intent 구조 적용
PeraSite Oct 17, 2025
6e96014
refactor: MyReviewListActivity 새 Intent 구조 적용
PeraSite Oct 17, 2025
a03b597
refactor: AndroidMessageDialogActivity 새 Intent 구조 적용
PeraSite Oct 17, 2025
a9a8bc9
chore: Default start 추가
PeraSite Oct 17, 2025
a096d62
refactor: UserInfoActivity 새 Intent 구조 적용
PeraSite Oct 17, 2025
18e60af
refactor: ReportActivity 새 Intent 구조 적용
PeraSite Oct 17, 2025
3371d2e
refactor: ModifyReviewActivity 새 Intent 구조 적용
PeraSite Oct 17, 2025
b6f4318
refactor: ReviewActivity 새 Intent 구조 적용
PeraSite Oct 17, 2025
20db1c5
refactor: ReviewWriteRateActivity 새 Intent 구조 적용
PeraSite Oct 17, 2025
dec1a51
refactor: type-safe한 Fragment arguments
PeraSite Oct 17, 2025
37ea8ea
Merge branch 'develop' into refactor/typesafe-intent
PeraSite Oct 20, 2025
5a12705
docs: ActivityCompanion, FragmentCompanion 주석 추가
PeraSite Oct 20, 2025
49eabf7
feat: FragmentCompanionWithArgsDefault 추가
PeraSite Oct 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.Args(REMOTE_NOTIFICATION)) {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -39,14 +40,17 @@ class NotificationReceiver : BroadcastReceiver() {
notificationManager.createNotificationChannel(channel)


val intent = Intent(context, IntroActivity::class.java).apply {
val intent = IntroActivity.intent(
context,
IntroActivity.Args(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
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ 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
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
Expand All @@ -38,6 +38,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>(
ScreenId.HOME_MAIN
) {

companion object : ActivityCompanion(MainActivity::class)

@Inject
lateinit var workManager: WorkManager

Expand Down Expand Up @@ -149,12 +151,14 @@ class MainActivity : BaseActivity<ActivityMainBinding>(
if (state is UiState.Success) {
when (state.data) {
is MainState.NicknameNull -> {
intent.putExtra("force", true)
startActivity<UserInfoActivity>()
UserInfoActivity.start(
this@MainActivity,
UserInfoActivity.Args(force = true)
)
}

is MainState.LoggedOut -> {
startActivity<LoginActivity>()
LoginActivity.start(this@MainActivity)
finishAffinity()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
package com.eatssu.android.presentation.base

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Parcelable
import androidx.core.content.IntentCompat.getParcelableExtra
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<out Activity>,
) {
/**
* 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<Args>(
* 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<TArgs>(
protected val activityClass: KClass<out Activity>,
protected val argsClass: KClass<TArgs>,
) 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 {
putExtra(INTENT_ARGS_KEY, args)
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<Args>(
* 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<TArgs>(
activityClass: KClass<out Activity>,
argsClass: KClass<TArgs>,
private val defaultArgs: (Context) -> TArgs,
) : ActivityCompanionWithArgs<TArgs>(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 {
putExtra(INTENT_ARGS_KEY, defaultArgs(context))
intentBuilder()
}

/**
* 기본 인자로 Activity를 실행합니다.
*
* @param context Context
* @param intentBuilder Intent에 추가 설정을 할 수 있는 람다
*/
fun start(context: Context, intentBuilder: Intent.() -> Unit = {}) {
context.startActivity(intent(context, intentBuilder))
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ abstract class BaseActivity<B : ViewBinding>(
}

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()
}

Expand Down Expand Up @@ -169,8 +169,7 @@ abstract class BaseActivity<B : ViewBinding>(
}

private fun showForceUpdateDialog() {
val intent = Intent(this, ForceUpdateDialogActivity::class.java)
startActivity(intent)
ForceUpdateDialogActivity.start(this)
}

override fun onResume() {
Expand Down
Loading