feat: EdgeToEdge 개선, Pull to Refresh 추가, 출처를 알 수 없는 앱 설치 권한 추가 (v1.6.0)
- EdgeToEdge: 투명 상태바/네비게이션바 설정, WindowInsets 처리 개선 - Pull to Refresh: 아래로 당겨서 새로고침 기능 추가 - 권한: REQUEST_INSTALL_PACKAGES 추가로 APK 업데이트 설치 지원 - 버전: 1.5.0 -> 1.6.0 (versionCode 11 -> 12)
This commit is contained in:
@@ -24,8 +24,8 @@ android {
|
||||
applicationId = "com.hotdeal.alarm"
|
||||
minSdk = 31
|
||||
targetSdk = 35
|
||||
versionCode = 11
|
||||
versionName = "1.5.0"
|
||||
versionCode = 12
|
||||
versionName = "1.6.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
<!-- Boot Completed -->
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
|
||||
<!-- Install Unknown Apps (for APK updates) -->
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
|
||||
<application
|
||||
android:name=".HotDealApplication"
|
||||
android:allowBackup="true"
|
||||
|
||||
@@ -16,11 +16,14 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material.icons.outlined.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.material3.pulltorefresh.PullToRefreshContainer
|
||||
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -40,6 +43,18 @@ fun DealListScreen(
|
||||
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
|
||||
// Pull to Refresh 상태
|
||||
val pullToRefreshState = rememberPullToRefreshState()
|
||||
var isRefreshing by remember { mutableStateOf(false) }
|
||||
|
||||
// 새로고침 완료 감지
|
||||
LaunchedEffect(uiState) {
|
||||
if (uiState !is MainUiState.Loading) {
|
||||
isRefreshing = false
|
||||
pullToRefreshState.endRefresh()
|
||||
}
|
||||
}
|
||||
|
||||
var searchText by remember { mutableStateOf("") }
|
||||
var selectedSiteFilter by remember { mutableStateOf<SiteType?>(null) }
|
||||
var showFavoritesOnly by remember { mutableStateOf(false) }
|
||||
@@ -108,252 +123,274 @@ fun DealListScreen(
|
||||
)
|
||||
)
|
||||
},
|
||||
contentWindowInsets = WindowInsets.systemBars
|
||||
contentWindowInsets = WindowInsets(0, 0, 0, 0)
|
||||
) { paddingValues ->
|
||||
Column(
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
.nestedScroll(pullToRefreshState.nestedScrollConnection)
|
||||
) {
|
||||
// 필터 메뉴
|
||||
AnimatedVisibility(
|
||||
visible = showFilterMenu,
|
||||
enter = expandVertically(animationSpec = spring(stiffness = Spring.StiffnessLow)) + fadeIn(),
|
||||
exit = shrinkVertically(animationSpec = spring(stiffness = Spring.StiffnessLow)) + fadeOut()
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
.consumeWindowInsets(paddingValues)
|
||||
) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f)
|
||||
)
|
||||
// 필터 메뉴
|
||||
AnimatedVisibility(
|
||||
visible = showFilterMenu,
|
||||
enter = expandVertically(animationSpec = spring(stiffness = Spring.StiffnessLow)) + fadeIn(),
|
||||
exit = shrinkVertically(animationSpec = spring(stiffness = Spring.StiffnessLow)) + fadeOut()
|
||||
) {
|
||||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.FilterAlt,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = "사이트 필터",
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
}
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f)
|
||||
)
|
||||
) {
|
||||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.FilterAlt,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = "사이트 필터",
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.horizontalScroll(rememberScrollState()),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
EnhancedFilterChip(
|
||||
selected = selectedSiteFilter == null,
|
||||
onClick = { selectedSiteFilter = null },
|
||||
label = "전체",
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
|
||||
SiteType.entries.forEach { siteType ->
|
||||
val color = getSiteColor(siteType)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.horizontalScroll(rememberScrollState()),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
EnhancedFilterChip(
|
||||
selected = selectedSiteFilter == siteType,
|
||||
onClick = {
|
||||
selectedSiteFilter = if (selectedSiteFilter == siteType) null else siteType
|
||||
},
|
||||
label = siteType.displayName,
|
||||
color = color
|
||||
selected = selectedSiteFilter == null,
|
||||
onClick = { selectedSiteFilter = null },
|
||||
label = "전체",
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
|
||||
SiteType.entries.forEach { siteType ->
|
||||
val color = getSiteColor(siteType)
|
||||
EnhancedFilterChip(
|
||||
selected = selectedSiteFilter == siteType,
|
||||
onClick = {
|
||||
selectedSiteFilter = if (selectedSiteFilter == siteType) null else siteType
|
||||
},
|
||||
label = siteType.displayName,
|
||||
color = color
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
// 특수 필터
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
// 내 키워드 필터
|
||||
EnhancedFilterChip(
|
||||
selected = showKeywordMatchOnly,
|
||||
onClick = { showKeywordMatchOnly = !showKeywordMatchOnly },
|
||||
label = "내 키워드",
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
|
||||
// 즐겨찾기 필터
|
||||
EnhancedFilterChip(
|
||||
selected = showFavoritesOnly,
|
||||
onClick = { showFavoritesOnly = !showFavoritesOnly },
|
||||
label = "즐겨찾기",
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
// 특수 필터
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
// 내 키워드 필터
|
||||
EnhancedFilterChip(
|
||||
selected = showKeywordMatchOnly,
|
||||
onClick = { showKeywordMatchOnly = !showKeywordMatchOnly },
|
||||
label = "내 키워드",
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
|
||||
// 즐겨찾기 필터
|
||||
EnhancedFilterChip(
|
||||
selected = showFavoritesOnly,
|
||||
onClick = { showFavoritesOnly = !showFavoritesOnly },
|
||||
label = "즐겨찾기",
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
// 검색창
|
||||
OutlinedTextField(
|
||||
value = searchText,
|
||||
onValueChange = { searchText = it },
|
||||
placeholder = {
|
||||
Text(
|
||||
text = "제목으로 검색...",
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f)
|
||||
)
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
singleLine = true,
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Search,
|
||||
contentDescription = "검색",
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
},
|
||||
trailingIcon = {
|
||||
if (searchText.isNotEmpty()) {
|
||||
IconButton(onClick = { searchText = "" }) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Close,
|
||||
contentDescription = "지우기",
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
focusedBorderColor = MaterialTheme.colorScheme.primary,
|
||||
unfocusedBorderColor = MaterialTheme.colorScheme.outline.copy(alpha = 0.3f)
|
||||
)
|
||||
)
|
||||
|
||||
// 딜 리스트
|
||||
when (val state = uiState) {
|
||||
is MainUiState.Loading -> {
|
||||
DealListSkeleton(count = 5)
|
||||
}
|
||||
|
||||
is MainUiState.Success -> {
|
||||
val filteredDeals = remember(state.deals, searchText, selectedSiteFilter, showFavoritesOnly, showKeywordMatchOnly) {
|
||||
state.deals.filter { deal ->
|
||||
val matchesSearch = searchText.isBlank() || deal.title.contains(searchText, ignoreCase = true)
|
||||
val matchesSite = selectedSiteFilter == null || deal.siteType == selectedSiteFilter
|
||||
val matchesFavorite = !showFavoritesOnly || deal.isFavorite
|
||||
val matchesKeyword = !showKeywordMatchOnly || deal.isKeywordMatch
|
||||
matchesSearch && matchesSite && matchesFavorite && matchesKeyword
|
||||
}
|
||||
}
|
||||
|
||||
if (filteredDeals.isEmpty()) {
|
||||
if (state.deals.isEmpty()) {
|
||||
NoDealsState(onRefresh = { viewModel.refresh() })
|
||||
} else {
|
||||
val selectedFilter = selectedSiteFilter
|
||||
val message = when {
|
||||
showKeywordMatchOnly -> "키워드 매칭된 핫딜이 없습니다"
|
||||
showFavoritesOnly -> "즐겨찾기한 핫딜이 없습니다"
|
||||
selectedFilter != null -> "${selectedFilter.displayName}의 핫딜이 없습니다"
|
||||
searchText.isNotBlank() -> "'$searchText'에 대한 검색 결과가 없습니다"
|
||||
else -> "표시할 핫딜이 없습니다"
|
||||
}
|
||||
EmptyState(
|
||||
title = "결과가 없습니다",
|
||||
message = message,
|
||||
icon = Icons.Outlined.Search
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Surface(
|
||||
modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.padding(horizontal = 12.dp, vertical = 6.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Inventory2,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.size(16.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(6.dp))
|
||||
Text(
|
||||
text = "${filteredDeals.size}개의 핫딜",
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
if (selectedSiteFilter != null) {
|
||||
val filter = selectedSiteFilter!!
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = "• ${filter.displayName}",
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = getSiteColor(filter)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
items(
|
||||
items = filteredDeals,
|
||||
key = { it.id }
|
||||
) { deal ->
|
||||
AnimatedVisibility(
|
||||
visible = true,
|
||||
enter = fadeIn(animationSpec = tween(300)) +
|
||||
slideInVertically(
|
||||
animationSpec = tween(300),
|
||||
initialOffsetY = { it / 8 }
|
||||
),
|
||||
exit = fadeOut(animationSpec = tween(200))
|
||||
) {
|
||||
DealItem(
|
||||
deal = deal,
|
||||
onClick = {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(deal.url))
|
||||
context.startActivity(intent)
|
||||
},
|
||||
onFavoriteToggle = { dealId ->
|
||||
viewModel.toggleFavorite(dealId)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// EdgeToEdge: 하단 네비게이션 바 공간 확보
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is MainUiState.Error -> {
|
||||
ErrorState(
|
||||
message = state.message,
|
||||
onRetry = { viewModel.refresh() }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 검색창
|
||||
OutlinedTextField(
|
||||
value = searchText,
|
||||
onValueChange = { searchText = it },
|
||||
placeholder = {
|
||||
Text(
|
||||
text = "제목으로 검색...",
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f)
|
||||
)
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
singleLine = true,
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Search,
|
||||
contentDescription = "검색",
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
},
|
||||
trailingIcon = {
|
||||
if (searchText.isNotEmpty()) {
|
||||
IconButton(onClick = { searchText = "" }) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Close,
|
||||
contentDescription = "지우기",
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
focusedBorderColor = MaterialTheme.colorScheme.primary,
|
||||
unfocusedBorderColor = MaterialTheme.colorScheme.outline.copy(alpha = 0.3f)
|
||||
)
|
||||
// Pull to Refresh 인디케이터
|
||||
PullToRefreshContainer(
|
||||
state = pullToRefreshState,
|
||||
modifier = Modifier.align(Alignment.TopCenter),
|
||||
containerColor = MaterialTheme.colorScheme.primaryContainer,
|
||||
contentColor = MaterialTheme.colorScheme.onPrimaryContainer
|
||||
)
|
||||
|
||||
// 딜 리스트
|
||||
when (val state = uiState) {
|
||||
is MainUiState.Loading -> {
|
||||
DealListSkeleton(count = 5)
|
||||
}
|
||||
|
||||
is MainUiState.Success -> {
|
||||
val filteredDeals = remember(state.deals, searchText, selectedSiteFilter, showFavoritesOnly, showKeywordMatchOnly) {
|
||||
state.deals.filter { deal ->
|
||||
val matchesSearch = searchText.isBlank() ||
|
||||
deal.title.contains(searchText, ignoreCase = true)
|
||||
val matchesSite = selectedSiteFilter == null ||
|
||||
deal.siteType == selectedSiteFilter
|
||||
val matchesFavorite = !showFavoritesOnly || deal.isFavorite
|
||||
val matchesKeyword = !showKeywordMatchOnly || deal.isKeywordMatch
|
||||
matchesSearch && matchesSite && matchesFavorite && matchesKeyword
|
||||
}
|
||||
}
|
||||
|
||||
if (filteredDeals.isEmpty()) {
|
||||
if (state.deals.isEmpty()) {
|
||||
NoDealsState(onRefresh = { viewModel.refresh() })
|
||||
} else {
|
||||
val selectedFilter = selectedSiteFilter
|
||||
val message = when {
|
||||
showKeywordMatchOnly -> "키워드 매칭된 핫딜이 없습니다"
|
||||
showFavoritesOnly -> "즐겨찾기한 핫딜이 없습니다"
|
||||
selectedFilter != null -> "${selectedFilter.displayName}의 핫딜이 없습니다"
|
||||
searchText.isNotBlank() -> "'$searchText'에 대한 검색 결과가 없습니다"
|
||||
else -> "표시할 핫딜이 없습니다"
|
||||
}
|
||||
EmptyState(
|
||||
title = "결과가 없습니다",
|
||||
message = message,
|
||||
icon = Icons.Outlined.Search
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Surface(
|
||||
modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.padding(horizontal = 12.dp, vertical = 6.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Inventory2,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.size(16.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(6.dp))
|
||||
Text(
|
||||
text = "${filteredDeals.size}개의 핫딜",
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
if (selectedSiteFilter != null) {
|
||||
val filter = selectedSiteFilter!!
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = "• ${filter.displayName}",
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = getSiteColor(filter)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
items(
|
||||
items = filteredDeals,
|
||||
key = { it.id }
|
||||
) { deal ->
|
||||
AnimatedVisibility(
|
||||
visible = true,
|
||||
enter = fadeIn(animationSpec = tween(300)) +
|
||||
slideInVertically(
|
||||
animationSpec = tween(300),
|
||||
initialOffsetY = { it / 8 }
|
||||
),
|
||||
exit = fadeOut(animationSpec = tween(200))
|
||||
) {
|
||||
DealItem(
|
||||
deal = deal,
|
||||
onClick = {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(deal.url))
|
||||
context.startActivity(intent)
|
||||
},
|
||||
onFavoriteToggle = { dealId ->
|
||||
viewModel.toggleFavorite(dealId)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is MainUiState.Error -> {
|
||||
ErrorState(
|
||||
message = state.message,
|
||||
onRetry = { viewModel.refresh() }
|
||||
)
|
||||
|
||||
// 새로고침 트리거
|
||||
LaunchedEffect(pullToRefreshState.isRefreshing) {
|
||||
if (pullToRefreshState.isRefreshing) {
|
||||
isRefreshing = true
|
||||
viewModel.refresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,8 @@ import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.hotdeal.alarm.ui.theme.HotDealTheme
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="Theme.HotDealAlarm" parent="android:Theme.Material.Light.NoActionBar">
|
||||
<item name="android:colorPrimary">@color/primary</item>
|
||||
<item name="android:colorPrimaryDark">@color/primary_dark</item>
|
||||
<item name="android:colorAccent">@color/secondary</item>
|
||||
<item name="android:statusBarColor">@color/primary_dark</item>
|
||||
<item name="android:navigationBarColor">@color/background</item>
|
||||
<!-- EdgeToEdge compatible theme using AppCompat -->
|
||||
<style name="Theme.HotDealAlarm" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<item name="colorPrimary">@color/primary</item>
|
||||
<item name="colorPrimaryDark">@color/primary_dark</item>
|
||||
<item name="colorAccent">@color/secondary</item>
|
||||
<!-- EdgeToEdge: 투명 상태바/네비게이션바 -->
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
<item name="android:windowLightNavigationBar">true</item>
|
||||
<item name="android:enforceNavigationBarContrast">false</item>
|
||||
<item name="android:enforceStatusBarContrast">false</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user