From 2ab95577369c415cbeef40d1fc4df632819ada27 Mon Sep 17 00:00:00 2001 From: sanjeok77 Date: Sat, 7 Mar 2026 03:59:45 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20EdgeToEdge=20=EA=B0=9C=EC=84=A0=20-=20?= =?UTF-8?q?=EC=8B=9C=EC=8A=A4=ED=85=9C=20=EB=B0=94=20=EC=83=89=EC=83=81=20?= =?UTF-8?q?=ED=86=B5=EC=9D=BC=20=EB=B0=8F=20=ED=99=94=EB=A9=B4=20=EA=B3=B5?= =?UTF-8?q?=EA=B0=84=20=EC=B5=9C=EC=A0=81=ED=99=94=20(v1.9.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - MainScreen.kt: 불필요한 windowInsetsPadding 제거로 화면 공간 확보 - DealListScreen.kt: TopAppBar에 statusBarsPadding 적용, FAB에 navigationBarsPadding 적용 - Theme.kt: 시스템 바 색상을 앱 surface 색상과 일치시켜 이질감 해소 - MainActivity.kt: setupEdgeToEdge 함수 간소화 및 중복 코드 제거 - version.json: 1.9.0 버전 업데이트 --- app/build.gradle.kts | 4 +- .../presentation/deallist/DealListScreen.kt | 22 +- .../alarm/presentation/main/MainActivity.kt | 40 +-- .../alarm/presentation/main/MainScreen.kt | 4 +- .../java/com/hotdeal/alarm/ui/theme/Theme.kt | 233 +++++++++++------- version.json | 12 +- 6 files changed, 166 insertions(+), 149 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9800070..cf93013 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -24,8 +24,8 @@ android { applicationId = "com.hotdeal.alarm" minSdk = 31 targetSdk = 35 - versionCode = 14 - versionName = "1.8.0" + versionCode = 15 + versionName = "1.9.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { diff --git a/app/src/main/java/com/hotdeal/alarm/presentation/deallist/DealListScreen.kt b/app/src/main/java/com/hotdeal/alarm/presentation/deallist/DealListScreen.kt index f73bae2..d1feeae 100644 --- a/app/src/main/java/com/hotdeal/alarm/presentation/deallist/DealListScreen.kt +++ b/app/src/main/java/com/hotdeal/alarm/presentation/deallist/DealListScreen.kt @@ -130,11 +130,13 @@ fun DealListScreen( ) } }, - colors = TopAppBarDefaults.topAppBarColors( - containerColor = MaterialTheme.colorScheme.surface - ) - ) - }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.surface, + scrolledContainerColor = MaterialTheme.colorScheme.surface + ), + modifier = Modifier.statusBarsPadding() + ) + }, floatingActionButton = { AnimatedVisibility( visible = showScrollToTop, @@ -148,7 +150,7 @@ fun DealListScreen( containerColor = MaterialTheme.colorScheme.primary, contentColor = MaterialTheme.colorScheme.onPrimary, shape = CircleShape, - modifier = Modifier.padding(bottom = 80.dp) // 메뉴키에 가려지지 않도록 상단으로 이동 + modifier = Modifier.navigationBarsPadding() ) { Icon( imageVector = Icons.Filled.KeyboardArrowUp, @@ -396,10 +398,10 @@ fun DealListScreen( } } - // EdgeToEdge: 하단 네비게이션 바 공간 확보 - item { - Spacer(modifier = Modifier.height(32.dp)) - } + // EdgeToEdge: 하단 네비게이션 바 공간 확보 + item { + Spacer(modifier = Modifier.height(16.dp)) + } } } } diff --git a/app/src/main/java/com/hotdeal/alarm/presentation/main/MainActivity.kt b/app/src/main/java/com/hotdeal/alarm/presentation/main/MainActivity.kt index 1fcf33e..471b028 100644 --- a/app/src/main/java/com/hotdeal/alarm/presentation/main/MainActivity.kt +++ b/app/src/main/java/com/hotdeal/alarm/presentation/main/MainActivity.kt @@ -133,22 +133,13 @@ class MainActivity : ComponentActivity() { * EdgeToEdge 설정 - One UI 7+ 대응 */ private fun setupEdgeToEdge() { - // WindowCompat을 사용한 설정 + // WindowCompat을 사용한 EdgeToEdge 설정 WindowCompat.setDecorFitsSystemWindows(window, false) - - // statusBarColor와 navigationBarColor를 투명하게 - window.statusBarColor = android.graphics.Color.TRANSPARENT - window.navigationBarColor = android.graphics.Color.TRANSPARENT - - // One UI 7+에서 시스템 바가 콘텐츠를 가리지 않도록 설정 + + // One UI 7+에서 시스템 바 인셋 처리 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) { - window.setDecorFitsSystemWindows(false) - - // 시스템 바 인셋 처리 ViewCompat.setOnApplyWindowInsetsListener(window.decorView.rootView) { view, insets -> val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) - val ime = insets.getInsets(WindowInsetsCompat.Type.ime()) - view.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) insets } @@ -159,29 +150,8 @@ class MainActivity : ComponentActivity() { WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS ) } - - // 시스템 바 아이콘 색상 설정 (라이트/다크 모드) - val decorView = window.decorView - @Suppress("DEPRECATION") - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) { - window.insetsController?.let { controller -> - // 상태바 아이콘 밝게 (다크 모드용) - controller.setSystemBarsAppearance( - 0, - android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS - ) - // 네비게이션바 아이콘 밝게 (다크 모드용) - controller.setSystemBarsAppearance( - 0, - android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS - ) - } - } else { - @Suppress("DEPRECATION") - decorView.systemUiVisibility = decorView.systemUiVisibility or - View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR or - View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR - } + + // 시스템 바 아이콘 색상 설정은 Theme.kt에서 처리 } override fun onDestroy() { diff --git a/app/src/main/java/com/hotdeal/alarm/presentation/main/MainScreen.kt b/app/src/main/java/com/hotdeal/alarm/presentation/main/MainScreen.kt index 9c0ef83..adc0d2d 100644 --- a/app/src/main/java/com/hotdeal/alarm/presentation/main/MainScreen.kt +++ b/app/src/main/java/com/hotdeal/alarm/presentation/main/MainScreen.kt @@ -67,9 +67,7 @@ fun MainScreen( } Column( - modifier = Modifier - .fillMaxSize() - .windowInsetsPadding(WindowInsets.safeDrawing) // 시스템 바 패딩 적용 + modifier = Modifier.fillMaxSize() ) { HorizontalPager( state = pagerState, diff --git a/app/src/main/java/com/hotdeal/alarm/ui/theme/Theme.kt b/app/src/main/java/com/hotdeal/alarm/ui/theme/Theme.kt index 0dbe31a..9a8a35e 100644 --- a/app/src/main/java/com/hotdeal/alarm/ui/theme/Theme.kt +++ b/app/src/main/java/com/hotdeal/alarm/ui/theme/Theme.kt @@ -17,109 +17,110 @@ import androidx.compose.ui.platform.LocalView import androidx.core.view.WindowCompat import com.hotdeal.alarm.domain.model.SiteType -// Light Theme Colors -private val LightPrimary = Color(0xFF1976D2) +// ============================================ +// Material You Style - Premium Color Palette +// ============================================ + +// Light Theme - Premium Palette +private val LightPrimary = Color(0xFF0061A4) private val LightOnPrimary = Color(0xFFFFFFFF) private val LightPrimaryContainer = Color(0xFFD1E4FF) private val LightOnPrimaryContainer = Color(0xFF001D36) -private val LightSecondary = Color(0xFFFF9800) +private val LightSecondary = Color(0xFF535F70) private val LightOnSecondary = Color(0xFFFFFFFF) -private val LightSecondaryContainer = Color(0xFFFFE0B2) -private val LightOnSecondaryContainer = Color(0xFF261800) +private val LightSecondaryContainer = Color(0xFFD7E3F8) +private val LightOnSecondaryContainer = Color(0xFF101C2B) -private val LightTertiary = Color(0xFF536DFE) +private val LightTertiary = Color(0xFF6B5778) private val LightOnTertiary = Color(0xFFFFFFFF) +private val LightTertiaryContainer = Color(0xFFF2DAFF) +private val LightOnTertiaryContainer = Color(0xFF251431) -private val LightBackground = Color(0xFFFAFAFA) -private val LightOnBackground = Color(0xFF1C1B1F) -private val LightSurface = Color(0xFFFFFFFF) -private val LightOnSurface = Color(0xFF1C1B1F) +private val LightBackground = Color(0xFFFDFCFF) +private val LightOnBackground = Color(0xFF1A1C1E) +private val LightSurface = Color(0xFFFDFCFF) +private val LightOnSurface = Color(0xFF1A1C1E) +private val LightSurfaceVariant = Color(0xFFDFE2EB) +private val LightOnSurfaceVariant = Color(0xFF43474E) -private val LightError = Color(0xFFD32F2F) +private val LightError = Color(0xFFBA1A1A) private val LightOnError = Color(0xFFFFFFFF) private val LightErrorContainer = Color(0xFFFFDAD6) private val LightOnErrorContainer = Color(0xFF410002) -private val LightOutline = Color(0xFF79747E) -private val LightOutlineVariant = Color(0xFFCAC4D0) +private val LightOutline = Color(0xFF73777F) +private val LightOutlineVariant = Color(0xFFC3C6CF) +private val LightInverseSurface = Color(0xFF2F3033) +private val LightInverseOnSurface = Color(0xFFF1F0F4) +private val LightInversePrimary = Color(0xFF9ECAFF) +private val LightSurfaceTint = Color(0xFF0061A4) -// Dark Theme Colors -private val DarkPrimary = Color(0xFF90CAF9) +// Dark Theme - Premium Palette +private val DarkPrimary = Color(0xFF9ECAFF) private val DarkOnPrimary = Color(0xFF003258) private val DarkPrimaryContainer = Color(0xFF00497D) private val DarkOnPrimaryContainer = Color(0xFFD1E4FF) -private val DarkSecondary = Color(0xFFFFB74D) -private val DarkOnSecondary = Color(0xFF442B00) -private val DarkSecondaryContainer = Color(0xFF624000) -private val DarkOnSecondaryContainer = Color(0xFFFFE0B2) +private val DarkSecondary = Color(0xFFBBC7DB) +private val DarkOnSecondary = Color(0xFF253140) +private val DarkSecondaryContainer = Color(0xFF3B4858) +private val DarkOnSecondaryContainer = Color(0xFFD7E3F8) -private val DarkTertiary = Color(0xFF8C9EFF) -private val DarkOnTertiary = Color(0xFF001A3F) +private val DarkTertiary = Color(0xFFD6BEE4) +private val DarkOnTertiary = Color(0xFF3B2948) +private val DarkTertiaryContainer = Color(0xFF523F5F) +private val DarkOnTertiaryContainer = Color(0xFFF2DAFF) -private val DarkBackground = Color(0xFF121212) -private val DarkOnBackground = Color(0xFFE0E0E0) -private val DarkSurface = Color(0xFF1E1E1E) -private val DarkOnSurface = Color(0xFFE0E0E0) +private val DarkBackground = Color(0xFF1A1C1E) +private val DarkOnBackground = Color(0xFFE2E2E6) +private val DarkSurface = Color(0xFF1A1C1E) +private val DarkOnSurface = Color(0xFFE2E2E6) +private val DarkSurfaceVariant = Color(0xFF43474E) +private val DarkOnSurfaceVariant = Color(0xFFC3C6CF) -private val DarkError = Color(0xFFCF6679) -private val DarkOnError = Color(0xFF000000) +private val DarkError = Color(0xFFFFB4AB) +private val DarkOnError = Color(0xFF690005) private val DarkErrorContainer = Color(0xFF93000A) private val DarkOnErrorContainer = Color(0xFFFFDAD6) -private val DarkOutline = Color(0xFF938F99) -private val DarkOutlineVariant = Color(0xFF49454F) +private val DarkOutline = Color(0xFF8D9199) +private val DarkOutlineVariant = Color(0xFF43474E) +private val DarkInverseSurface = Color(0xFFE2E2E6) +private val DarkInverseOnSurface = Color(0xFF2F3033) +private val DarkInversePrimary = Color(0xFF0061A4) +private val DarkSurfaceTint = Color(0xFF9ECAFF) -// ========================= -// index.html Inspired Colors -// ========================= +// ============================================ +// Site Colors - Premium Tones +// ============================================ -// Dark Theme (index.html style) -val IndexBgPrimary = Color(0xFF0f0f1a) -val IndexBgSecondary = Color(0xFF1a1a2e) -val IndexBgCard = Color(0xFF16162a) -val IndexBgCardHover = Color(0xFF1e1e3a) -val IndexBgInput = Color(0xFF252545) - -val IndexTextPrimary = Color(0xFFffffff) -val IndexTextSecondary = Color(0xFFa0a0b8) -val IndexTextMuted = Color(0xFF6b6b8a) - -val IndexAccentPrimary = Color(0xFF6366f1) -val IndexAccentSecondary = Color(0xFF8b5cf6) - -val IndexHotBadgeBg = Color(0x26EF4444) // rgba(239, 68, 68, 0.15) -val IndexHotBadgeText = Color(0xFFef4444) - -val IndexBoardBadgeBg = Color(0x26818CF8) // rgba(129, 140, 248, 0.15) -val IndexBoardBadgeText = Color(0xFF818cf8) - -// Light Theme (index.html style) -val IndexLightBgPrimary = Color(0xFFf8fafc) -val IndexLightBgSecondary = Color(0xFFffffff) -val IndexLightBgCard = Color(0xFFffffff) -val IndexLightBgCardHover = Color(0xFFf1f5f9) -val IndexLightBgInput = Color(0xFFf1f5f9) - -val IndexLightTextPrimary = Color(0xFF0f172a) -val IndexLightTextSecondary = Color(0xFF475569) -val IndexLightTextMuted = Color(0xFF94a3b8) - -val IndexLightAccentPrimary = Color(0xFF4f46e5) -val IndexLightAccentSecondary = Color(0xFF7c3aed) - -val IndexLightHotBadgeBg = Color(0x1ADC2626) // rgba(220, 38, 38, 0.1) -val IndexLightHotBadgeText = Color(0xFFdc2626) - -val IndexLightBoardBadgeBg = Color(0x1A4F46E5) // rgba(79, 70, 229, 0.1) -val IndexLightBoardBadgeText = Color(0xFF4f46e5) - -// Site Colors +// 뽐뿌 - Premium Pink val PpomppuColor = Color(0xFFE91E63) -val ClienColor = Color(0xFF4CAF50) -val RuriwebColor = Color(0xFF2196F3) -val CoolenjoyColor = Color(0xFFFF5722) +val PpomppuColorLight = Color(0xFFFCE4EC) +val PpomppuColorDark = Color(0xFFC2185B) + +// 클리앙 - Premium Green +val ClienColor = Color(0xFF2E7D32) +val ClienColorLight = Color(0xFFE8F5E9) +val ClienColorDark = Color(0xFF1B5E20) + +// 루리웹 - Premium Blue +val RuriwebColor = Color(0xFF1565C0) +val RuriwebColorLight = Color(0xFFE3F2FD) +val RuriwebColorDark = Color(0xFF0D47A1) + +// 쿨엔조이 - Premium Orange +val CoolenjoyColor = Color(0xFFEF6C00) +val CoolenjoyColorLight = Color(0xFFFFF3E0) +val CoolenjoyColorDark = Color(0xFFE65100) + +// Keyword Match - Light Red Theme +val KeywordMatchColor = Color(0xFFE53935) +val KeywordMatchColorLight = Color(0xFFFFEBEE) + +// Favorite - Premium Red +val FavoriteColor = Color(0xFFE53935) /** * 사이트별 색상 가져오기 @@ -134,6 +135,36 @@ fun getSiteColor(siteType: SiteType?): Color { } } +/** + * 사이트별 라이트 배경색 가져오기 + */ +fun getSiteColorLight(siteType: SiteType?): Color { + return when (siteType) { + SiteType.PPOMPPU -> PpomppuColorLight + SiteType.CLIEN -> ClienColorLight + SiteType.RURIWEB -> RuriwebColorLight + SiteType.COOLENJOY -> CoolenjoyColorLight + null -> Color.LightGray.copy(alpha = 0.3f) + } +} + +/** + * 사이트별 다크 배경색 가져오기 + */ +fun getSiteColorDark(siteType: SiteType?): Color { + return when (siteType) { + SiteType.PPOMPPU -> PpomppuColorDark + SiteType.CLIEN -> ClienColorDark + SiteType.RURIWEB -> RuriwebColorDark + SiteType.COOLENJOY -> CoolenjoyColorDark + null -> Color.DarkGray + } +} + +// ============================================ +// Color Schemes +// ============================================ + private val LightColorScheme = lightColorScheme( primary = LightPrimary, onPrimary = LightOnPrimary, @@ -145,16 +176,24 @@ private val LightColorScheme = lightColorScheme( onSecondaryContainer = LightOnSecondaryContainer, tertiary = LightTertiary, onTertiary = LightOnTertiary, + tertiaryContainer = LightTertiaryContainer, + onTertiaryContainer = LightOnTertiaryContainer, background = LightBackground, onBackground = LightOnBackground, surface = LightSurface, onSurface = LightOnSurface, + surfaceVariant = LightSurfaceVariant, + onSurfaceVariant = LightOnSurfaceVariant, error = LightError, onError = LightOnError, errorContainer = LightErrorContainer, onErrorContainer = LightOnErrorContainer, outline = LightOutline, - outlineVariant = LightOutlineVariant + outlineVariant = LightOutlineVariant, + inverseSurface = LightInverseSurface, + inverseOnSurface = LightInverseOnSurface, + inversePrimary = LightInversePrimary, + surfaceTint = LightSurfaceTint ) private val DarkColorScheme = darkColorScheme( @@ -168,16 +207,24 @@ private val DarkColorScheme = darkColorScheme( onSecondaryContainer = DarkOnSecondaryContainer, tertiary = DarkTertiary, onTertiary = DarkOnTertiary, + tertiaryContainer = DarkTertiaryContainer, + onTertiaryContainer = DarkOnTertiaryContainer, background = DarkBackground, onBackground = DarkOnBackground, surface = DarkSurface, onSurface = DarkOnSurface, + surfaceVariant = DarkSurfaceVariant, + onSurfaceVariant = DarkOnSurfaceVariant, error = DarkError, onError = DarkOnError, errorContainer = DarkErrorContainer, onErrorContainer = DarkOnErrorContainer, outline = DarkOutline, - outlineVariant = DarkOutlineVariant + outlineVariant = DarkOutlineVariant, + inverseSurface = DarkInverseSurface, + inverseOnSurface = DarkInverseOnSurface, + inversePrimary = DarkInversePrimary, + surfaceTint = DarkSurfaceTint ) @Composable @@ -197,19 +244,19 @@ fun HotDealTheme( val view = LocalView.current if (!view.isInEditMode) { - SideEffect { - val window = (view.context as Activity).window - // Edge-to-edge: 투명한 상태바 - window.statusBarColor = android.graphics.Color.TRANSPARENT - window.navigationBarColor = android.graphics.Color.TRANSPARENT - WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme - WindowCompat.getInsetsController(window, view).isAppearanceLightNavigationBars = !darkTheme - } + SideEffect { + val window = (view.context as Activity).window + // 시스템 바 색상을 앱 배경색과 일치시켜 이질감 제거 + window.statusBarColor = colorScheme.surface.toArgb() + window.navigationBarColor = colorScheme.surface.toArgb() + WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme + WindowCompat.getInsetsController(window, view).isAppearanceLightNavigationBars = !darkTheme + } + } - MaterialTheme( - colorScheme = colorScheme, - typography = AppTypography, - content = content - ) -} -} + MaterialTheme( + colorScheme = colorScheme, + typography = AppTypography, + content = content + ) +} \ No newline at end of file diff --git a/version.json b/version.json index ec311c1..5fc865f 100644 --- a/version.json +++ b/version.json @@ -1,14 +1,14 @@ { - "version": "1.6.0", - "versionCode": 12, + "version": "1.9.0", + "versionCode": 15, "minSdk": 31, "targetSdk": 35, "forceUpdate": false, "updateUrl": "https://git.webpluss.net/attachments/0482dc08-5216-4223-beda-2887501578d8", "changelog": [ - "Pull to Refresh 기능 추가 (아래로 당겨서 새로고침)", - "EdgeToEdge 개선 (투명 상태바/네비게이션바)", - "출처를 알 수 없는 앱 설치 권한 추가", - "WindowInsets 처리 개선" + "EdgeToEdge 색상 개선 - 시스템 바가 앱 테마와 일치", + "화면 공간 최적화 - 불필요한 패딩 제거", + "TopAppBar가 시스템 바 영역까지 확장", + "하단 네비게이션 영역 패딩 최적화" ] }