diff --git a/presentation/src/debug/AndroidManifest.xml b/presentation/src/debug/AndroidManifest.xml
new file mode 100644
index 0000000..589b308
--- /dev/null
+++ b/presentation/src/debug/AndroidManifest.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/DebugMainActivity.kt b/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/DebugMainActivity.kt
new file mode 100644
index 0000000..2584afb
--- /dev/null
+++ b/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/DebugMainActivity.kt
@@ -0,0 +1,16 @@
+package com.ray.template.android.presentation.ui.main
+
+import android.os.Bundle
+import androidx.activity.compose.setContent
+import androidx.appcompat.app.AppCompatActivity
+import dagger.hilt.android.AndroidEntryPoint
+
+@AndroidEntryPoint
+class DebugMainActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContent {
+ DebugMainScreen()
+ }
+ }
+}
diff --git a/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/DebugMainScreen.kt b/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/DebugMainScreen.kt
new file mode 100644
index 0000000..dfd5586
--- /dev/null
+++ b/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/DebugMainScreen.kt
@@ -0,0 +1,81 @@
+package com.ray.template.android.presentation.ui.main
+
+import androidx.compose.foundation.gestures.detectDragGestures
+import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Icon
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableFloatStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color.Companion.Blue
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.IntOffset
+import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.navigation.NavController
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.rememberNavController
+import com.ray.template.android.presentation.R
+import com.ray.template.android.presentation.common.theme.Space40
+import com.ray.template.android.presentation.common.theme.TemplateTheme
+import com.ray.template.android.presentation.common.util.compose.ErrorObserver
+import com.ray.template.android.presentation.common.util.compose.safeNavigate
+import com.ray.template.android.presentation.common.view.RippleBox
+import com.ray.template.android.presentation.ui.main.debug.DebugConstant
+import com.ray.template.android.presentation.ui.main.debug.debugDestination
+import com.ray.template.android.presentation.ui.main.splash.SplashConstant
+import kotlin.math.roundToInt
+
+@Composable
+fun DebugMainScreen(
+ viewModel: MainViewModel = hiltViewModel()
+) {
+ TemplateTheme {
+ val navController = rememberNavController()
+
+ NavHost(
+ navController = navController,
+ startDestination = SplashConstant.ROUTE
+ ) {
+ mainDestination(navController)
+ debugDestination(navController)
+ }
+
+ ErrorObserver(viewModel)
+ MainScreenRefreshFailDialog(navController, viewModel.refreshFailEvent)
+ DebugPopup(navController)
+ }
+}
+
+@Composable
+private fun DebugPopup(
+ navController: NavController
+) {
+ var offsetX by remember { mutableFloatStateOf(0f) }
+ var offsetY by remember { mutableFloatStateOf(0f) }
+
+ RippleBox(
+ modifier = Modifier
+ .offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
+ .pointerInput(Unit) {
+ detectDragGestures { change, dragAmount ->
+ change.consume()
+ offsetX += dragAmount.x
+ offsetY += dragAmount.y
+ }
+ },
+ onClick = {
+ navController.safeNavigate(DebugConstant.ROUTE)
+ }
+ ) {
+ Icon(
+ modifier = Modifier.size(Space40),
+ painter = painterResource(R.drawable.ic_more_vertical),
+ contentDescription = null,
+ tint = Blue
+ )
+ }
+}
diff --git a/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/debug/DebugArgument.kt b/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/debug/DebugArgument.kt
new file mode 100644
index 0000000..a3b7ea6
--- /dev/null
+++ b/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/debug/DebugArgument.kt
@@ -0,0 +1,23 @@
+package com.ray.template.android.presentation.ui.main.debug
+
+import androidx.compose.runtime.Immutable
+import com.ray.template.android.common.util.coroutine.event.EventFlow
+import kotlinx.coroutines.CoroutineExceptionHandler
+
+@Immutable
+data class DebugArgument(
+ val state: DebugState,
+ val event: EventFlow,
+ val intent: (DebugIntent) -> Unit,
+ val logEvent: (eventName: String, params: Map) -> Unit,
+ val handler: CoroutineExceptionHandler
+)
+
+sealed interface DebugState {
+ data object Init : DebugState
+}
+
+
+sealed interface DebugEvent
+
+sealed interface DebugIntent
diff --git a/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/debug/DebugConstant.kt b/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/debug/DebugConstant.kt
new file mode 100644
index 0000000..e2e55a8
--- /dev/null
+++ b/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/debug/DebugConstant.kt
@@ -0,0 +1,5 @@
+package com.ray.template.android.presentation.ui.main.debug
+
+object DebugConstant {
+ const val ROUTE = "debug"
+}
diff --git a/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/debug/DebugDestination.kt b/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/debug/DebugDestination.kt
new file mode 100644
index 0000000..d04141b
--- /dev/null
+++ b/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/debug/DebugDestination.kt
@@ -0,0 +1,37 @@
+package com.ray.template.android.presentation.ui.main.debug
+
+import androidx.compose.runtime.getValue
+import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import androidx.navigation.NavController
+import androidx.navigation.NavGraphBuilder
+import androidx.navigation.compose.composable
+import com.ray.template.android.presentation.common.util.compose.ErrorObserver
+
+fun NavGraphBuilder.debugDestination(
+ navController: NavController
+) {
+ composable(
+ route = DebugConstant.ROUTE
+ ) {
+ val viewModel: DebugViewModel = hiltViewModel()
+
+ val argument: DebugArgument = let {
+ val state by viewModel.state.collectAsStateWithLifecycle()
+
+ DebugArgument(
+ state = state,
+ event = viewModel.event,
+ intent = viewModel::onIntent,
+ logEvent = viewModel::logEvent,
+ handler = viewModel.handler
+ )
+ }
+
+ ErrorObserver(viewModel)
+ DebugScreen(
+ navController = navController,
+ argument = argument
+ )
+ }
+}
diff --git a/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/debug/DebugScreen.kt b/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/debug/DebugScreen.kt
new file mode 100644
index 0000000..22882ea
--- /dev/null
+++ b/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/debug/DebugScreen.kt
@@ -0,0 +1,63 @@
+package com.ray.template.android.presentation.ui.main.debug
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.navigation.NavController
+import androidx.navigation.compose.rememberNavController
+import com.ray.template.android.common.util.coroutine.event.MutableEventFlow
+import com.ray.template.android.common.util.coroutine.event.eventObserve
+import com.ray.template.android.presentation.common.theme.Gray900
+import com.ray.template.android.presentation.common.theme.Headline0
+import com.ray.template.android.presentation.common.util.compose.LaunchedEffectWithLifecycle
+import kotlinx.coroutines.CoroutineExceptionHandler
+import kotlinx.coroutines.plus
+
+@Composable
+fun DebugScreen(
+ navController: NavController,
+ argument: DebugArgument,
+) {
+ val (state, event, intent, logEvent, handler) = argument
+ val scope = rememberCoroutineScope() + handler
+ val context = LocalContext.current
+
+ Column(
+ modifier = Modifier.fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+ Text(
+ text = "Debug Page",
+ style = Headline0.merge(Gray900)
+ )
+ }
+
+ LaunchedEffectWithLifecycle(event, handler) {
+ event.eventObserve { event ->
+
+ }
+ }
+}
+
+@Preview
+@Composable
+private fun DebugScreenPreview() {
+ DebugScreen(
+ navController = rememberNavController(),
+ argument = DebugArgument(
+ state = DebugState.Init,
+ event = MutableEventFlow(),
+ intent = {},
+ logEvent = { _, _ -> },
+ handler = CoroutineExceptionHandler { _, _ -> }
+ )
+ )
+}
diff --git a/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/debug/DebugViewModel.kt b/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/debug/DebugViewModel.kt
new file mode 100644
index 0000000..ce8ba6a
--- /dev/null
+++ b/presentation/src/debug/kotlin/com/ray/template/android/presentation/ui/main/debug/DebugViewModel.kt
@@ -0,0 +1,34 @@
+package com.ray.template.android.presentation.ui.main.debug
+
+import androidx.lifecycle.SavedStateHandle
+import com.ray.template.android.common.util.coroutine.event.EventFlow
+import com.ray.template.android.common.util.coroutine.event.MutableEventFlow
+import com.ray.template.android.common.util.coroutine.event.asEventFlow
+import com.ray.template.android.presentation.common.base.BaseViewModel
+import dagger.hilt.android.lifecycle.HiltViewModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+@HiltViewModel
+class DebugViewModel @Inject constructor(
+ private val savedStateHandle: SavedStateHandle
+) : BaseViewModel() {
+
+ private val _state: MutableStateFlow = MutableStateFlow(DebugState.Init)
+ val state: StateFlow = _state.asStateFlow()
+
+ private val _event: MutableEventFlow = MutableEventFlow()
+ val event: EventFlow = _event.asEventFlow()
+
+ init {
+ launch {
+
+ }
+ }
+
+ fun onIntent(intent: DebugIntent) {
+
+ }
+}
diff --git a/presentation/src/main/kotlin/com/ray/template/android/presentation/ui/main/MainDestination.kt b/presentation/src/main/kotlin/com/ray/template/android/presentation/ui/main/MainDestination.kt
new file mode 100644
index 0000000..ec1f0ea
--- /dev/null
+++ b/presentation/src/main/kotlin/com/ray/template/android/presentation/ui/main/MainDestination.kt
@@ -0,0 +1,15 @@
+package com.ray.template.android.presentation.ui.main
+
+import androidx.navigation.NavController
+import androidx.navigation.NavGraphBuilder
+import com.ray.template.android.presentation.ui.main.home.homeDestination
+import com.ray.template.android.presentation.ui.main.nonlogin.nonLoginNavGraphNavGraph
+import com.ray.template.android.presentation.ui.main.splash.splashDestination
+
+fun NavGraphBuilder.mainDestination(
+ navController: NavController
+) {
+ splashDestination(navController = navController)
+ nonLoginNavGraphNavGraph(navController = navController)
+ homeDestination(navController = navController)
+}
diff --git a/presentation/src/main/kotlin/com/ray/template/android/presentation/ui/main/MainScreen.kt b/presentation/src/main/kotlin/com/ray/template/android/presentation/ui/main/MainScreen.kt
index cec1def..794864a 100644
--- a/presentation/src/main/kotlin/com/ray/template/android/presentation/ui/main/MainScreen.kt
+++ b/presentation/src/main/kotlin/com/ray/template/android/presentation/ui/main/MainScreen.kt
@@ -18,10 +18,7 @@ import com.ray.template.android.presentation.common.util.compose.ErrorObserver
import com.ray.template.android.presentation.common.util.compose.LaunchedEffectWithLifecycle
import com.ray.template.android.presentation.common.util.compose.safeNavigate
import com.ray.template.android.presentation.common.view.DialogScreen
-import com.ray.template.android.presentation.ui.main.home.homeDestination
-import com.ray.template.android.presentation.ui.main.nonlogin.nonLoginNavGraphNavGraph
import com.ray.template.android.presentation.ui.main.splash.SplashConstant
-import com.ray.template.android.presentation.ui.main.splash.splashDestination
@Composable
fun MainScreen(
@@ -30,17 +27,15 @@ fun MainScreen(
TemplateTheme {
val navController = rememberNavController()
- ErrorObserver(viewModel)
- MainScreenRefreshFailDialog(navController, viewModel.refreshFailEvent)
-
NavHost(
navController = navController,
startDestination = SplashConstant.ROUTE
) {
- splashDestination(navController = navController)
- nonLoginNavGraphNavGraph(navController = navController)
- homeDestination(navController = navController)
+ mainDestination(navController)
}
+
+ ErrorObserver(viewModel)
+ MainScreenRefreshFailDialog(navController, viewModel.refreshFailEvent)
}
}