feat: EdgeToEdge 개선 - 시스템 바 색상 통일 및 화면 공간 최적화 (v1.9.0)

- MainScreen.kt: 불필요한 windowInsetsPadding 제거로 화면 공간 확보
- DealListScreen.kt: TopAppBar에 statusBarsPadding 적용, FAB에 navigationBarsPadding 적용
- Theme.kt: 시스템 바 색상을 앱 surface 색상과 일치시켜 이질감 해소
- MainActivity.kt: setupEdgeToEdge 함수 간소화 및 중복 코드 제거
- version.json: 1.9.0 버전 업데이트
This commit is contained in:
sanjeok77
2026-03-07 03:59:45 +09:00
parent bf2084626b
commit 2ab9557736
6 changed files with 166 additions and 149 deletions

View File

@@ -24,8 +24,8 @@ android {
applicationId = "com.hotdeal.alarm" applicationId = "com.hotdeal.alarm"
minSdk = 31 minSdk = 31
targetSdk = 35 targetSdk = 35
versionCode = 14 versionCode = 15
versionName = "1.8.0" versionName = "1.9.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables { vectorDrawables {

View File

@@ -131,8 +131,10 @@ fun DealListScreen(
} }
}, },
colors = TopAppBarDefaults.topAppBarColors( colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.surface containerColor = MaterialTheme.colorScheme.surface,
) scrolledContainerColor = MaterialTheme.colorScheme.surface
),
modifier = Modifier.statusBarsPadding()
) )
}, },
floatingActionButton = { floatingActionButton = {
@@ -148,7 +150,7 @@ fun DealListScreen(
containerColor = MaterialTheme.colorScheme.primary, containerColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.onPrimary, contentColor = MaterialTheme.colorScheme.onPrimary,
shape = CircleShape, shape = CircleShape,
modifier = Modifier.padding(bottom = 80.dp) // 메뉴키에 가려지지 않도록 상단으로 이동 modifier = Modifier.navigationBarsPadding()
) { ) {
Icon( Icon(
imageVector = Icons.Filled.KeyboardArrowUp, imageVector = Icons.Filled.KeyboardArrowUp,
@@ -398,7 +400,7 @@ fun DealListScreen(
// EdgeToEdge: 하단 네비게이션 바 공간 확보 // EdgeToEdge: 하단 네비게이션 바 공간 확보
item { item {
Spacer(modifier = Modifier.height(32.dp)) Spacer(modifier = Modifier.height(16.dp))
} }
} }
} }

View File

@@ -133,22 +133,13 @@ class MainActivity : ComponentActivity() {
* EdgeToEdge 설정 - One UI 7+ 대응 * EdgeToEdge 설정 - One UI 7+ 대응
*/ */
private fun setupEdgeToEdge() { private fun setupEdgeToEdge() {
// WindowCompat을 사용한 설정 // WindowCompat을 사용한 EdgeToEdge 설정
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
// statusBarColor와 navigationBarColor를 투명하게 // One UI 7+에서 시스템 바 인셋 처리
window.statusBarColor = android.graphics.Color.TRANSPARENT
window.navigationBarColor = android.graphics.Color.TRANSPARENT
// One UI 7+에서 시스템 바가 콘텐츠를 가리지 않도록 설정
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
window.setDecorFitsSystemWindows(false)
// 시스템 바 인셋 처리
ViewCompat.setOnApplyWindowInsetsListener(window.decorView.rootView) { view, insets -> ViewCompat.setOnApplyWindowInsetsListener(window.decorView.rootView) { view, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
val ime = insets.getInsets(WindowInsetsCompat.Type.ime())
view.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) view.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets insets
} }
@@ -160,28 +151,7 @@ class MainActivity : ComponentActivity() {
) )
} }
// 시스템 바 아이콘 색상 설정 (라이트/다크 모드) // 시스템 바 아이콘 색상 설정은 Theme.kt에서 처리
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
}
} }
override fun onDestroy() { override fun onDestroy() {

View File

@@ -67,9 +67,7 @@ fun MainScreen(
} }
Column( Column(
modifier = Modifier modifier = Modifier.fillMaxSize()
.fillMaxSize()
.windowInsetsPadding(WindowInsets.safeDrawing) // 시스템 바 패딩 적용
) { ) {
HorizontalPager( HorizontalPager(
state = pagerState, state = pagerState,

View File

@@ -17,109 +17,110 @@ import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import com.hotdeal.alarm.domain.model.SiteType 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 LightOnPrimary = Color(0xFFFFFFFF)
private val LightPrimaryContainer = Color(0xFFD1E4FF) private val LightPrimaryContainer = Color(0xFFD1E4FF)
private val LightOnPrimaryContainer = Color(0xFF001D36) private val LightOnPrimaryContainer = Color(0xFF001D36)
private val LightSecondary = Color(0xFFFF9800) private val LightSecondary = Color(0xFF535F70)
private val LightOnSecondary = Color(0xFFFFFFFF) private val LightOnSecondary = Color(0xFFFFFFFF)
private val LightSecondaryContainer = Color(0xFFFFE0B2) private val LightSecondaryContainer = Color(0xFFD7E3F8)
private val LightOnSecondaryContainer = Color(0xFF261800) private val LightOnSecondaryContainer = Color(0xFF101C2B)
private val LightTertiary = Color(0xFF536DFE) private val LightTertiary = Color(0xFF6B5778)
private val LightOnTertiary = Color(0xFFFFFFFF) private val LightOnTertiary = Color(0xFFFFFFFF)
private val LightTertiaryContainer = Color(0xFFF2DAFF)
private val LightOnTertiaryContainer = Color(0xFF251431)
private val LightBackground = Color(0xFFFAFAFA) private val LightBackground = Color(0xFFFDFCFF)
private val LightOnBackground = Color(0xFF1C1B1F) private val LightOnBackground = Color(0xFF1A1C1E)
private val LightSurface = Color(0xFFFFFFFF) private val LightSurface = Color(0xFFFDFCFF)
private val LightOnSurface = Color(0xFF1C1B1F) 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 LightOnError = Color(0xFFFFFFFF)
private val LightErrorContainer = Color(0xFFFFDAD6) private val LightErrorContainer = Color(0xFFFFDAD6)
private val LightOnErrorContainer = Color(0xFF410002) private val LightOnErrorContainer = Color(0xFF410002)
private val LightOutline = Color(0xFF79747E) private val LightOutline = Color(0xFF73777F)
private val LightOutlineVariant = Color(0xFFCAC4D0) 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 // Dark Theme - Premium Palette
private val DarkPrimary = Color(0xFF90CAF9) private val DarkPrimary = Color(0xFF9ECAFF)
private val DarkOnPrimary = Color(0xFF003258) private val DarkOnPrimary = Color(0xFF003258)
private val DarkPrimaryContainer = Color(0xFF00497D) private val DarkPrimaryContainer = Color(0xFF00497D)
private val DarkOnPrimaryContainer = Color(0xFFD1E4FF) private val DarkOnPrimaryContainer = Color(0xFFD1E4FF)
private val DarkSecondary = Color(0xFFFFB74D) private val DarkSecondary = Color(0xFFBBC7DB)
private val DarkOnSecondary = Color(0xFF442B00) private val DarkOnSecondary = Color(0xFF253140)
private val DarkSecondaryContainer = Color(0xFF624000) private val DarkSecondaryContainer = Color(0xFF3B4858)
private val DarkOnSecondaryContainer = Color(0xFFFFE0B2) private val DarkOnSecondaryContainer = Color(0xFFD7E3F8)
private val DarkTertiary = Color(0xFF8C9EFF) private val DarkTertiary = Color(0xFFD6BEE4)
private val DarkOnTertiary = Color(0xFF001A3F) private val DarkOnTertiary = Color(0xFF3B2948)
private val DarkTertiaryContainer = Color(0xFF523F5F)
private val DarkOnTertiaryContainer = Color(0xFFF2DAFF)
private val DarkBackground = Color(0xFF121212) private val DarkBackground = Color(0xFF1A1C1E)
private val DarkOnBackground = Color(0xFFE0E0E0) private val DarkOnBackground = Color(0xFFE2E2E6)
private val DarkSurface = Color(0xFF1E1E1E) private val DarkSurface = Color(0xFF1A1C1E)
private val DarkOnSurface = Color(0xFFE0E0E0) private val DarkOnSurface = Color(0xFFE2E2E6)
private val DarkSurfaceVariant = Color(0xFF43474E)
private val DarkOnSurfaceVariant = Color(0xFFC3C6CF)
private val DarkError = Color(0xFFCF6679) private val DarkError = Color(0xFFFFB4AB)
private val DarkOnError = Color(0xFF000000) private val DarkOnError = Color(0xFF690005)
private val DarkErrorContainer = Color(0xFF93000A) private val DarkErrorContainer = Color(0xFF93000A)
private val DarkOnErrorContainer = Color(0xFFFFDAD6) private val DarkOnErrorContainer = Color(0xFFFFDAD6)
private val DarkOutline = Color(0xFF938F99) private val DarkOutline = Color(0xFF8D9199)
private val DarkOutlineVariant = Color(0xFF49454F) 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) // 뽐뿌 - Premium Pink
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
val PpomppuColor = Color(0xFFE91E63) val PpomppuColor = Color(0xFFE91E63)
val ClienColor = Color(0xFF4CAF50) val PpomppuColorLight = Color(0xFFFCE4EC)
val RuriwebColor = Color(0xFF2196F3) val PpomppuColorDark = Color(0xFFC2185B)
val CoolenjoyColor = Color(0xFFFF5722)
// 클리앙 - 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( private val LightColorScheme = lightColorScheme(
primary = LightPrimary, primary = LightPrimary,
onPrimary = LightOnPrimary, onPrimary = LightOnPrimary,
@@ -145,16 +176,24 @@ private val LightColorScheme = lightColorScheme(
onSecondaryContainer = LightOnSecondaryContainer, onSecondaryContainer = LightOnSecondaryContainer,
tertiary = LightTertiary, tertiary = LightTertiary,
onTertiary = LightOnTertiary, onTertiary = LightOnTertiary,
tertiaryContainer = LightTertiaryContainer,
onTertiaryContainer = LightOnTertiaryContainer,
background = LightBackground, background = LightBackground,
onBackground = LightOnBackground, onBackground = LightOnBackground,
surface = LightSurface, surface = LightSurface,
onSurface = LightOnSurface, onSurface = LightOnSurface,
surfaceVariant = LightSurfaceVariant,
onSurfaceVariant = LightOnSurfaceVariant,
error = LightError, error = LightError,
onError = LightOnError, onError = LightOnError,
errorContainer = LightErrorContainer, errorContainer = LightErrorContainer,
onErrorContainer = LightOnErrorContainer, onErrorContainer = LightOnErrorContainer,
outline = LightOutline, outline = LightOutline,
outlineVariant = LightOutlineVariant outlineVariant = LightOutlineVariant,
inverseSurface = LightInverseSurface,
inverseOnSurface = LightInverseOnSurface,
inversePrimary = LightInversePrimary,
surfaceTint = LightSurfaceTint
) )
private val DarkColorScheme = darkColorScheme( private val DarkColorScheme = darkColorScheme(
@@ -168,16 +207,24 @@ private val DarkColorScheme = darkColorScheme(
onSecondaryContainer = DarkOnSecondaryContainer, onSecondaryContainer = DarkOnSecondaryContainer,
tertiary = DarkTertiary, tertiary = DarkTertiary,
onTertiary = DarkOnTertiary, onTertiary = DarkOnTertiary,
tertiaryContainer = DarkTertiaryContainer,
onTertiaryContainer = DarkOnTertiaryContainer,
background = DarkBackground, background = DarkBackground,
onBackground = DarkOnBackground, onBackground = DarkOnBackground,
surface = DarkSurface, surface = DarkSurface,
onSurface = DarkOnSurface, onSurface = DarkOnSurface,
surfaceVariant = DarkSurfaceVariant,
onSurfaceVariant = DarkOnSurfaceVariant,
error = DarkError, error = DarkError,
onError = DarkOnError, onError = DarkOnError,
errorContainer = DarkErrorContainer, errorContainer = DarkErrorContainer,
onErrorContainer = DarkOnErrorContainer, onErrorContainer = DarkOnErrorContainer,
outline = DarkOutline, outline = DarkOutline,
outlineVariant = DarkOutlineVariant outlineVariant = DarkOutlineVariant,
inverseSurface = DarkInverseSurface,
inverseOnSurface = DarkInverseOnSurface,
inversePrimary = DarkInversePrimary,
surfaceTint = DarkSurfaceTint
) )
@Composable @Composable
@@ -199,12 +246,13 @@ fun HotDealTheme(
if (!view.isInEditMode) { if (!view.isInEditMode) {
SideEffect { SideEffect {
val window = (view.context as Activity).window val window = (view.context as Activity).window
// Edge-to-edge: 투명한 상태바 // 시스템 바 색상을 앱 배경색과 일치시켜 이질감 제거
window.statusBarColor = android.graphics.Color.TRANSPARENT window.statusBarColor = colorScheme.surface.toArgb()
window.navigationBarColor = android.graphics.Color.TRANSPARENT window.navigationBarColor = colorScheme.surface.toArgb()
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme
WindowCompat.getInsetsController(window, view).isAppearanceLightNavigationBars = !darkTheme WindowCompat.getInsetsController(window, view).isAppearanceLightNavigationBars = !darkTheme
} }
}
MaterialTheme( MaterialTheme(
colorScheme = colorScheme, colorScheme = colorScheme,
@@ -212,4 +260,3 @@ fun HotDealTheme(
content = content content = content
) )
} }
}

View File

@@ -1,14 +1,14 @@
{ {
"version": "1.6.0", "version": "1.9.0",
"versionCode": 12, "versionCode": 15,
"minSdk": 31, "minSdk": 31,
"targetSdk": 35, "targetSdk": 35,
"forceUpdate": false, "forceUpdate": false,
"updateUrl": "https://git.webpluss.net/attachments/0482dc08-5216-4223-beda-2887501578d8", "updateUrl": "https://git.webpluss.net/attachments/0482dc08-5216-4223-beda-2887501578d8",
"changelog": [ "changelog": [
"Pull to Refresh 기능 추가 (아래로 당겨서 새로고침)", "EdgeToEdge 색상 개선 - 시스템 바가 앱 테마와 일치",
"EdgeToEdge 개선 (투명 상태바/네비게이션바)", "화면 공간 최적화 - 불필요한 패딩 제거",
"출처를 알 수 없는 앱 설치 권한 추가", "TopAppBar가 시스템 바 영역까지 확장",
"WindowInsets 처리 개선" "하단 네비게이션 영역 패딩 최적화"
] ]
} }