diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 7cc318e..eb1c9cf 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -3,11 +3,11 @@ import java.util.Properties
plugins {
// 커스텀 플러그인 적용
id("barrion.android.application")
- id("barrion.android.application.compose") // 새로운 Compose 플러그인 사용
- id("org.jetbrains.kotlin.plugin.compose") // Compose 컴파일러 플러그인 추가
- id("barrion.hilt") // 의존성 주입
- id("barrion.network") // 네트워킹
- id("barrion.imageloading") // 이미지 로딩
+ id("barrion.android.application.compose")
+ id("org.jetbrains.kotlin.plugin.compose")
+ id("barrion.hilt")
+ id("barrion.network")
+ id("barrion.imageloading")
}
val properties =
@@ -24,13 +24,21 @@ android {
targetSdk = 34
versionCode = 1
versionName = "1.0"
+
+ // 리소스 최적화 설정
+ resourceConfigurations.addAll(listOf("en", "ko"))
}
+
+ // 동적 기능 모듈 관련 설정 추가
+ // 온보딩 모듈이 동적 기능 모듈로 구성되어 있다면 사용
+ // dynamicFeatures += setOf(":feature:onboarding")
+
buildFeatures {
compose = true
}
composeOptions {
- kotlinCompilerExtensionVersion = "1.5.10" // libs.versions.toml에 정의된 값 또는 직접 명시
+ kotlinCompilerExtensionVersion = "1.5.10"
}
buildTypes {
@@ -43,16 +51,15 @@ android {
}
}
- // Java 버전 오버라이드 (플러그인에서 17 사용, 앱에서 11로 변경)
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
+
kotlinOptions {
jvmTarget = "11"
}
- // 빌드 기능 설정 (필요한 경우)
buildFeatures {
viewBinding = true
dataBinding = true
@@ -61,17 +68,21 @@ android {
}
dependencies {
- // 앱 특화 의존성만 추가 (플러그인에서 처리하지 않는 의존성)
+ // 기존 의존성 유지
+ implementation(project(":core:ui"))
+ implementation(project(":presentation"))
+ implementation(project(":feature:onboarding"))
+
+ implementation("androidx.core:core-splashscreen:1.0.1")
+ implementation("androidx.navigation:navigation-compose:2.7.5")
implementation(libs.balloon)
implementation(libs.core.splashscreen)
- // 테스트 의존성 (테스트 플러그인이 없는 경우)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
}
-
//import java.util.Properties
//
//plugins {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 6fc3779..fcbf187 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools">
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png
new file mode 100644
index 0000000..061c585
Binary files /dev/null and b/app/src/main/ic_launcher-playstore.png differ
diff --git a/app/src/main/java/com/example/barrion/BarrionApplication.kt b/app/src/main/java/com/example/barrion/BarrionApplication.kt
new file mode 100644
index 0000000..5367e77
--- /dev/null
+++ b/app/src/main/java/com/example/barrion/BarrionApplication.kt
@@ -0,0 +1,19 @@
+// app/src/main/java/com/example/barrion/BarrionApplication.kt
+
+package com.example.barrion
+
+import android.app.Application
+import dagger.hilt.android.HiltAndroidApp
+
+/**
+ * 앱의 애플리케이션 클래스
+ * Hilt 의존성 주입을 위한 진입점 역할을 합니다.
+ *
+ * @HiltAndroidApp 어노테이션은 Hilt의 코드 생성을 트리거하고
+ * 애플리케이션 수준의 의존성 컨테이너를 생성합니다.
+ */
+@HiltAndroidApp
+class BarrionApplication : Application() {
+ // 앱 시작 시 초기화가 필요한 코드를 여기에 추가할 수 있습니다.
+ // 예: 로깅 설정, 크래시 리포팅 도구 초기화, 글로벌 설정 등
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/barrion/MainActivity.kt b/app/src/main/java/com/example/barrion/MainActivity.kt
index fe0aff2..2f7d4fb 100644
--- a/app/src/main/java/com/example/barrion/MainActivity.kt
+++ b/app/src/main/java/com/example/barrion/MainActivity.kt
@@ -1,50 +1,86 @@
+// app/src/main/java/com/example/barrion/MainActivity.kt
+
package com.example.barrion
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
+import androidx.activity.viewModels
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
+import androidx.compose.material3.Surface
import androidx.compose.ui.Modifier
-import androidx.compose.ui.tooling.preview.Preview
-import com.example.barrion.ui.theme.BarrionTheme
+import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
+import androidx.lifecycle.lifecycleScope
+import com.example.presentation.splash.SplashViewModel
+import androidx.navigation.compose.rememberNavController
+import com.example.barrion.navigation.BarrionNavHost
+import com.example.ui.theme.BarrionTheme
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.launch
+/**
+ * 앱의 메인 액티비티
+ * 앱의 시작점이며 Compose 기반 UI를 설정합니다.
+ *
+ * @AndroidEntryPoint 어노테이션은 Hilt의 의존성 주입을 이 액티비티에 적용합니다.
+ */
+@AndroidEntryPoint
class MainActivity : ComponentActivity() {
+
+ // Hilt를 통해 SplashViewModel 의존성 주입
+ private val viewModel: SplashViewModel by viewModels()
+
override fun onCreate(savedInstanceState: Bundle?) {
+ // 스플래시 스크린 설정 - Android 12+ 스플래시 화면 API 사용
+ val splashScreen = installSplashScreen()
+
+ // 뷰모델의 초기화 상태에 따라 스플래시 화면 표시 시간 조절
+ // isInitialized.value가 true가 될 때까지 스플래시 화면 유지
+ splashScreen.setKeepOnScreenCondition {
+ !viewModel.isInitialized.value
+ }
+
super.onCreate(savedInstanceState)
+
+ // 엣지투엣지 디스플레이 활성화 - 전체 화면 사용
enableEdgeToEdge()
+
+ // 앱 초기화 상태 관찰 및 처리
+ lifecycleScope.launch {
+ // 뷰모델의 초기화 상태를 관찰하여 필요한 작업 수행
+ viewModel.isInitialized.collectLatest { isInitialized ->
+ if (isInitialized) {
+ // 초기화가 완료된 후 수행할 작업
+ // 예: 로그인 상태 확인, 데이터 프리로드 등
+ }
+ }
+ }
+
+ // Compose UI 설정
setContent {
+ // 앱의 테마 적용
BarrionTheme {
- Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
- Greeting(
- name = "A222",
- modifier = Modifier.padding(innerPadding),
- )
+ // 스캐폴드를 사용하여 기본 레이아웃 구성
+ Scaffold { innerPadding ->
+ Surface(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(innerPadding),
+ color = MaterialTheme.colorScheme.background
+ ) {
+ // 네비게이션 컨트롤러 생성
+ val navController = rememberNavController()
+
+ // 앱의 메인 네비게이션 설정
+ BarrionNavHost(navController = navController)
+ }
}
}
}
}
-}
-
-@Composable
-fun Greeting(
- name: String,
- modifier: Modifier = Modifier,
-) {
- Text(
- text = "Hello $name!",
- modifier = modifier,
- )
-}
-
-@Preview(showBackground = true)
-@Composable
-fun GreetingPreview() {
- BarrionTheme {
- Greeting("Android")
- }
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/barrion/navigation/BarrionNavHost.kt b/app/src/main/java/com/example/barrion/navigation/BarrionNavHost.kt
new file mode 100644
index 0000000..1a56b91
--- /dev/null
+++ b/app/src/main/java/com/example/barrion/navigation/BarrionNavHost.kt
@@ -0,0 +1,89 @@
+// app/src/main/java/com/example/barrion/navigation/BarrionNavHost.kt
+
+package com.example.barrion.navigation
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.composable
+import com.example.onboarding.presentation.OnboardingScreen
+
+/**
+ * 앱의 메인 네비게이션 호스트
+ * 모든 화면 간의 이동을 관리합니다.
+ *
+ * @param navController 화면 전환을 위한 네비게이션 컨트롤러
+ */
+@Composable
+fun BarrionNavHost(navController: NavHostController) {
+ // 앱의 모든 화면 간 네비게이션을 설정
+ NavHost(
+ navController = navController,
+ startDestination = NavRoutes.Onboarding.route // 시작 화면을 온보딩으로 설정
+ ) {
+ // 온보딩 화면 라우트
+ composable(route = NavRoutes.Onboarding.route) {
+ OnboardingScreen(
+ onNavigateToHome = {
+ // 홈 화면으로 이동하면서 온보딩 화면은 백스택에서 제거
+ navController.navigate(NavRoutes.Home.route) {
+ popUpTo(NavRoutes.Onboarding.route) { inclusive = true }
+ }
+ }
+ )
+ }
+
+ // 홈 화면 라우트 (메뉴 관리 화면)
+ composable(route = NavRoutes.Home.route) {
+ // 현재 구현 예정인 화면 - 구현 후 주석 해제
+ // MenuScreen(
+ // onNavigateToOrder = { navController.navigate(NavRoutes.Order.route) },
+ // onNavigateToSales = { navController.navigate(NavRoutes.Sales.route) },
+ // onNavigateToStaff = { navController.navigate(NavRoutes.Staff.route) }
+ // )
+
+ // 임시로 개발 중 메시지 표시
+ Box(
+ modifier = Modifier.fillMaxSize(),
+ contentAlignment = Alignment.Center
+ ) {
+ Text(
+ text = "앱 개발 중...",
+ style = MaterialTheme.typography.headlineMedium
+ )
+ }
+ }
+
+ // 주문 관리 화면 라우트
+ composable(route = NavRoutes.Order.route) {
+ // 현재 구현 예정인 화면 - 구현 후 주석 해제
+ // OrderScreen(
+ // onNavigateBack = { navController.popBackStack() }
+ // )
+ }
+
+ // 매출 화면 라우트
+ composable(route = NavRoutes.Sales.route) {
+ // 현재 구현 예정인 화면 - 구현 후 주석 해제
+ // SalesScreen(
+ // onNavigateBack = { navController.popBackStack() }
+ // )
+ }
+
+ // 직원 관리 화면 라우트
+ composable(route = NavRoutes.Staff.route) {
+ // 현재 구현 예정인 화면 - 구현 후 주석 해제
+ // StaffScreen(
+ // onNavigateBack = { navController.popBackStack() }
+ // )
+ }
+
+ // 추가 화면들..
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/barrion/navigation/NavRoutes.kt b/app/src/main/java/com/example/barrion/navigation/NavRoutes.kt
new file mode 100644
index 0000000..676d908
--- /dev/null
+++ b/app/src/main/java/com/example/barrion/navigation/NavRoutes.kt
@@ -0,0 +1,55 @@
+// app/src/main/java/com/example/barrion/navigation/NavRoutes.kt
+
+package com.example.barrion.navigation
+
+/**
+ * 앱의 네비게이션 경로를 정의하는 sealed class
+ * 모든 화면 경로를 한 곳에서 관리하여 일관성을 유지하고 오타를 방지합니다.
+ */
+sealed class NavRoutes(val route: String) {
+ /**
+ * 온보딩 화면 경로 - 앱 최초 실행 시 표시되는 화면
+ * 사용자 가이드 및 초기 설정을 포함합니다.
+ */
+ object Onboarding : NavRoutes("onboarding")
+
+ /**
+ * 홈 화면 경로 - 앱의 메인 화면
+ * 메뉴 관리 기능을 제공하는 화면입니다.
+ */
+ object Home : NavRoutes("home")
+
+ /**
+ * 주문 화면 경로 - 주문 관리 기능
+ * 주문 목록 확인, 주문 처리 등의 기능을 제공합니다.
+ */
+ object Order : NavRoutes("order")
+
+ /**
+ * 매출 화면 경로 - 매출 관리 및 통계
+ * 매출 현황, 통계, 리포트 등을 제공합니다.
+ */
+ object Sales : NavRoutes("sales")
+
+ /**
+ * 직원 관리 화면 경로 - 직원 정보 및 관리
+ * 직원 목록, 근태 관리, 권한 설정 등을 제공합니다.
+ */
+ object Staff : NavRoutes("staff")
+
+ // 파라미터가 있는 경로 예시:
+ // /**
+ // * 주문 상세 화면 경로 - 특정 주문의 상세 정보
+ // * {orderId} 파라미터를 통해 특정 주문 정보를 로드합니다.
+ // * 사용 예시: navController.navigate("order/12345")
+ // */
+ // object OrderDetail : NavRoutes("order/{orderId}")
+
+ // /**
+ // * URL에서 경로 파라미터를 추출하는 헬퍼 함수
+ // * 사용 예시: val orderId = OrderDetail.getOrderId(savedStateHandle)
+ // */
+ // fun getOrderId(savedStateHandle: SavedStateHandle): String {
+ // return checkNotNull(savedStateHandle["orderId"])
+ // }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/barrion/ui/theme/Color.kt b/app/src/main/java/com/example/barrion/ui/theme/Color.kt
deleted file mode 100644
index c450ded..0000000
--- a/app/src/main/java/com/example/barrion/ui/theme/Color.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.example.barrion.ui.theme
-
-import androidx.compose.ui.graphics.Color
-
-val Purple80 = Color(0xFFD0BCFF)
-val PurpleGrey80 = Color(0xFFCCC2DC)
-val Pink80 = Color(0xFFEFB8C8)
-
-val Purple40 = Color(0xFF6650a4)
-val PurpleGrey40 = Color(0xFF625b71)
-val Pink40 = Color(0xFF7D5260)
diff --git a/app/src/main/java/com/example/barrion/ui/theme/Theme.kt b/app/src/main/java/com/example/barrion/ui/theme/Theme.kt
deleted file mode 100644
index 48e023b..0000000
--- a/app/src/main/java/com/example/barrion/ui/theme/Theme.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.example.barrion.ui.theme
-
-import android.os.Build
-import androidx.compose.foundation.isSystemInDarkTheme
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.darkColorScheme
-import androidx.compose.material3.dynamicDarkColorScheme
-import androidx.compose.material3.dynamicLightColorScheme
-import androidx.compose.material3.lightColorScheme
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.platform.LocalContext
-
-private val DarkColorScheme =
- darkColorScheme(
- primary = Purple80,
- secondary = PurpleGrey80,
- tertiary = Pink80,
- )
-
-private val LightColorScheme =
- lightColorScheme(
- primary = Purple40,
- secondary = PurpleGrey40,
- tertiary = Pink40,
- /* Other default colors to override
- background = Color(0xFFFFFBFE),
- surface = Color(0xFFFFFBFE),
- onPrimary = Color.White,
- onSecondary = Color.White,
- onTertiary = Color.White,
- onBackground = Color(0xFF1C1B1F),
- onSurface = Color(0xFF1C1B1F),
- */
- )
-
-@Composable
-fun BarrionTheme(
- darkTheme: Boolean = isSystemInDarkTheme(),
- // Dynamic color is available on Android 12+
- dynamicColor: Boolean = true,
- content: @Composable () -> Unit,
-) {
- val colorScheme =
- when {
- dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
- val context = LocalContext.current
- if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
- }
-
- darkTheme -> DarkColorScheme
- else -> LightColorScheme
- }
-
- MaterialTheme(
- colorScheme = colorScheme,
- typography = Typography,
- content = content,
- )
-}
diff --git a/app/src/main/java/com/example/barrion/ui/theme/Type.kt b/app/src/main/java/com/example/barrion/ui/theme/Type.kt
deleted file mode 100644
index 15523d4..0000000
--- a/app/src/main/java/com/example/barrion/ui/theme/Type.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.example.barrion.ui.theme
-
-import androidx.compose.material3.Typography
-import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.font.FontFamily
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.unit.sp
-
-// Set of Material typography styles to start with
-val Typography =
- Typography(
- bodyLarge =
- TextStyle(
- fontFamily = FontFamily.Default,
- fontWeight = FontWeight.Normal,
- fontSize = 16.sp,
- lineHeight = 24.sp,
- letterSpacing = 0.5.sp,
- ),
- /* Other default text styles to override
- titleLarge = TextStyle(
- fontFamily = FontFamily.Default,
- fontWeight = FontWeight.Normal,
- fontSize = 22.sp,
- lineHeight = 28.sp,
- letterSpacing = 0.sp
- ),
- labelSmall = TextStyle(
- fontFamily = FontFamily.Default,
- fontWeight = FontWeight.Medium,
- fontSize = 11.sp,
- lineHeight = 16.sp,
- letterSpacing = 0.5.sp
- )
- */
- )
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
deleted file mode 100644
index 2b068d1..0000000
--- a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..ec320dd
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
index 6f3b755..7353dbd 100644
--- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
index 6f3b755..7353dbd 100644
--- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp
index c209e78..33c45d8 100644
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.webp and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
index b2dfe3d..d4623b7 100644
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp
index 4f0f1d6..a80fae6 100644
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.webp and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
index 62b611d..20aaaf8 100644
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
index 948a307..264eede 100644
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
index 1b9a695..4f49b7f 100644
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
index 28d4b77..bae0255 100644
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
index 9287f50..e4f5793 100644
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
index aa7d642..e11fda8 100644
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
index 9126ae3..3d4931b 100644
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index f8c6127..795cdcf 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -7,4 +7,6 @@
#FF018786
#FF000000
#FFFFFFFF
+
+ #2142FF
\ No newline at end of file
diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml
new file mode 100644
index 0000000..aff99b4
--- /dev/null
+++ b/app/src/main/res/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+
+
+ #2142FF
+
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 9184aef..503c841 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -1,5 +1,22 @@
-
+
+
+
-
+
+
\ No newline at end of file
diff --git a/core/common/src/main/java/com/example/common/MyClass.kt b/core/common/src/main/java/com/example/common/MyClass.kt
deleted file mode 100644
index f4eec00..0000000
--- a/core/common/src/main/java/com/example/common/MyClass.kt
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.example.common
-
-class MyClass {
-}
\ No newline at end of file
diff --git a/core/ui/src/main/java/com/example/ui/components/buttons/BarrionActionButtons.kt b/core/ui/src/main/java/com/example/ui/components/buttons/BarrionActionButtons.kt
new file mode 100644
index 0000000..b30d282
--- /dev/null
+++ b/core/ui/src/main/java/com/example/ui/components/buttons/BarrionActionButtons.kt
@@ -0,0 +1,261 @@
+// core/ui/src/main/java/com/example/ui/components/buttons/BarrionActionButtons.kt
+package com.example.ui.components.buttons
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.OutlinedButton
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import com.example.ui.theme.barrionColors
+
+/**
+ * 장 버튼 - 전체 너비를 차지하는 기본 액션 버튼
+ *
+ * @param text 버튼에 표시할 텍스트
+ * @param onClick 버튼 클릭 시 실행될 콜백
+ * @param modifier 추가 Modifier (기본 크기: 너비 260dp, 높이 40dp)
+ * @param enabled 버튼 활성화 여부
+ */
+@Composable
+fun BarrionFullButton(
+ text: String,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true
+) {
+ Button(
+ onClick = onClick,
+ modifier = modifier
+ .width(260.dp)
+ .height(40.dp),
+ enabled = enabled,
+ shape = RoundedCornerShape(12.dp),
+ colors = ButtonDefaults.buttonColors(
+ containerColor = MaterialTheme.barrionColors.primaryBlue,
+ contentColor = MaterialTheme.barrionColors.white,
+ disabledContainerColor = MaterialTheme.barrionColors.grayMedium,
+ disabledContentColor = MaterialTheme.barrionColors.white
+ ),
+ contentPadding = PaddingValues(horizontal = 16.dp)
+ ) {
+ Text(
+ text = text,
+ style = MaterialTheme.typography.labelLarge,
+ textAlign = TextAlign.Center
+ )
+ }
+}
+
+/**
+ * 단 버튼 - 좌/우 버튼 쌍으로 구성된 네비게이션 버튼
+ *
+ * @param leftText 왼쪽 버튼에 표시할 텍스트
+ * @param rightText 오른쪽 버튼에 표시할 텍스트
+ * @param onLeftClick 왼쪽 버튼 클릭 시 실행될 콜백
+ * @param onRightClick 오른쪽 버튼 클릭 시 실행될 콜백
+ * @param rightEnabled 오른쪽 버튼 활성화 여부 (특정 조건 충족 여부)
+ * @param modifier 추가 Modifier
+ */
+@Composable
+fun BarrionNavigationButtons(
+ leftText: String,
+ rightText: String,
+ onLeftClick: () -> Unit,
+ onRightClick: () -> Unit,
+ rightEnabled: Boolean = true,
+ modifier: Modifier = Modifier
+) {
+ androidx.compose.foundation.layout.Row(
+ modifier = modifier.fillMaxWidth(),
+ horizontalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(8.dp)
+ ) {
+ // 왼쪽 버튼 (아웃라인 스타일)
+ OutlinedButton(
+ onClick = onLeftClick,
+ modifier = Modifier
+ .weight(1f)
+ .height(49.dp),
+ shape = RoundedCornerShape(12.dp),
+ border = BorderStroke(1.5.dp, MaterialTheme.barrionColors.primaryBlue),
+ colors = ButtonDefaults.outlinedButtonColors(
+ containerColor = MaterialTheme.barrionColors.white,
+ contentColor = MaterialTheme.barrionColors.primaryBlue
+ )
+ ) {
+ Text(
+ text = leftText,
+ style = MaterialTheme.typography.labelLarge,
+ textAlign = TextAlign.Center
+ )
+ }
+
+ // 오른쪽 버튼 (채워진 스타일)
+ Button(
+ onClick = onRightClick,
+ modifier = Modifier
+ .weight(1f)
+ .height(49.dp),
+ enabled = rightEnabled,
+ shape = RoundedCornerShape(12.dp),
+ colors = ButtonDefaults.buttonColors(
+ containerColor = MaterialTheme.barrionColors.primaryBlue,
+ contentColor = MaterialTheme.barrionColors.white,
+ disabledContainerColor = MaterialTheme.barrionColors.grayMedium,
+ disabledContentColor = MaterialTheme.barrionColors.white
+ )
+ ) {
+ Text(
+ text = rightText,
+ style = MaterialTheme.typography.labelLarge,
+ textAlign = TextAlign.Center
+ )
+ }
+ }
+}
+
+/**
+ * 단일 아웃라인 버튼 - 네비게이션 버튼 쌍의 왼쪽 스타일과 동일한 단일 버튼
+ *
+ * @param text 버튼에 표시할 텍스트
+ * @param onClick 버튼 클릭 시 실행될 콜백
+ * @param modifier 추가 Modifier
+ * @param enabled 버튼 활성화 여부
+ */
+@Composable
+fun BarrionOutlineActionButton(
+ text: String,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true
+) {
+ OutlinedButton(
+ onClick = onClick,
+ modifier = modifier
+ .width(157.dp)
+ .height(49.dp),
+ enabled = enabled,
+ shape = RoundedCornerShape(12.dp),
+ border = BorderStroke(1.5.dp, MaterialTheme.barrionColors.primaryBlue),
+ colors = ButtonDefaults.outlinedButtonColors(
+ containerColor = MaterialTheme.barrionColors.white,
+ contentColor = MaterialTheme.barrionColors.primaryBlue,
+ disabledContainerColor = MaterialTheme.barrionColors.white,
+ disabledContentColor = MaterialTheme.barrionColors.primaryBlue.copy(alpha = 0.5f)
+ )
+ ) {
+ Text(
+ text = text,
+ style = MaterialTheme.typography.labelLarge,
+ textAlign = TextAlign.Center
+ )
+ }
+}
+
+/**
+ * 단일 필드 버튼 - 네비게이션 버튼 쌍의 오른쪽 스타일과 동일한 단일 버튼
+ *
+ * @param text 버튼에 표시할 텍스트
+ * @param onClick 버튼 클릭 시 실행될 콜백
+ * @param modifier 추가 Modifier
+ * @param enabled 버튼 활성화 여부
+ */
+@Composable
+fun BarrionFilledActionButton(
+ text: String,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true
+) {
+ Button(
+ onClick = onClick,
+ modifier = modifier
+ .width(157.dp)
+ .height(49.dp),
+ enabled = enabled,
+ shape = RoundedCornerShape(12.dp),
+ colors = ButtonDefaults.buttonColors(
+ containerColor = MaterialTheme.barrionColors.primaryBlue,
+ contentColor = MaterialTheme.barrionColors.white,
+ disabledContainerColor = MaterialTheme.barrionColors.grayMedium,
+ disabledContentColor = MaterialTheme.barrionColors.white
+ )
+ ) {
+ Text(
+ text = text,
+ style = MaterialTheme.typography.labelLarge,
+ textAlign = TextAlign.Center
+ )
+ }
+}
+
+/**
+ * 알림 다이얼로그 버튼 쌍 - 이미지 5와 같은 다이얼로그에서 사용되는 버튼 쌍
+ *
+ * @param leftText 왼쪽 버튼에 표시할 텍스트 (예: "아니오")
+ * @param rightText 오른쪽 버튼에 표시할 텍스트 (예: "예")
+ * @param onLeftClick 왼쪽 버튼 클릭 시 실행될 콜백
+ * @param onRightClick 오른쪽 버튼 클릭 시 실행될 콜백
+ * @param modifier 추가 Modifier
+ */
+@Composable
+fun BarrionDialogButtons(
+ leftText: String,
+ rightText: String,
+ onLeftClick: () -> Unit,
+ onRightClick: () -> Unit,
+ modifier: Modifier = Modifier
+) {
+ androidx.compose.foundation.layout.Row(
+ modifier = modifier.fillMaxWidth(),
+ horizontalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(8.dp)
+ ) {
+ // 왼쪽 버튼 (아웃라인 스타일)
+ OutlinedButton(
+ onClick = onLeftClick,
+ modifier = Modifier
+ .weight(1f)
+ .height(49.dp),
+ shape = RoundedCornerShape(12.dp),
+ border = BorderStroke(1.5.dp, MaterialTheme.barrionColors.primaryBlue),
+ colors = ButtonDefaults.outlinedButtonColors(
+ containerColor = MaterialTheme.barrionColors.white,
+ contentColor = MaterialTheme.barrionColors.primaryBlue
+ )
+ ) {
+ Text(
+ text = leftText,
+ style = MaterialTheme.typography.labelLarge,
+ textAlign = TextAlign.Center
+ )
+ }
+
+ // 오른쪽 버튼 (채워진 스타일)
+ Button(
+ onClick = onRightClick,
+ modifier = Modifier
+ .weight(1f)
+ .height(49.dp),
+ shape = RoundedCornerShape(12.dp),
+ colors = ButtonDefaults.buttonColors(
+ containerColor = MaterialTheme.barrionColors.primaryBlue,
+ contentColor = MaterialTheme.barrionColors.white
+ )
+ ) {
+ Text(
+ text = rightText,
+ style = MaterialTheme.typography.labelLarge,
+ textAlign = TextAlign.Center
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/ui/src/main/java/com/example/ui/components/buttons/BarrionButton.kt b/core/ui/src/main/java/com/example/ui/components/buttons/BarrionButton.kt
new file mode 100644
index 0000000..b26c689
--- /dev/null
+++ b/core/ui/src/main/java/com/example/ui/components/buttons/BarrionButton.kt
@@ -0,0 +1,166 @@
+// core/ui/src/main/java/com/example/ui/components/buttons/BarrionButton.kt
+package com.example.ui.components.buttons
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.OutlinedButton
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.example.ui.theme.BarrionTheme
+import com.example.ui.theme.CornerRadius
+import com.example.ui.theme.barrionColors
+
+/**
+ * 아웃라인 스타일 버튼 (테두리가 있는 흰색 배경)
+ */
+@Composable
+fun BarrionOutlinedButton(
+ text: String,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ fullWidth: Boolean = true
+) {
+ val buttonModifier = if (fullWidth) {
+ modifier.fillMaxWidth().height(56.dp)
+ } else {
+ modifier.height(56.dp)
+ }
+
+ OutlinedButton(
+ onClick = onClick,
+ modifier = buttonModifier,
+ enabled = enabled,
+ shape = RoundedCornerShape(CornerRadius.XLarge),
+ border = BorderStroke(1.dp, MaterialTheme.barrionColors.primaryBlue),
+ colors = ButtonDefaults.outlinedButtonColors(
+ containerColor = MaterialTheme.barrionColors.white,
+ contentColor = MaterialTheme.barrionColors.primaryBlue,
+ disabledContentColor = MaterialTheme.barrionColors.primaryBlue.copy(alpha = 0.5f),
+ disabledContainerColor = MaterialTheme.barrionColors.white
+ ),
+ contentPadding = PaddingValues(horizontal = 16.dp)
+ ) {
+ Text(
+ text = text,
+ style = MaterialTheme.typography.labelLarge,
+ textAlign = TextAlign.Center
+ )
+ }
+}
+
+/**
+ * 주요 액션용 파란색 배경 버튼
+ */
+@Composable
+fun BarrionPrimaryButton(
+ text: String,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ fullWidth: Boolean = true
+) {
+ val buttonModifier = if (fullWidth) {
+ modifier.fillMaxWidth().height(56.dp)
+ } else {
+ modifier.height(56.dp)
+ }
+
+ Button(
+ onClick = onClick,
+ modifier = buttonModifier,
+ enabled = enabled,
+ shape = RoundedCornerShape(CornerRadius.XLarge),
+ colors = ButtonDefaults.buttonColors(
+ containerColor = MaterialTheme.barrionColors.primaryBlue,
+ contentColor = MaterialTheme.barrionColors.white,
+ disabledContainerColor = MaterialTheme.barrionColors.primaryBlue.copy(alpha = 0.5f),
+ disabledContentColor = MaterialTheme.barrionColors.white
+ ),
+ contentPadding = PaddingValues(horizontal = 16.dp)
+ ) {
+ Text(
+ text = text,
+ style = MaterialTheme.typography.labelLarge,
+ textAlign = TextAlign.Center
+ )
+ }
+}
+
+/**
+ * 보조 액션용 회색 배경 버튼
+ */
+@Composable
+fun BarrionSecondaryButton(
+ text: String,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ fullWidth: Boolean = true
+) {
+ val buttonModifier = if (fullWidth) {
+ modifier.fillMaxWidth().height(56.dp)
+ } else {
+ modifier.height(56.dp)
+ }
+
+ Button(
+ onClick = onClick,
+ modifier = buttonModifier,
+ enabled = enabled,
+ shape = RoundedCornerShape(CornerRadius.XLarge),
+ colors = ButtonDefaults.buttonColors(
+ containerColor = MaterialTheme.barrionColors.grayMedium,
+ contentColor = MaterialTheme.barrionColors.white,
+ disabledContainerColor = MaterialTheme.barrionColors.grayMedium.copy(alpha = 0.5f),
+ disabledContentColor = MaterialTheme.barrionColors.white
+ ),
+ contentPadding = PaddingValues(horizontal = 16.dp)
+ ) {
+ Text(
+ text = text,
+ style = MaterialTheme.typography.labelLarge,
+ textAlign = TextAlign.Center
+ )
+ }
+}
+
+// BarrionButton.kt 파일에 추가
+@Preview(showBackground = true)
+@Composable
+fun BarrionButtonPreview() {
+ BarrionTheme {
+ Column(
+ modifier = Modifier.padding(16.dp),
+ verticalArrangement = Arrangement.spacedBy(8.dp)
+ ) {
+ BarrionOutlinedButton(
+ text = "아웃라인 버튼",
+ onClick = { }
+ )
+
+ BarrionPrimaryButton(
+ text = "기본 버튼",
+ onClick = { }
+ )
+
+ BarrionSecondaryButton(
+ text = "보조 버튼",
+ onClick = { }
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/ui/src/main/java/com/example/ui/components/textfields/BarrionTextField.kt b/core/ui/src/main/java/com/example/ui/components/textfields/BarrionTextField.kt
new file mode 100644
index 0000000..ef5469c
--- /dev/null
+++ b/core/ui/src/main/java/com/example/ui/components/textfields/BarrionTextField.kt
@@ -0,0 +1,232 @@
+// core/ui/src/main/java/com/example/ui/components/textfields/BarrionTextField.kt
+package com.example.ui.components.textfields
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.text.BasicTextField
+import androidx.compose.foundation.text.KeyboardActions
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.text.input.VisualTransformation
+import androidx.compose.ui.unit.dp
+import com.example.ui.theme.barrionColors
+
+/**
+ * 텍스트 필드 상태를 정의하는 Enum
+ */
+enum class BarrionTextFieldState {
+ NORMAL, // 기본 상태 (회색 테두리)
+ FOCUSED, // 포커스된 상태 (파란색 테두리)
+ ERROR, // 오류 상태 (빨간색 테두리)
+ DISABLED // 비활성화 상태 (회색 배경)
+}
+
+/**
+ * 커스텀 텍스트 필드 컴포넌트
+ *
+ * @param value 현재 입력된 텍스트 값
+ * @param onValueChange 텍스트 값 변경 시 호출되는 콜백
+ * @param modifier Modifier
+ * @param title 텍스트 필드 위에 표시되는 제목 (null일 경우 표시하지 않음)
+ * @param placeholder 입력 전 표시되는 플레이스홀더 텍스트
+ * @param fieldState 텍스트 필드의 현재 상태
+ * @param enabled 텍스트 필드 활성화 여부
+ * @param readOnly 읽기 전용 모드 여부
+ * @param keyboardOptions 키보드 옵션
+ * @param keyboardActions 키보드 액션
+ * @param singleLine 한 줄 입력 모드 여부
+ * @param maxLines 최대 줄 수
+ * @param visualTransformation 입력 값의 시각적 변환 (비밀번호 마스킹 등)
+ */
+@Composable
+fun BarrionTextField(
+ value: String,
+ onValueChange: (String) -> Unit,
+ modifier: Modifier = Modifier,
+ title: String? = null,
+ placeholder: String = "",
+ fieldState: BarrionTextFieldState = BarrionTextFieldState.NORMAL,
+ enabled: Boolean = true,
+ readOnly: Boolean = false,
+ keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
+ keyboardActions: KeyboardActions = KeyboardActions.Default,
+ singleLine: Boolean = true,
+ maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
+ visualTransformation: VisualTransformation = VisualTransformation.None
+) {
+ val interactionSource = remember { MutableInteractionSource() }
+
+ // 상태에 따른 색상 및 스타일 설정
+ val borderColor = when (fieldState) {
+ BarrionTextFieldState.FOCUSED -> MaterialTheme.barrionColors.primaryBlue
+ BarrionTextFieldState.ERROR -> MaterialTheme.barrionColors.error
+ else -> MaterialTheme.barrionColors.grayMediumLight
+ }
+
+ val backgroundColor = when (fieldState) {
+ BarrionTextFieldState.DISABLED -> MaterialTheme.barrionColors.grayVeryLight
+ else -> Color.White
+ }
+
+ val textColor = when {
+ !enabled -> MaterialTheme.barrionColors.grayMedium
+ fieldState == BarrionTextFieldState.ERROR -> MaterialTheme.barrionColors.error
+ else -> MaterialTheme.barrionColors.grayBlack
+ }
+
+ Column(modifier = modifier.fillMaxWidth()) {
+ // 제목이 있는 경우 표시
+ if (title != null) {
+ Text(
+ text = title,
+ style = MaterialTheme.typography.bodyMedium,
+ color = MaterialTheme.barrionColors.grayDark,
+ modifier = Modifier.padding(bottom = 4.dp)
+ )
+ }
+
+ // 텍스트 필드
+ BasicTextField(
+ value = value,
+ onValueChange = onValueChange,
+ modifier = Modifier
+ .fillMaxWidth()
+ .clip(RoundedCornerShape(12.dp))
+ .border(
+ width = 1.dp,
+ color = borderColor,
+ shape = RoundedCornerShape(12.dp)
+ )
+ .background(backgroundColor),
+ enabled = enabled && !readOnly,
+ readOnly = readOnly,
+ textStyle = MaterialTheme.typography.bodyLarge.copy(color = textColor),
+ keyboardOptions = keyboardOptions,
+ keyboardActions = keyboardActions,
+ singleLine = singleLine,
+ maxLines = maxLines,
+ visualTransformation = visualTransformation,
+ interactionSource = interactionSource,
+ cursorBrush = SolidColor(MaterialTheme.barrionColors.primaryBlue),
+ decorationBox = { innerTextField ->
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 16.dp, vertical = 12.dp)
+ ) {
+ // 플레이스홀더 텍스트 (입력값이 비어있을 때만 표시)
+ if (value.isEmpty() && !readOnly) {
+ Text(
+ text = placeholder,
+ style = MaterialTheme.typography.bodyLarge,
+ color = MaterialTheme.barrionColors.grayMedium
+ )
+ }
+
+ // 실제 입력 필드
+ innerTextField()
+ }
+ }
+ )
+ }
+}
+
+/**
+ * 유효성 검사 기능이 포함된 텍스트 필드
+ *
+ * @param value 현재 입력된 텍스트 값
+ * @param onValueChange 텍스트 값 변경 시 호출되는 콜백
+ * @param validator 입력 값의 유효성을 검사하는 함수, true를 반환하면 유효한 값
+ * @param title 텍스트 필드 위에 표시되는 제목
+ * @param placeholder 입력 전 표시되는 플레이스홀더 텍스트
+ * @param errorMessage 유효성 검사 실패 시 표시되는 오류 메시지
+ * @param modifier Modifier
+ * @param enabled 텍스트 필드 활성화 여부
+ * @param keyboardOptions 키보드 옵션
+ * @param keyboardActions 키보드 액션
+ * @param singleLine 한 줄 입력 모드 여부
+ * @param visualTransformation 입력 값의 시각적 변환 (비밀번호 마스킹 등)
+ */
+@Composable
+fun BarrionValidatedTextField(
+ value: String,
+ onValueChange: (String) -> Unit,
+ validator: (String) -> Boolean,
+ title: String,
+ placeholder: String,
+ errorMessage: String,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
+ keyboardActions: KeyboardActions = KeyboardActions.Default,
+ singleLine: Boolean = true,
+ visualTransformation: VisualTransformation = VisualTransformation.None
+) {
+ val isValid = if (value.isEmpty()) true else validator(value)
+ val fieldState = when {
+ value.isEmpty() -> BarrionTextFieldState.NORMAL
+ isValid -> BarrionTextFieldState.FOCUSED
+ else -> BarrionTextFieldState.ERROR
+ }
+
+ Column(modifier = modifier.fillMaxWidth()) {
+ BarrionTextField(
+ value = value,
+ onValueChange = onValueChange,
+ title = title,
+ placeholder = placeholder,
+ fieldState = fieldState,
+ enabled = enabled,
+ keyboardOptions = keyboardOptions,
+ keyboardActions = keyboardActions,
+ singleLine = singleLine,
+ visualTransformation = visualTransformation
+ )
+
+ // 유효성 검사 실패 시 오류 메시지 표시
+ if (fieldState == BarrionTextFieldState.ERROR) {
+ Text(
+ text = errorMessage,
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.barrionColors.error,
+ modifier = Modifier.padding(start = 4.dp, top = 4.dp)
+ )
+ }
+ }
+}
+
+/**
+ * 읽기 전용 텍스트 필드 (수정 불가능한 정보 표시용)
+ *
+ * @param value 표시할 텍스트 값
+ * @param title 텍스트 필드 위에 표시되는 제목
+ * @param modifier Modifier
+ */
+@Composable
+fun BarrionReadOnlyTextField(
+ value: String,
+ title: String,
+ modifier: Modifier = Modifier
+) {
+ BarrionTextField(
+ value = value,
+ onValueChange = { }, // 읽기 전용이므로 변경 불가
+ title = title,
+ fieldState = BarrionTextFieldState.DISABLED,
+ readOnly = true,
+ modifier = modifier
+ )
+}
\ No newline at end of file
diff --git a/core/ui/src/main/java/com/example/ui/theme/Color.kt b/core/ui/src/main/java/com/example/ui/theme/Color.kt
new file mode 100644
index 0000000..5d12d65
--- /dev/null
+++ b/core/ui/src/main/java/com/example/ui/theme/Color.kt
@@ -0,0 +1,129 @@
+package com.example.ui.theme
+
+import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.staticCompositionLocalOf
+import androidx.compose.ui.graphics.Color
+
+// 메인 블루 색상
+val BluePrimary = Color(0xFF1335C9)
+val BlueSecondary = Color(0xFF2142FF)
+val BlueTertiary = Color(0xFF4361FF)
+
+// 블루 변형
+val BlueDark = Color(0xFF0A1A5E)
+val BlueMediumDark = Color(0xFF0E2894)
+val BlueMedium = Color(0xFF1335C9)
+val BlueBright = Color(0xFF2142FF)
+val BlueLight = Color(0xFF4361FF)
+val BlueLighter = Color(0xFF637BFF)
+val BluePale = Color(0xFF8395FF)
+val BlueVeryPale = Color(0xFFA3AFFF)
+val BlueWhite = Color(0xFFE0E3FF)
+
+// 그레이 색상
+val GrayBlack = Color(0xFF1A1A1A)
+val GrayVeryDark = Color(0xFF2E2E33)
+val GrayDark = Color(0xFF474752)
+val GrayMediumDark = Color(0xFF5F5F70)
+val GrayMedium = Color(0xFF9696A3)
+val GrayMediumLight = Color(0xFFB2B2BC)
+val GrayLight = Color(0xFFCDCDD5)
+val GrayVeryLight = Color(0xFFE8E8EC)
+val GrayWhite = Color(0xFFF4F4F6)
+
+// 데이터 클래스로 색상 정의 (CompositionLocal 사용을 위한)
+internal val BarrionColors = BarrionColor(
+ // 메인 블루 색상
+ primaryBlue = BluePrimary,
+ secondaryBlue = BlueSecondary,
+ tertiaryBlue = BlueTertiary,
+
+ // 블루 변형
+ blueDark = BlueDark,
+ blueMediumDark = BlueMediumDark,
+ blueMedium = BlueMedium,
+ blueBright = BlueBright,
+ blueLight = BlueLight,
+ blueLighter = BlueLighter,
+ bluePale = BluePale,
+ blueVeryPale = BlueVeryPale,
+ blueWhite = BlueWhite,
+
+ // 그레이 색상
+ grayBlack = GrayBlack,
+ grayVeryDark = GrayVeryDark,
+ grayDark = GrayDark,
+ grayMediumDark = GrayMediumDark,
+ grayMedium = GrayMedium,
+ grayMediumLight = GrayMediumLight,
+ grayLight = GrayLight,
+ grayVeryLight = GrayVeryLight,
+ grayWhite = GrayWhite,
+
+ // 기능 색상 (필요시 추가)
+ error = Color(0xFFFF3434),
+ success = Color(0xFF4CAF50),
+ warning = Color(0xFFFFC107),
+ info = Color(0xFF2196F3),
+
+ // 기타 유틸리티 색상
+ white = Color(0xFFFFFFFF),
+ black = Color(0xFF000000),
+ transparent = Color(0x00000000),
+
+ // 투명도 변형
+ blackOverlay30 = Color(0x4D000000),
+ blackOverlay60 = Color(0x99000000),
+ whiteOverlay30 = Color(0x4DFFFFFF)
+)
+
+@Immutable
+data class BarrionColor(
+ // 메인 블루 색상
+ val primaryBlue: Color,
+ val secondaryBlue: Color,
+ val tertiaryBlue: Color,
+
+ // 블루 변형
+ val blueDark: Color,
+ val blueMediumDark: Color,
+ val blueMedium: Color,
+ val blueBright: Color,
+ val blueLight: Color,
+ val blueLighter: Color,
+ val bluePale: Color,
+ val blueVeryPale: Color,
+ val blueWhite: Color,
+
+ // 그레이 색상
+ val grayBlack: Color,
+ val grayVeryDark: Color,
+ val grayDark: Color,
+ val grayMediumDark: Color,
+ val grayMedium: Color,
+ val grayMediumLight: Color,
+ val grayLight: Color,
+ val grayVeryLight: Color,
+ val grayWhite: Color,
+
+ // 기능 색상
+ val error: Color,
+ val success: Color,
+ val warning: Color,
+ val info: Color,
+
+ // 기타 유틸리티 색상
+ val white: Color,
+ val black: Color,
+ val transparent: Color,
+
+ // 투명도 변형
+ val blackOverlay30: Color,
+ val blackOverlay60: Color,
+ val whiteOverlay30: Color
+)
+
+// CompositionLocal을 통해 앱 전체에서 색상에 접근할 수 있도록 설정
+internal val LocalBarrionColor = staticCompositionLocalOf {
+ BarrionColors
+}
\ No newline at end of file
diff --git a/core/ui/src/main/java/com/example/ui/theme/Dimensions.kt b/core/ui/src/main/java/com/example/ui/theme/Dimensions.kt
new file mode 100644
index 0000000..f50d7f5
--- /dev/null
+++ b/core/ui/src/main/java/com/example/ui/theme/Dimensions.kt
@@ -0,0 +1,39 @@
+package com.example.ui.theme
+
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+
+// 간격 정의
+object Spacing {
+ val XXSmall = 2.dp
+ val XSmall = 4.dp
+ val Small = 8.dp
+ val Medium = 16.dp
+ val Large = 24.dp
+ val XLarge = 32.dp
+ val XXLarge = 48.dp
+}
+
+// 텍스트 크기 정의
+object TextSize {
+ val Small = 12.sp
+ val Medium = 14.sp
+ val Large = 16.sp
+ val XLarge = 20.sp
+ val XXLarge = 24.sp
+}
+
+// 모서리 둥글기 정의
+object CornerRadius {
+ val Small = 4.dp
+ val Medium = 8.dp
+ val Large = 16.dp
+ val XLarge = 24.dp
+}
+
+// 그림자 높이 정의
+object Elevation {
+ val Small = 2.dp
+ val Medium = 4.dp
+ val Large = 8.dp
+}
\ No newline at end of file
diff --git a/core/ui/src/main/java/com/example/ui/theme/Theme.kt b/core/ui/src/main/java/com/example/ui/theme/Theme.kt
new file mode 100644
index 0000000..da791f4
--- /dev/null
+++ b/core/ui/src/main/java/com/example/ui/theme/Theme.kt
@@ -0,0 +1,114 @@
+package com.example.ui.theme
+
+import android.app.Activity
+import android.os.Build
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.darkColorScheme
+import androidx.compose.material3.dynamicDarkColorScheme
+import androidx.compose.material3.dynamicLightColorScheme
+import androidx.compose.material3.lightColorScheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.SideEffect
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.toArgb
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalView
+import androidx.core.view.WindowCompat
+
+// 라이트 테마를 위한 색상 스키마 정의
+private val LightColorScheme = lightColorScheme(
+ primary = BluePrimary,
+ secondary = BlueSecondary,
+ tertiary = BlueTertiary,
+
+ // 배경 및 표면 색상
+ background = GrayVeryLight,
+ surface = GrayWhite,
+ surfaceVariant = GrayLight,
+
+ // 텍스트 및 아이콘 색상
+ onPrimary = GrayWhite, // 기본 색상 위 텍스트/아이콘
+ onSecondary = GrayWhite,
+ onTertiary = GrayWhite,
+ onBackground = GrayBlack, // 배경 위 텍스트/아이콘
+ onSurface = GrayBlack,
+ onSurfaceVariant = GrayDark,
+
+ // 기타 색상
+ error = Color(0xFFFF3434),
+ onError = GrayWhite
+)
+
+// 다크 테마를 위한 색상 스키마 정의
+private val DarkColorScheme = darkColorScheme(
+ primary = BlueBright, // 어두운 배경에서는 더 밝은 블루
+ secondary = BlueLight,
+ tertiary = BlueLighter,
+
+ // 배경 및 표면 색상
+ background = GrayBlack,
+ surface = GrayVeryDark,
+ surfaceVariant = GrayDark,
+
+ // 텍스트 및 아이콘 색상
+ onPrimary = GrayWhite,
+ onSecondary = GrayWhite,
+ onTertiary = GrayWhite,
+ onBackground = GrayWhite,
+ onSurface = GrayWhite,
+ onSurfaceVariant = GrayMediumLight,
+
+ // 기타 색상
+ error = Color(0xFFFF5252),
+ onError = GrayWhite
+)
+
+@Composable
+fun BarrionTheme(
+ darkTheme: Boolean = isSystemInDarkTheme(),
+ // Dynamic color is available on Android 12+
+ dynamicColor: Boolean = false, // 커스텀 색상을 우선하기 위해 기본값 false로 변경
+ content: @Composable () -> Unit,
+) {
+ val colorScheme = when {
+ dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
+ val context = LocalContext.current
+ if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
+ }
+ darkTheme -> DarkColorScheme
+ else -> LightColorScheme
+ }
+
+ // 상태 표시줄 색상 설정
+ val view = LocalView.current
+ if (!view.isInEditMode) {
+ SideEffect {
+ val window = (view.context as Activity).window
+
+ // 상태 표시줄 배경색을 하얀색으로 설정
+ window.statusBarColor = Color.White.toArgb()
+
+ // 상태 표시줄 아이콘 색상 설정 (라이트 테마에서는 어두운 아이콘)
+ // 다크 테마에서는 밝은 아이콘을, 라이트 테마에서는 어두운 아이콘을 사용
+ WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = true
+ }
+ }
+
+ // 커스텀 색상 시스템을 앱 전체에 제공
+ CompositionLocalProvider(
+ LocalBarrionColor provides BarrionColors
+ ) {
+ MaterialTheme(
+ colorScheme = colorScheme,
+ typography = Typography,
+ content = content,
+ )
+ }
+}
+
+// 커스텀 색상에 쉽게 접근하기 위한 확장 속성
+val MaterialTheme.barrionColors: BarrionColor
+ @Composable
+ get() = LocalBarrionColor.current
\ No newline at end of file
diff --git a/core/ui/src/main/java/com/example/ui/theme/Type.kt b/core/ui/src/main/java/com/example/ui/theme/Type.kt
new file mode 100644
index 0000000..9967af2
--- /dev/null
+++ b/core/ui/src/main/java/com/example/ui/theme/Type.kt
@@ -0,0 +1,124 @@
+package com.example.ui.theme
+
+import androidx.compose.material3.Typography
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.Font
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+import com.example.ui.R
+
+// Pretendard 폰트 패밀리 정의
+val PretendardFamily = FontFamily(
+ Font(R.font.pretendard_thin, FontWeight.Thin),
+ Font(R.font.pretendard_extralight, FontWeight.ExtraLight),
+ Font(R.font.pretendard_light, FontWeight.Light),
+ Font(R.font.pretendard_regular, FontWeight.Normal),
+ Font(R.font.pretendard_medium, FontWeight.Medium),
+ Font(R.font.pretendard_semibold, FontWeight.SemiBold),
+ Font(R.font.pretendard_bold, FontWeight.Bold),
+ Font(R.font.pretendard_extrabold, FontWeight.ExtraBold),
+ Font(R.font.pretendard_black, FontWeight.Black)
+)
+
+// dimens.xml의 텍스트 크기를 Compose에서 사용하기 위한 변수
+private val TextSizeSmall = 12.sp
+private val TextSizeMedium = 14.sp
+private val TextSizeLarge = 16.sp
+private val TextSizeXLarge = 20.sp
+private val TextSizeXXLarge = 24.sp
+
+// Typography 정의
+val Typography = Typography(
+ // 표제 스타일
+ headlineLarge = TextStyle(
+ fontFamily = PretendardFamily,
+ fontWeight = FontWeight.Bold,
+ fontSize = TextSizeXXLarge,
+ lineHeight = 32.sp,
+ letterSpacing = (-0.5).sp
+ ),
+ headlineMedium = TextStyle(
+ fontFamily = PretendardFamily,
+ fontWeight = FontWeight.Bold,
+ fontSize = TextSizeXLarge,
+ lineHeight = 28.sp,
+ letterSpacing = (-0.5).sp
+ ),
+ headlineSmall = TextStyle(
+ fontFamily = PretendardFamily,
+ fontWeight = FontWeight.Bold,
+ fontSize = TextSizeLarge,
+ lineHeight = 24.sp,
+ letterSpacing = 0.sp
+ ),
+
+ // 제목 스타일
+ titleLarge = TextStyle(
+ fontFamily = PretendardFamily,
+ fontWeight = FontWeight.SemiBold,
+ fontSize = TextSizeXLarge,
+ lineHeight = 28.sp,
+ letterSpacing = (-0.25).sp
+ ),
+ titleMedium = TextStyle(
+ fontFamily = PretendardFamily,
+ fontWeight = FontWeight.SemiBold,
+ fontSize = TextSizeLarge,
+ lineHeight = 24.sp,
+ letterSpacing = 0.sp
+ ),
+ titleSmall = TextStyle(
+ fontFamily = PretendardFamily,
+ fontWeight = FontWeight.Medium,
+ fontSize = TextSizeMedium,
+ lineHeight = 20.sp,
+ letterSpacing = 0.sp
+ ),
+
+ // 본문 스타일
+ bodyLarge = TextStyle(
+ fontFamily = PretendardFamily,
+ fontWeight = FontWeight.Normal,
+ fontSize = TextSizeLarge,
+ lineHeight = 24.sp,
+ letterSpacing = 0.sp
+ ),
+ bodyMedium = TextStyle(
+ fontFamily = PretendardFamily,
+ fontWeight = FontWeight.Normal,
+ fontSize = TextSizeMedium,
+ lineHeight = 20.sp,
+ letterSpacing = 0.sp
+ ),
+ bodySmall = TextStyle(
+ fontFamily = PretendardFamily,
+ fontWeight = FontWeight.Normal,
+ fontSize = TextSizeSmall,
+ lineHeight = 16.sp,
+ letterSpacing = 0.1.sp
+ ),
+
+ // 라벨 스타일 (버튼 등에 사용)
+ labelLarge = TextStyle(
+ fontFamily = PretendardFamily,
+ fontWeight = FontWeight.Medium,
+ fontSize = TextSizeMedium,
+ lineHeight = 20.sp,
+ letterSpacing = 0.sp
+ ),
+ labelMedium = TextStyle(
+ fontFamily = PretendardFamily,
+ fontWeight = FontWeight.Medium,
+ fontSize = TextSizeSmall,
+ lineHeight = 16.sp,
+ letterSpacing = 0.sp
+ ),
+ labelSmall = TextStyle(
+ fontFamily = PretendardFamily,
+ fontWeight = FontWeight.Medium,
+ fontSize = 10.sp,
+ lineHeight = 14.sp,
+ letterSpacing = 0.sp
+ )
+)
\ No newline at end of file
diff --git a/core/ui/src/main/res/drawable/combined_shape.xml b/core/ui/src/main/res/drawable/combined_shape.xml
new file mode 100644
index 0000000..ff30a6d
--- /dev/null
+++ b/core/ui/src/main/res/drawable/combined_shape.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/core/ui/src/main/res/font/pretendard_black.ttf b/core/ui/src/main/res/font/pretendard_black.ttf
new file mode 100644
index 0000000..d0c1db8
Binary files /dev/null and b/core/ui/src/main/res/font/pretendard_black.ttf differ
diff --git a/core/ui/src/main/res/font/pretendard_bold.ttf b/core/ui/src/main/res/font/pretendard_bold.ttf
new file mode 100644
index 0000000..fb07fc6
Binary files /dev/null and b/core/ui/src/main/res/font/pretendard_bold.ttf differ
diff --git a/core/ui/src/main/res/font/pretendard_extrabold.ttf b/core/ui/src/main/res/font/pretendard_extrabold.ttf
new file mode 100644
index 0000000..9d5fe07
Binary files /dev/null and b/core/ui/src/main/res/font/pretendard_extrabold.ttf differ
diff --git a/core/ui/src/main/res/font/pretendard_extralight.ttf b/core/ui/src/main/res/font/pretendard_extralight.ttf
new file mode 100644
index 0000000..09e6542
Binary files /dev/null and b/core/ui/src/main/res/font/pretendard_extralight.ttf differ
diff --git a/core/ui/src/main/res/font/pretendard_light.ttf b/core/ui/src/main/res/font/pretendard_light.ttf
new file mode 100644
index 0000000..2e8541d
Binary files /dev/null and b/core/ui/src/main/res/font/pretendard_light.ttf differ
diff --git a/core/ui/src/main/res/font/pretendard_medium.ttf b/core/ui/src/main/res/font/pretendard_medium.ttf
new file mode 100644
index 0000000..1db67c6
Binary files /dev/null and b/core/ui/src/main/res/font/pretendard_medium.ttf differ
diff --git a/core/ui/src/main/res/font/pretendard_regular.ttf b/core/ui/src/main/res/font/pretendard_regular.ttf
new file mode 100644
index 0000000..01147e9
Binary files /dev/null and b/core/ui/src/main/res/font/pretendard_regular.ttf differ
diff --git a/core/ui/src/main/res/font/pretendard_semibold.ttf b/core/ui/src/main/res/font/pretendard_semibold.ttf
new file mode 100644
index 0000000..9f2690f
Binary files /dev/null and b/core/ui/src/main/res/font/pretendard_semibold.ttf differ
diff --git a/core/ui/src/main/res/font/pretendard_thin.ttf b/core/ui/src/main/res/font/pretendard_thin.ttf
new file mode 100644
index 0000000..fe9825f
Binary files /dev/null and b/core/ui/src/main/res/font/pretendard_thin.ttf differ
diff --git a/core/ui/src/main/res/values/colors.xml b/core/ui/src/main/res/values/colors.xml
new file mode 100644
index 0000000..87e7c1a
--- /dev/null
+++ b/core/ui/src/main/res/values/colors.xml
@@ -0,0 +1,31 @@
+
+
+
+
+ #1335C9
+ #2142FF
+ #4361FF
+
+
+ #0A1A5E
+ #0E2894
+ #1335C9
+ #2142FF
+ #4361FF
+ #637BFF
+ #8395FF
+ #A3AFFF
+ #E0E3FF
+
+
+ #1A1A1A
+ #2E2E33
+ #474752
+ #5F5F70
+ #9696A3
+ #B2B2BC
+ #CDCDD5
+ #E8E8EC
+ #F4F4F6
+
+
\ No newline at end of file
diff --git a/core/ui/src/main/res/values/dimens.xml b/core/ui/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..07ef8f6
--- /dev/null
+++ b/core/ui/src/main/res/values/dimens.xml
@@ -0,0 +1,18 @@
+
+
+
+ 2dp
+ 4dp
+ 8dp
+ 16dp
+ 24dp
+ 32dp
+ 48dp
+
+
+ 12sp
+ 14sp
+ 16sp
+ 20sp
+ 24sp
+
\ No newline at end of file
diff --git a/core/ui/src/main/res/values/themes.xml b/core/ui/src/main/res/values/themes.xml
new file mode 100644
index 0000000..a6b3dae
--- /dev/null
+++ b/core/ui/src/main/res/values/themes.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/feature/onboarding/build.gradle.kts b/feature/onboarding/build.gradle.kts
index f17605f..535c45d 100644
--- a/feature/onboarding/build.gradle.kts
+++ b/feature/onboarding/build.gradle.kts
@@ -1,14 +1,75 @@
plugins {
- id("barrion.android.feature")
- // 필요에 따라 추가 플러그인 적용
+ id("com.android.library")
+ id("org.jetbrains.kotlin.android")
+
+ // Compose 컴파일러 플러그인
+ id("org.jetbrains.kotlin.plugin.compose")
+
+ // 필요한 Hilt와 이미지 로딩 플러그인
id("barrion.hilt")
id("barrion.imageloading")
}
android {
- namespace = "com.example.feature.auth" // 각 모듈에 맞는 네임스페이스 사용
+ namespace = "com.example.onboarding"
+
+ // 컴파일 SDK 버전 추가 (앱 모듈과 같은 버전 사용)
+ compileSdk = 34 // 이 부분이 누락되었습니다
+
+ defaultConfig {
+ minSdk = 21 // 앱 모듈과 일치
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+
+ buildFeatures {
+ compose = true
+ }
+
+ composeOptions {
+ kotlinCompilerExtensionVersion = "1.5.10"
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ }
+
+ kotlinOptions {
+ jvmTarget = "11"
+ }
}
dependencies {
- // 모듈 특화 의존성만 추가
+ // 코어 UI 모듈 의존성
+ implementation(project(":core:ui"))
+
+ // Compose 기본 의존성
+ implementation("androidx.compose.ui:ui")
+ implementation("androidx.compose.material3:material3")
+ implementation("androidx.compose.ui:ui-tooling-preview")
+ debugImplementation("androidx.compose.ui:ui-tooling")
+
+ // Material 아이콘 확장 의존성
+ implementation("androidx.compose.material:material-icons-extended:1.5.4")
+
+ // 다른 필요한 의존성
+ implementation("androidx.core:core-ktx:1.12.0")
+ implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
+
+ // 테스트 의존성
+ testImplementation("junit:junit:4.13.2")
+ androidTestImplementation("androidx.test.ext:junit:1.1.5")
+ androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
}
\ No newline at end of file
diff --git a/feature/onboarding/src/main/java/com/example/onboarding/presentation/OnboardingScreen.kt b/feature/onboarding/src/main/java/com/example/onboarding/presentation/OnboardingScreen.kt
new file mode 100644
index 0000000..44a9662
--- /dev/null
+++ b/feature/onboarding/src/main/java/com/example/onboarding/presentation/OnboardingScreen.kt
@@ -0,0 +1,231 @@
+// features/onboarding/src/main/java/com/example/onboarding/presentation/OnboardingScreen.kt
+
+package com.example.onboarding.presentation
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.pager.HorizontalPager
+import androidx.compose.foundation.pager.rememberPagerState
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.*
+import androidx.compose.runtime.*
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import com.example.onboarding.R
+import com.example.ui.components.buttons.BarrionFullButton
+import com.example.ui.components.buttons.BarrionNavigationButtons
+import com.example.ui.components.buttons.BarrionPrimaryButton
+import com.example.ui.theme.barrionColors
+import kotlinx.coroutines.launch
+
+/**
+ * 온보딩 페이지 데이터 클래스
+ * 각 온보딩 페이지의 제목, 설명, 이미지 리소스 ID를 포함합니다.
+ */
+data class OnboardingPage(
+ val title: String, // 페이지 제목
+ val description: String, // 페이지 설명
+ val imageResId: Int // 이미지 리소스 ID
+)
+
+/**
+ * 온보딩 화면 컴포저블
+ * 4개의 온보딩 페이지로 구성되며, 수평 페이저를 통해 사용자가 페이지를 넘길 수 있습니다.
+ * 마지막 페이지에 도달하면 시작하기 버튼이 활성화됩니다.
+ *
+ * @param onNavigateToHome 시작하기 버튼 클릭 시 호출될 콜백 함수 (홈 화면으로 이동)
+ */
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun OnboardingScreen(
+ onNavigateToHome: () -> Unit
+) {
+ // 온보딩 페이지 정의 - 4개의 화면으로 구성
+ val pages = listOf(
+ OnboardingPage(
+ title = "매출 관리",
+ description = "오늘 우리 가게는 얼마나 벌었을까요?",
+ imageResId = R.drawable.onboarding_sale // 매출 관리 이미지
+ ),
+ OnboardingPage(
+ title = "메뉴 관리",
+ description = "메뉴 관리, 이제 터치 몇 번으로 끝",
+ imageResId = R.drawable.onboarding_menu // 메뉴 관리 이미지
+ ),
+ OnboardingPage(
+ title = "주문 관리",
+ description = "주문 현황을 한눈에 확인하세요.",
+ imageResId = R.drawable.onboarding_order // 주문 관리 이미지
+ ),
+ OnboardingPage(
+ title = "직원 관리",
+ description = "직원 정보, 쉽고 빠르게 관리해요.",
+ imageResId = R.drawable.onboarding_staff // 직원 관리 이미지
+ )
+ )
+
+ // 페이저 상태 관리
+ val pagerState = rememberPagerState(pageCount = { pages.size })
+ val coroutineScope = rememberCoroutineScope()
+
+ // 현재 마지막 페이지인지 확인 (시작하기 버튼 활성화 여부에 사용)
+ val isLastPage = pagerState.currentPage == pages.size - 1
+
+ // 전체 화면 컨테이너
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(MaterialTheme.colorScheme.background)
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(16.dp)
+ ) {
+ // 수평 페이저 - 온보딩 페이지들을 수평으로 스와이프하여 볼 수 있음
+ HorizontalPager(
+ state = pagerState,
+ modifier = Modifier
+ .fillMaxWidth()
+ .weight(1f)
+ ) { page ->
+ // 현재 페이지 인덱스에 해당하는 온보딩 페이지 컨텐츠를 표시
+ OnboardingPageContent(pages[page])
+ }
+
+ // 하단 여백 추가
+ Spacer(modifier = Modifier.height(16.dp))
+
+ // 페이지 인디케이터 - 현재 몇 번째 페이지인지 표시하는 도트
+ Row(
+ modifier = Modifier
+ .align(Alignment.CenterHorizontally)
+ .padding(bottom = 32.dp),
+ horizontalArrangement = Arrangement.Center
+ ) {
+ // 페이지 수만큼 도트 생성
+ repeat(pages.size) { index ->
+ val isSelected = pagerState.currentPage == index
+ Box(
+ modifier = Modifier
+ .padding(horizontal = 4.dp)
+ .size(8.dp)
+ .clip(CircleShape)
+ .background(
+ // 현재 페이지는 파란색, 나머지는 회색으로 표시
+ if (isSelected) MaterialTheme.barrionColors.primaryBlue
+ else MaterialTheme.barrionColors.grayLight
+ )
+ )
+ }
+ }
+
+ // 시작하기 버튼 - 마지막 페이지에서만 활성화됨
+ BarrionPrimaryButton(
+ text = "시작하기",
+ onClick = {
+ if (isLastPage) {
+ // 마지막 페이지면 홈 화면으로 이동
+ onNavigateToHome()
+ } else {
+ // 아니면 다음 페이지로 이동
+ coroutineScope.launch {
+ pagerState.animateScrollToPage(pagerState.currentPage + 1)
+ }
+ }
+ },
+ modifier = Modifier
+ .padding(horizontal = 24.dp)
+ .padding(bottom = 40.dp),
+ enabled = isLastPage // 마지막 페이지에서만 활성화
+ )
+
+ // 하단 추가 여백
+ Spacer(modifier = Modifier.height(24.dp))
+ }
+ }
+}
+
+/**
+ * 각 온보딩 페이지의 콘텐츠를 표시하는 컴포저블
+ *
+ * @param page 표시할 온보딩 페이지 데이터
+ */
+@Composable
+fun OnboardingPageContent(page: OnboardingPage) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 16.dp),
+ horizontalAlignment = Alignment.Start // 왼쪽 정렬
+ ) {
+ // 상단 여백 - 제목과 설명을 아래로 내려 배치
+ Spacer(modifier = Modifier.height(36.dp))
+
+ // 페이지 제목
+ Text(
+ text = page.title,
+ style = MaterialTheme.typography.headlineLarge,
+ fontWeight = FontWeight.ExtraBold,
+ modifier = Modifier.padding(bottom = 8.dp)
+ )
+
+ // 페이지 설명
+ Text(
+ text = page.description,
+ style = MaterialTheme.typography.bodyLarge,
+ color = MaterialTheme.barrionColors.grayMediumDark,
+ modifier = Modifier.padding(bottom = 32.dp)
+ )
+
+ // 이미지 카드 - 해당 기능을 시각적으로, 보여주는 이미지
+ if (page.imageResId != 0) {
+ Card(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(380.dp), // 이미지 높이 설정
+ shape = RoundedCornerShape(16.dp),
+ elevation = CardDefaults.cardElevation(defaultElevation = 4.dp) // 그림자 효과
+ ) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .clip(RoundedCornerShape(16.dp))
+ ) {
+ Image(
+ painter = painterResource(id = page.imageResId),
+ contentDescription = page.title,
+ contentScale = ContentScale.Crop, // 이미지가 컨테이너를 꽉 채우도록 설정
+ alignment = Alignment.TopCenter, // 이미지 상단이 보이도록 정렬
+ modifier = Modifier.fillMaxSize()
+ )
+ }
+ }
+ } else {
+ // 이미지가 없는 경우 대체 UI 표시
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(380.dp)
+ .clip(RoundedCornerShape(16.dp))
+ .background(MaterialTheme.barrionColors.grayVeryLight),
+ contentAlignment = Alignment.Center
+ ) {
+ Text(
+ text = "${page.title} 이미지",
+ style = MaterialTheme.typography.bodyMedium,
+ color = MaterialTheme.barrionColors.grayMedium
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/feature/onboarding/src/main/res/drawable/onboarding_menu.png b/feature/onboarding/src/main/res/drawable/onboarding_menu.png
new file mode 100644
index 0000000..8938f81
Binary files /dev/null and b/feature/onboarding/src/main/res/drawable/onboarding_menu.png differ
diff --git a/feature/onboarding/src/main/res/drawable/onboarding_order.png b/feature/onboarding/src/main/res/drawable/onboarding_order.png
new file mode 100644
index 0000000..bad2ca3
Binary files /dev/null and b/feature/onboarding/src/main/res/drawable/onboarding_order.png differ
diff --git a/feature/onboarding/src/main/res/drawable/onboarding_sale.png b/feature/onboarding/src/main/res/drawable/onboarding_sale.png
new file mode 100644
index 0000000..640e1e2
Binary files /dev/null and b/feature/onboarding/src/main/res/drawable/onboarding_sale.png differ
diff --git a/feature/onboarding/src/main/res/drawable/onboarding_staff.png b/feature/onboarding/src/main/res/drawable/onboarding_staff.png
new file mode 100644
index 0000000..c49f280
Binary files /dev/null and b/feature/onboarding/src/main/res/drawable/onboarding_staff.png differ
diff --git a/presentation/build.gradle.kts b/presentation/build.gradle.kts
index 0734033..f17605f 100644
--- a/presentation/build.gradle.kts
+++ b/presentation/build.gradle.kts
@@ -1,43 +1,14 @@
- plugins {
- alias(libs.plugins.android.library)
- alias(libs.plugins.kotlin.android)
- }
-
- android {
- namespace = "com.example.presentation"
- compileSdk = 34
-
- defaultConfig {
- minSdk = 24
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles("consumer-rules.pro")
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- proguardFiles(
- getDefaultProguardFile("proguard-android-optimize.txt"),
- "proguard-rules.pro"
- )
- }
- }
- compileOptions {
- sourceCompatibility = JavaVersion.VERSION_11
- targetCompatibility = JavaVersion.VERSION_11
- }
- kotlinOptions {
- jvmTarget = "11"
- }
- }
-
- dependencies {
-
- implementation(libs.androidx.core.ktx)
- implementation(libs.androidx.appcompat)
- implementation(libs.material)
- testImplementation(libs.junit)
- androidTestImplementation(libs.androidx.junit)
- androidTestImplementation(libs.androidx.espresso.core)
- }
\ No newline at end of file
+plugins {
+ id("barrion.android.feature")
+ // 필요에 따라 추가 플러그인 적용
+ id("barrion.hilt")
+ id("barrion.imageloading")
+}
+
+android {
+ namespace = "com.example.feature.auth" // 각 모듈에 맞는 네임스페이스 사용
+}
+
+dependencies {
+ // 모듈 특화 의존성만 추가
+}
\ No newline at end of file
diff --git a/presentation/src/main/java/com/example/presentation/splash/SplashViewModel.kt b/presentation/src/main/java/com/example/presentation/splash/SplashViewModel.kt
new file mode 100644
index 0000000..1d95d4d
--- /dev/null
+++ b/presentation/src/main/java/com/example/presentation/splash/SplashViewModel.kt
@@ -0,0 +1,38 @@
+package com.example.presentation.splash
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+/**
+ * 스플래시 화면 초기화를 관리하는 ViewModel
+ */
+class SplashViewModel @Inject constructor(
+ // 필요한 레포지토리나 유스케이스 의존성 주입
+) : ViewModel() {
+
+ private val _isInitialized = MutableStateFlow(false)
+ val isInitialized: StateFlow = _isInitialized.asStateFlow()
+
+ init {
+ initializeApp()
+ }
+
+ private fun initializeApp() {
+ viewModelScope.launch {
+ // 1. 필요한 초기화 작업 수행
+ // 예: 사용자 인증 상태 확인, 데이터 초기화 등
+
+ // 2. 최소 스플래시 화면 표시 시간 보장
+ delay(5000) // 1.5초 지연
+
+ // 3. 초기화 완료
+ _isInitialized.value = true
+ }
+ }
+}
\ No newline at end of file