diff --git a/app/src/main/java/com/doyoonkim/knutice/AppNavHost.kt b/app/src/main/java/com/doyoonkim/knutice/AppNavHost.kt index 0c3f28dc..c67b368d 100644 --- a/app/src/main/java/com/doyoonkim/knutice/AppNavHost.kt +++ b/app/src/main/java/com/doyoonkim/knutice/AppNavHost.kt @@ -2,9 +2,12 @@ package com.doyoonkim.knutice import android.net.Uri import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.calculateEndPadding +import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.LayoutDirection import androidx.lifecycle.ViewModelProvider import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost @@ -23,8 +26,8 @@ fun AppNavHost( NavHost( modifier = modifier.padding( PaddingValues( - top = contentPadding.calculateTopPadding(), -// bottom = contentPadding.calculateBottomPadding() + start = contentPadding.calculateStartPadding(LayoutDirection.Ltr), + end = contentPadding.calculateEndPadding(LayoutDirection.Ltr) ) ), navController = navController, diff --git a/app/src/main/java/com/doyoonkim/knutice/MainActivity.kt b/app/src/main/java/com/doyoonkim/knutice/MainActivity.kt index d9e20ff3..4e46c739 100644 --- a/app/src/main/java/com/doyoonkim/knutice/MainActivity.kt +++ b/app/src/main/java/com/doyoonkim/knutice/MainActivity.kt @@ -10,46 +10,30 @@ import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.BottomNavigationItem import androidx.compose.material3.BottomAppBar import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog import androidx.core.view.WindowCompat import androidx.lifecycle.ViewModelProvider @@ -58,16 +42,16 @@ import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import com.doyoonkim.common.navigation.NavRoutes import com.doyoonkim.common.theme.KNUTICETheme -import com.doyoonkim.common.theme.containerBackgroundSolid import com.doyoonkim.common.theme.subTitle import com.doyoonkim.common.theme.title import com.doyoonkim.common.ui.PermissionRationaleComposable import com.doyoonkim.common.R +import com.doyoonkim.common.theme.displayBackground +import com.doyoonkim.common.theme.onAnyBackground import com.doyoonkim.notification.local.NotificationAlarmScheduler import kotlinx.coroutines.delay import javax.inject.Inject -@OptIn(ExperimentalMaterial3Api::class) class MainActivity : ComponentActivity() { @Inject lateinit var viewModelFactory: ViewModelProvider.Factory @@ -91,11 +75,11 @@ class MainActivity : ComponentActivity() { var showPermissionRationale by remember { mutableStateOf(false) } navController = rememberNavController() - // Bottom Bar Handling - var bottomBarState = Triple(true, false, false) + // SharedScaffoldHandling + var sharedScaffoldState: Triple val backStackEntryState by navController.currentBackStackEntryAsState() - backStackEntryState?.destination?.route.let { route -> - bottomBarState = when(route) { + backStackEntryState?.destination?.route.let { + sharedScaffoldState = when(it) { NavRoutes.Home.route -> Triple(true, true, false) NavRoutes.Bookmark.route -> Triple(true, false, true) else -> Triple(false, false, false) @@ -127,79 +111,9 @@ class MainActivity : ComponentActivity() { } Scaffold( - modifier = Modifier.fillMaxSize() - .background(MaterialTheme.colorScheme.containerBackgroundSolid), - topBar = { - TopAppBar( - title = { - Row( - modifier = Modifier.fillMaxWidth().wrapContentHeight(), - horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically - ) { - if (!bottomBarState.first) { - IconButton( - onClick = { - navController.popBackStack() - } - ) { - Image( - painter = painterResource(R.drawable.baseline_arrow_back_ios_new_24), - contentDescription = "back", - modifier = Modifier.wrapContentSize(), - colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.title) - ) - } - } - - Text( - modifier = Modifier.fillMaxWidth(), - text = stringResource(R.string.app_name), - textAlign = TextAlign.Left, - fontSize = 20.sp, - fontWeight = FontWeight.ExtraBold, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - color = MaterialTheme.colorScheme.title - ) - } - }, - actions = { - if (bottomBarState.first) { - IconButton( - onClick = { - navController.navigate(NavRoutes.NoticeSearch.route) - } - ) { - Image( - painter = painterResource(R.drawable.baseline_search_24), - contentDescription = "Search", - modifier = Modifier.wrapContentSize(), - colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.title) - ) - } - IconButton( - onClick = { - navController.navigate(NavRoutes.Settings.route) - } - ) { - Image( - painter = painterResource(R.drawable.baseline_settings_24), - contentDescription = "Settings", - modifier = Modifier.wrapContentSize(), - colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.title) - ) - } - } - }, - colors = TopAppBarDefaults.topAppBarColors( - containerColor = MaterialTheme.colorScheme.containerBackgroundSolid, - titleContentColor = MaterialTheme.colorScheme.title - ) - ) - }, + modifier = Modifier.fillMaxSize(), bottomBar = { - if (bottomBarState.first) { + if (sharedScaffoldState.first) { BottomAppBar( modifier = Modifier .wrapContentSize() @@ -208,10 +122,10 @@ class MainActivity : ComponentActivity() { actions = { // https://developer.android.com/develop/ui/compose/navigation#bottom-nav BottomNavigationItem( - selected = bottomBarState.second, + selected = sharedScaffoldState.second, enabled = true, onClick = { - if (!bottomBarState.second) { + if (!sharedScaffoldState.second) { navController.navigate(NavRoutes.Home.route) } }, @@ -229,10 +143,10 @@ class MainActivity : ComponentActivity() { unselectedContentColor = MaterialTheme.colorScheme.subTitle ) BottomNavigationItem( - selected = bottomBarState.third, + selected = sharedScaffoldState.third, enabled = true, onClick = { - if (!bottomBarState.third) { + if (!sharedScaffoldState.third) { navController.navigate(NavRoutes.Bookmark.route) } }, @@ -249,13 +163,13 @@ class MainActivity : ComponentActivity() { selectedContentColor = MaterialTheme.colorScheme.title, unselectedContentColor = MaterialTheme.colorScheme.subTitle ) - } + }, + containerColor = MaterialTheme.colorScheme.onAnyBackground ) } }, - containerColor = MaterialTheme.colorScheme.containerBackgroundSolid, + containerColor = MaterialTheme.colorScheme.displayBackground ) { contentPadding -> - AppNavHost( modifier = Modifier, contentPadding = contentPadding, @@ -263,7 +177,6 @@ class MainActivity : ComponentActivity() { viewModelFactory = viewModelFactory, onExit = { activity.finish() } ) - LaunchedEffect(Unit) { // Intent handling (access application via onCreate call; click push notification when app is closed.) Log.d("MainActivity", "Intent received: ${launchedIntent?.data}") diff --git a/common/src/main/java/com/doyoonkim/common/theme/Color.kt b/common/src/main/java/com/doyoonkim/common/theme/Color.kt index 9052e620..737b3171 100644 --- a/common/src/main/java/com/doyoonkim/common/theme/Color.kt +++ b/common/src/main/java/com/doyoonkim/common/theme/Color.kt @@ -12,20 +12,18 @@ val Pink40 = Color(0xFF7D5260) // Color Scheme val Notification01 = Color(0xFFE65C19) -val Notification02 = Color(0xFFFFC55A) +val Notification02 = Color(0xFFF59E0B) val Notification03 = Color(0xFF7FD099) val Notification04 = Color(0xFF4294F7) +val Notification05 = Color(0xFF8B5CF6) -val WhiteBackground = Color(0xFFFFFFFF) -val DarkBackground = Color(0xFF262729) +val WhiteBackground = Color(0xFFF3F4F6) +val DarkBackground = Color(0xFF000000) -val ContainerLight = Color(0xFFF3F3F3) -val ContainerDark = Color(0xFF333437) -val ContainerBlack = Color(0xFF000000) -val ContainerWhite = Color(0xFFFFFFFF) +val SecondaryLight = Color(0xFFFFFFFF) +val SecondaryDark = Color(0xFF1B1C20) -val bottomNavBarWhite = Color(0xFFFFFFFF) -val bottomNavBarBlack = Color(0xFF424448) +val VariantPurple = Color(0xFF6b79fc) val TitleBlack = Color(0xFF000000) val TitleWhite = Color(0xFFFFFFFF) @@ -35,11 +33,14 @@ val SubtitleAny = Color(0xFF787879) val ButtonDark = Color(0xFF3C3C3C) val ButtonLight = Color(0xFFF3F3F3) -val GradientStartDark = Color(0xFF4F4F4F) +val OnBackgroundDark = Color(0xFF2F2F2F) +val OnBackgroundLight = Color(0xFFECECEC) + +val GradientStartDark = Color(0xFF1E1E1E) val GradientStartLight = Color(0xFFA1A1A1) -val GradientIntermediateDark = Color(0xFF5C5C5C) +val GradientIntermediateDark = Color(0xFF383838) val GradientIntermediateLight = Color(0xFFD2D2D2) -val GradientEndDark = Color(0xFF848484) +val GradientEndDark = Color(0xFF444444) val GradientEndLight = Color(0xFFE5E5E5) \ No newline at end of file diff --git a/common/src/main/java/com/doyoonkim/common/theme/Theme.kt b/common/src/main/java/com/doyoonkim/common/theme/Theme.kt index b4af8e49..6c69e5e1 100644 --- a/common/src/main/java/com/doyoonkim/common/theme/Theme.kt +++ b/common/src/main/java/com/doyoonkim/common/theme/Theme.kt @@ -55,21 +55,17 @@ val ColorScheme.displayBackground: Color @Composable get() = if(isSystemInDarkTheme()) DarkBackground else WhiteBackground -val ColorScheme.containerBackground: Color +val ColorScheme.secondaryBackground: Color @Composable - get() = if(isSystemInDarkTheme()) ContainerDark else ContainerWhite - -val ColorScheme.containerBackgroundSolid: Color - @Composable - get() = if(isSystemInDarkTheme()) ContainerBlack else ContainerLight + get() = if(isSystemInDarkTheme()) SecondaryDark else SecondaryLight val ColorScheme.containerGray: Color @Composable get() = if(isSystemInDarkTheme()) Color.Gray else Color.LightGray -val ColorScheme.bottomNavContainer: Color +val ColorScheme.onAnyBackground: Color @Composable - get() = if(isSystemInDarkTheme()) bottomNavBarBlack else bottomNavBarWhite + get() = if(isSystemInDarkTheme()) OnBackgroundDark else OnBackgroundLight val ColorScheme.title: Color @Composable @@ -79,17 +75,13 @@ val ColorScheme.subTitle: Color @Composable get() = SubtitleAny -val ColorScheme.buttonContainer: Color - @Composable - get() = if(isSystemInDarkTheme()) ButtonDark else ButtonLight - -val ColorScheme.buttonPurple: Color +val ColorScheme.variantPurple: Color @Composable - get() = Purple40 + get() = VariantPurple -val ColorScheme.textPurple: Color +val ColorScheme.buttonOnBackground: Color @Composable - get() = if(isSystemInDarkTheme()) Purple80 else Purple40 + get() = if(isSystemInDarkTheme()) ButtonDark else ButtonLight val ColorScheme.animationGradientStart: Color @Composable diff --git a/common/src/main/java/com/doyoonkim/common/ui/DateTimePicker.kt b/common/src/main/java/com/doyoonkim/common/ui/DateTimePicker.kt index f5c8e633..b7f78dbf 100644 --- a/common/src/main/java/com/doyoonkim/common/ui/DateTimePicker.kt +++ b/common/src/main/java/com/doyoonkim/common/ui/DateTimePicker.kt @@ -28,7 +28,8 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.doyoonkim.common.theme.containerGray +import com.doyoonkim.common.theme.onAnyBackground +import com.doyoonkim.common.theme.secondaryBackground import com.doyoonkim.common.theme.title import java.text.SimpleDateFormat import java.util.Calendar @@ -66,7 +67,7 @@ fun DatePickerDialog( .background(Color.Transparent) .clip(RoundedCornerShape(10.dp)) .clickable { pickerVisible = !pickerVisible }, - color = MaterialTheme.colorScheme.containerGray + color = MaterialTheme.colorScheme.onAnyBackground ) { Text( text = datePickerState.selectedDateMillis!!.toFormattedString(), diff --git a/common/src/main/java/com/doyoonkim/common/ui/LabeledToggleSwitch.kt b/common/src/main/java/com/doyoonkim/common/ui/LabeledToggleSwitch.kt index d851c435..6feee093 100644 --- a/common/src/main/java/com/doyoonkim/common/ui/LabeledToggleSwitch.kt +++ b/common/src/main/java/com/doyoonkim/common/ui/LabeledToggleSwitch.kt @@ -19,9 +19,9 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.doyoonkim.common.theme.buttonPurple import com.doyoonkim.common.theme.subTitle import com.doyoonkim.common.theme.title +import com.doyoonkim.common.theme.variantPurple @Composable fun LabeledToggleSwitch( @@ -67,7 +67,7 @@ fun LabeledToggleSwitch( Switch( checked = isChecked, colors = SwitchDefaults.colors().copy( - checkedTrackColor = MaterialTheme.colorScheme.buttonPurple, + checkedTrackColor = MaterialTheme.colorScheme.variantPurple, checkedThumbColor = Color.White ), onCheckedChange = { diff --git a/common/src/main/java/com/doyoonkim/common/ui/NotificationPreview.kt b/common/src/main/java/com/doyoonkim/common/ui/NotificationPreview.kt index a41084f6..089dd909 100644 --- a/common/src/main/java/com/doyoonkim/common/ui/NotificationPreview.kt +++ b/common/src/main/java/com/doyoonkim/common/ui/NotificationPreview.kt @@ -37,7 +37,7 @@ fun NotificationPreview( ) { Column( Modifier.padding(10.dp), - verticalArrangement = Arrangement.spacedBy(7.dp) + verticalArrangement = Arrangement.spacedBy(5.dp) ) { if (isLoading) { AnimatedGradient(Modifier.height(24.dp)) @@ -67,7 +67,7 @@ fun NotificationPreview( .padding(top = 7.dp, start = 5.dp, end = 5.dp), text = notificationTitle, textAlign = TextAlign.Start, - fontSize = 13.sp, + fontSize = 14.sp, fontWeight = FontWeight.SemiBold, color = MaterialTheme.colorScheme.title, maxLines = 1, @@ -78,7 +78,7 @@ fun NotificationPreview( .padding(top = 1.dp, start = 5.dp, bottom = 5.dp, end = 5.dp), text = notificationInfo, textAlign = TextAlign.Start, - fontSize = 9.sp, + fontSize = 12.sp, color = MaterialTheme.colorScheme.subTitle ) } diff --git a/common/src/main/java/com/doyoonkim/common/ui/NotificationPreviewCard.kt b/common/src/main/java/com/doyoonkim/common/ui/NotificationPreviewCard.kt index 55f0311d..c15b65da 100644 --- a/common/src/main/java/com/doyoonkim/common/ui/NotificationPreviewCard.kt +++ b/common/src/main/java/com/doyoonkim/common/ui/NotificationPreviewCard.kt @@ -13,7 +13,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.doyoonkim.common.theme.containerBackground +import com.doyoonkim.common.theme.secondaryBackground @Composable fun NotificationPreviewCard( @@ -30,7 +30,7 @@ fun NotificationPreviewCard( onClick() }, colors = CardColors( - containerColor = MaterialTheme.colorScheme.containerBackground, + containerColor = MaterialTheme.colorScheme.secondaryBackground, contentColor = Color.Unspecified, disabledContainerColor = Color.Unspecified, disabledContentColor = Color.Unspecified diff --git a/common/src/main/java/com/doyoonkim/common/ui/PermissionRationaleComposable.kt b/common/src/main/java/com/doyoonkim/common/ui/PermissionRationaleComposable.kt index 3321d7cb..7f44f605 100644 --- a/common/src/main/java/com/doyoonkim/common/ui/PermissionRationaleComposable.kt +++ b/common/src/main/java/com/doyoonkim/common/ui/PermissionRationaleComposable.kt @@ -26,7 +26,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.doyoonkim.common.R -import com.doyoonkim.common.theme.buttonPurple +import com.doyoonkim.common.theme.variantPurple @Composable fun PermissionRationaleComposable( @@ -73,7 +73,7 @@ fun PermissionRationaleComposable( Button( modifier = Modifier.fillMaxWidth(), colors = ButtonDefaults.buttonColors().copy( - containerColor = MaterialTheme.colorScheme.buttonPurple, + containerColor = MaterialTheme.colorScheme.variantPurple, contentColor = Color.White, ), onClick = onPermissionDecided diff --git a/common/src/main/java/com/doyoonkim/common/ui/TimePickerWheel.kt b/common/src/main/java/com/doyoonkim/common/ui/TimePickerWheel.kt index 8835fa66..ebe4d1b0 100644 --- a/common/src/main/java/com/doyoonkim/common/ui/TimePickerWheel.kt +++ b/common/src/main/java/com/doyoonkim/common/ui/TimePickerWheel.kt @@ -43,11 +43,12 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog import com.doyoonkim.common.R -import com.doyoonkim.common.theme.containerBackground +import com.doyoonkim.common.theme.secondaryBackground import com.doyoonkim.common.theme.containerGray +import com.doyoonkim.common.theme.onAnyBackground import com.doyoonkim.common.theme.subTitle -import com.doyoonkim.common.theme.textPurple import com.doyoonkim.common.theme.title +import com.doyoonkim.common.theme.variantPurple import kotlinx.coroutines.flow.filter import java.util.Calendar @@ -84,7 +85,7 @@ fun TimePickerDialog( .background(Color.Transparent) .clip(RoundedCornerShape(10.dp)) .clickable { pickerVisible = !pickerVisible }, - color = MaterialTheme.colorScheme.containerGray + color = MaterialTheme.colorScheme.onAnyBackground ) { Text( text = "${hours[hourSelected]}:${minutes[minuteSelected]}", @@ -110,7 +111,7 @@ fun TimePickerDialog( modifier = Modifier .clip(RoundedCornerShape(10.dp)) .background(Color.Transparent), - color = MaterialTheme.colorScheme.containerBackground + color = MaterialTheme.colorScheme.secondaryBackground ) { Column( modifier = Modifier.wrapContentSize() @@ -248,7 +249,7 @@ internal fun WheelPickerItem( fontSize = 25.sp, textAlign = TextAlign.Center, color = if (isHighlighted) { - MaterialTheme.colorScheme.textPurple + MaterialTheme.colorScheme.variantPurple } else { MaterialTheme.colorScheme.subTitle }, diff --git a/common/src/main/java/com/doyoonkim/common/ui/TopAppBars.kt b/common/src/main/java/com/doyoonkim/common/ui/TopAppBars.kt new file mode 100644 index 00000000..1b3e6c19 --- /dev/null +++ b/common/src/main/java/com/doyoonkim/common/ui/TopAppBars.kt @@ -0,0 +1,109 @@ +package com.doyoonkim.common.ui + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.sp +import com.doyoonkim.common.R +import com.doyoonkim.common.theme.displayBackground +import com.doyoonkim.common.theme.title + +/** + * @author kimdoyoon + * Created 6/23/25 at 11:38 PM + */ + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun TopAppBarWithBackButton( + modifier: Modifier = Modifier, + titleText: String, + onBackPressed: () -> Unit +) { + TopAppBar( + title = { + Text( + modifier = modifier.fillMaxWidth(), + text = titleText, + textAlign = TextAlign.Left, + fontSize = 20.sp, + fontWeight = FontWeight.ExtraBold, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + }, + navigationIcon = { + IconButton( + onClick = { onBackPressed() } + ) { + Icon( + imageVector = Icons.AutoMirrored.Default.ArrowBack, + contentDescription = null + ) + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.displayBackground, + titleContentColor = MaterialTheme.colorScheme.title, + navigationIconContentColor = MaterialTheme.colorScheme.title + ) + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun TopAppBarWithActions( + modifier: Modifier = Modifier, + titleText: String, + actions: @Composable (RowScope.() -> Unit) +) { + TopAppBar( + modifier = modifier, + title = { + Row( + modifier = Modifier.fillMaxWidth().wrapContentHeight(), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + modifier = Modifier.fillMaxWidth(), + text = titleText, + textAlign = TextAlign.Left, + fontSize = 20.sp, + fontWeight = FontWeight.W900, + maxLines = 1, + color = MaterialTheme.colorScheme.title + ) + } + }, + actions = { + actions() + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.displayBackground, + titleContentColor = MaterialTheme.colorScheme.title + ) + ) +} \ No newline at end of file diff --git a/feature/bookmark/src/main/java/com/doyoonkim/bookmark/bookmarkServiceGraph.kt b/feature/bookmark/src/main/java/com/doyoonkim/bookmark/bookmarkServiceGraph.kt index 584df150..2ac46642 100644 --- a/feature/bookmark/src/main/java/com/doyoonkim/bookmark/bookmarkServiceGraph.kt +++ b/feature/bookmark/src/main/java/com/doyoonkim/bookmark/bookmarkServiceGraph.kt @@ -1,7 +1,13 @@ package com.doyoonkim.bookmark +import androidx.compose.animation.AnimatedContentTransitionScope +import androidx.compose.animation.core.EaseIn +import androidx.compose.animation.core.EaseOut +import androidx.compose.animation.core.tween +import androidx.compose.foundation.background import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.ViewModelProvider @@ -17,6 +23,7 @@ import com.doyoonkim.bookmark.viewmodel.EditBookmarkViewModel import com.doyoonkim.common.navigation.BookmarkInfo import com.doyoonkim.common.navigation.NavRoutes import com.doyoonkim.common.navigation.NoticeDetail +import com.doyoonkim.common.theme.displayBackground fun NavGraphBuilder.bookmarkServiceGraph( navController: NavController, @@ -28,9 +35,10 @@ fun NavGraphBuilder.bookmarkServiceGraph( composable(NavRoutes.Bookmark.route) { BookmarkListScreen( - modifier = Modifier.padding(5.dp), + modifier = Modifier.padding(horizontal = 5.dp), viewModel = viewModel(factory = viewModelFactory), bottomPadding = contentPadding.calculateBottomPadding(), + onSettingsRequested = { navController.navigate(NavRoutes.Settings.route) }, onBookmarkSelected = { navController.navigate("bookmark/${it.noticeId}/${it.noticeTitle}/${it.noticeInfo}") }, @@ -46,7 +54,19 @@ fun NavGraphBuilder.bookmarkServiceGraph( navDeepLink { uriPattern = "knutice://service/bookmark/{id}/{title}/{info}" } - ) + ), + enterTransition = { + slideIntoContainer( + animationSpec = tween(300, easing = EaseIn), + towards = AnimatedContentTransitionScope.SlideDirection.Up + ) + }, + exitTransition = { + slideOutOfContainer( + animationSpec = tween(300, easing = EaseOut), + towards = AnimatedContentTransitionScope.SlideDirection.Down + ) + }, ) { backStackEntry -> val bookmarkInfo = backStackEntry.arguments?.let { BookmarkInfo( @@ -57,7 +77,7 @@ fun NavGraphBuilder.bookmarkServiceGraph( } ?: BookmarkInfo(0, "", "") EditBookmarkScreen( - modifier = Modifier.padding(5.dp), + modifier = Modifier.padding(horizontal = 10.dp), viewModel = viewModel(factory = viewModelFactory), bookmarkInfo = bookmarkInfo, onNoticeSelected = { onNoticeDetailRequested(it) }, diff --git a/feature/bookmark/src/main/java/com/doyoonkim/bookmark/edit/EditBookmarkScreen.kt b/feature/bookmark/src/main/java/com/doyoonkim/bookmark/edit/EditBookmarkScreen.kt index 8bb8fbee..05079c7a 100644 --- a/feature/bookmark/src/main/java/com/doyoonkim/bookmark/edit/EditBookmarkScreen.kt +++ b/feature/bookmark/src/main/java/com/doyoonkim/bookmark/edit/EditBookmarkScreen.kt @@ -4,6 +4,7 @@ import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically +import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -32,6 +33,7 @@ import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Switch import androidx.compose.material3.SwitchDefaults @@ -45,6 +47,8 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -55,11 +59,11 @@ import com.doyoonkim.bookmark.viewmodel.EditBookmarkViewModel import com.doyoonkim.common.navigation.BookmarkInfo import com.doyoonkim.common.navigation.NoticeDetail import com.doyoonkim.common.R -import com.doyoonkim.common.theme.buttonPurple -import com.doyoonkim.common.theme.containerBackground +import com.doyoonkim.common.theme.displayBackground +import com.doyoonkim.common.theme.secondaryBackground import com.doyoonkim.common.theme.subTitle -import com.doyoonkim.common.theme.textPurple import com.doyoonkim.common.theme.title +import com.doyoonkim.common.theme.variantPurple import com.doyoonkim.common.ui.DatePickerDialog import com.doyoonkim.common.ui.NotificationPreviewCard import com.doyoonkim.common.ui.RoundedCornerColumn @@ -67,6 +71,7 @@ import com.doyoonkim.common.ui.RoundedCornerColumnItem import com.doyoonkim.common.ui.RoundedCornerColumnTextItemWithExtraOnRight import com.doyoonkim.common.ui.TextSize import com.doyoonkim.common.ui.TimePickerDialog +import com.doyoonkim.common.ui.TopAppBarWithBackButton @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -80,6 +85,7 @@ fun EditBookmarkScreen( ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() val adjustImePadding = Modifier.consumeWindowInsets(WindowInsets.ime).imePadding() + val localFocusManager = LocalFocusManager.current BackHandler { onBackPressed() @@ -94,226 +100,241 @@ fun EditBookmarkScreen( } } - Column( - modifier = modifier.fillMaxSize() - .windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Bottom)) - ) { - NotificationPreviewCard( - modifier = Modifier.padding(5.dp), - isLoading = false, - notificationTitle = bookmarkInfo.noticeTitle, - notificationInfo = bookmarkInfo.noticeInfo + Scaffold( + topBar = { + TopAppBarWithBackButton( + titleText = stringResource(R.string.title_edit_bookmark), + onBackPressed = onBackPressed + ) + }, + containerColor = MaterialTheme.colorScheme.displayBackground + ) { innerPadding -> + Column( + modifier = modifier.fillMaxSize() + .padding(innerPadding) + .pointerInput(Unit) { + detectTapGestures( + onTap = { localFocusManager.clearFocus() } + ) + } ) { - // Request Full Content - uiState.targetNotice?.let { onNoticeSelected(NoticeDetail(it.nttId, it.url, false)) } - } - - Spacer(Modifier.height(30.dp)) - - RoundedCornerColumn( - backgroundColor = MaterialTheme.colorScheme.containerBackground - ) { - RoundedCornerColumnTextItemWithExtraOnRight( - verticalPadding = 12.dp, - titleText = stringResource(R.string.subtitle_get_reminder), - subTitleText = null, - fontSize = TextSize.Small, - primaryColor = MaterialTheme.colorScheme.title, - secondaryColor = MaterialTheme.colorScheme.subTitle, - hasBottomDivider = uiState.isReminderRequested + NotificationPreviewCard( + modifier = Modifier.padding(5.dp), + isLoading = false, + notificationTitle = bookmarkInfo.noticeTitle, + notificationInfo = bookmarkInfo.noticeInfo ) { - Switch( - checked = uiState.isReminderRequested && uiState.alarmPermissionStatus, - enabled = true, - modifier = Modifier.padding(10.dp).weight(1f), - colors = SwitchDefaults.colors().copy( - checkedTrackColor = MaterialTheme.colorScheme.buttonPurple, - checkedThumbColor = Color.White - ), - onCheckedChange = { viewModel.updateReminderOptions(requested = !uiState.isReminderRequested) } - ) + // Request Full Content + uiState.targetNotice?.let { onNoticeSelected(NoticeDetail(it.nttId, it.url, false)) } } - AnimatedVisibility( - modifier = Modifier.fillMaxWidth().wrapContentHeight(), - visible = uiState.isReminderRequested, - enter = slideInVertically(), - exit = slideOutVertically() + Spacer(Modifier.height(30.dp)) + + RoundedCornerColumn( + backgroundColor = MaterialTheme.colorScheme.secondaryBackground ) { - RoundedCornerColumnItem( + RoundedCornerColumnTextItemWithExtraOnRight( verticalPadding = 12.dp, - hasBottomDivider = false, + titleText = stringResource(R.string.subtitle_get_reminder), + subTitleText = null, + fontSize = TextSize.Small, + primaryColor = MaterialTheme.colorScheme.title, + secondaryColor = MaterialTheme.colorScheme.subTitle, + hasBottomDivider = uiState.isReminderRequested + ) { + Switch( + checked = uiState.isReminderRequested && uiState.alarmPermissionStatus, + enabled = true, + modifier = Modifier.padding(10.dp).weight(1f), + colors = SwitchDefaults.colors().copy( + checkedTrackColor = MaterialTheme.colorScheme.variantPurple, + checkedThumbColor = Color.White + ), + onCheckedChange = { viewModel.updateReminderOptions(requested = !uiState.isReminderRequested) } + ) + } + + AnimatedVisibility( + modifier = Modifier.fillMaxWidth().wrapContentHeight(), + visible = uiState.isReminderRequested, + enter = slideInVertically(), + exit = slideOutVertically() ) { - Row( - modifier = Modifier - .fillMaxWidth() - .wrapContentHeight(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(3.dp) + RoundedCornerColumnItem( + verticalPadding = 12.dp, + hasBottomDivider = false, ) { - Text( - text = stringResource(R.string.text_set_reminder_date_time), - textAlign = TextAlign.Start, - fontSize = 14.sp, - fontWeight = FontWeight.SemiBold, - color = MaterialTheme.colorScheme.title, - modifier = Modifier.padding(10.dp).weight(2f) - ) + Row( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(3.dp) + ) { + Text( + text = stringResource(R.string.text_set_reminder_date_time), + textAlign = TextAlign.Start, + fontSize = 14.sp, + fontWeight = FontWeight.SemiBold, + color = MaterialTheme.colorScheme.title, + modifier = Modifier.padding(10.dp).weight(2f) + ) - DatePickerDialog( - initialTime = uiState.timeForRemind - ) { year, month, day -> - viewModel.updateDateInfo(year, month, day) - } - TimePickerDialog( - initialTime = uiState.timeForRemind - ) { hour, min -> - viewModel.updateTimeInfo(hour, min) + DatePickerDialog( + initialTime = uiState.timeForRemind + ) { year, month, day -> + viewModel.updateDateInfo(year, month, day) + } + TimePickerDialog( + initialTime = uiState.timeForRemind + ) { hour, min -> + viewModel.updateTimeInfo(hour, min) + } } } } } - } - - Spacer(Modifier.height(15.dp)) - Text( - text = stringResource(R.string.subtitle_notes), - fontSize = 16.sp, - fontWeight = FontWeight.Normal, - color = MaterialTheme.colorScheme.title, - modifier = Modifier.padding(10.dp) - ) - - Box( - modifier = Modifier.fillMaxWidth() - .fillMaxHeight() - .weight(1f) - .padding(top = 5.dp, bottom = 20.dp) - .then(adjustImePadding) - ) { - TextField( - modifier = Modifier.fillMaxSize().padding(bottom = 5.dp), - value = uiState.bookmarkNote, - placeholder = { Text(text = stringResource(R.string.placeholder_notes)) }, - enabled = true, - onValueChange = { - viewModel.updateBookmarkNotes(it) - }, - colors = TextFieldDefaults.colors( - focusedTextColor = MaterialTheme.colorScheme.title, - unfocusedTextColor = MaterialTheme.colorScheme.subTitle, - focusedContainerColor = MaterialTheme.colorScheme.containerBackground, - unfocusedContainerColor = MaterialTheme.colorScheme.containerBackground, - focusedIndicatorColor = Color.Transparent, - unfocusedIndicatorColor = Color.Transparent, - disabledIndicatorColor = Color.Transparent - ), - shape = RoundedCornerShape(15.dp) - ) + Spacer(Modifier.height(15.dp)) Text( - text = "${uiState.bookmarkNote.length}/500", - fontSize = 12.sp, - fontWeight = FontWeight.Medium, - color = MaterialTheme.colorScheme.subTitle, - modifier = Modifier.wrapContentSize() - .padding(15.dp) - .align(Alignment.BottomEnd) + text = stringResource(R.string.subtitle_notes), + fontSize = 16.sp, + fontWeight = FontWeight.Normal, + color = MaterialTheme.colorScheme.title, + modifier = Modifier.padding(10.dp) ) - } - Row( - modifier = Modifier.fillMaxWidth().wrapContentHeight(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(5.dp) - ) { - Button( - modifier = Modifier.wrapContentHeight() - .weight(1f), - enabled = true, - colors = ButtonDefaults.buttonColors().copy( - containerColor = MaterialTheme.colorScheme.buttonPurple, - contentColor = Color.White, - ), - shape = RoundedCornerShape(10.dp), - onClick = { - viewModel.submitBookmark() - } + Box( + modifier = Modifier.fillMaxWidth() + .fillMaxHeight() + .weight(1f) + .padding(top = 5.dp, bottom = 20.dp) + .then(adjustImePadding) ) { + TextField( + modifier = Modifier.fillMaxSize().padding(bottom = 5.dp), + value = uiState.bookmarkNote, + placeholder = { Text(text = stringResource(R.string.placeholder_notes)) }, + enabled = true, + onValueChange = { + viewModel.updateBookmarkNotes(it) + }, + colors = TextFieldDefaults.colors( + focusedTextColor = MaterialTheme.colorScheme.title, + unfocusedTextColor = MaterialTheme.colorScheme.subTitle, + focusedContainerColor = MaterialTheme.colorScheme.secondaryBackground, + unfocusedContainerColor = MaterialTheme.colorScheme.secondaryBackground, + focusedIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent, + disabledIndicatorColor = Color.Transparent + ), + shape = RoundedCornerShape(15.dp) + ) + Text( - text = stringResource(R.string.btn_save), - fontSize = 16.sp, - fontWeight = FontWeight.Bold, - modifier = Modifier.padding(10.dp) + text = "${uiState.bookmarkNote.length}/500", + fontSize = 12.sp, + fontWeight = FontWeight.Medium, + color = MaterialTheme.colorScheme.subTitle, + modifier = Modifier.wrapContentSize() + .padding(15.dp) + .align(Alignment.BottomEnd) ) } - if (!uiState.requireCreation) { + Row( + modifier = Modifier.fillMaxWidth().wrapContentHeight(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(5.dp) + ) { Button( - modifier = Modifier.wrapContentHeight().weight(1f), + modifier = Modifier.wrapContentHeight() + .weight(1f), enabled = true, - shape = RoundedCornerShape(10.dp), colors = ButtonDefaults.buttonColors().copy( - containerColor = MaterialTheme.colorScheme.subTitle, - contentColor = Color.White + containerColor = MaterialTheme.colorScheme.variantPurple, + contentColor = Color.White, ), + shape = RoundedCornerShape(10.dp), onClick = { - viewModel.removeBookmark() + viewModel.submitBookmark() } ) { Text( - text = stringResource(R.string.btn_delete), + text = stringResource(R.string.btn_save), fontSize = 16.sp, fontWeight = FontWeight.Bold, modifier = Modifier.padding(10.dp) ) } + + if (!uiState.requireCreation) { + Button( + modifier = Modifier.wrapContentHeight().weight(1f), + enabled = true, + shape = RoundedCornerShape(10.dp), + colors = ButtonDefaults.buttonColors().copy( + containerColor = MaterialTheme.colorScheme.subTitle, + contentColor = Color.White + ), + onClick = { + viewModel.removeBookmark() + } + ) { + Text( + text = stringResource(R.string.btn_delete), + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(10.dp) + ) + } + } } } - } - if (uiState.isCompleted) { - BasicAlertDialog( - onDismissRequest = { - // Dismiss the dialog when the user clicks outside the dialog or on the back - // button. If you want to disable that functionality, simply use an empty - // onDismissRequest. + if (uiState.isCompleted) { + BasicAlertDialog( + onDismissRequest = { + // Dismiss the dialog when the user clicks outside the dialog or on the back + // button. If you want to disable that functionality, simply use an empty + // onDismissRequest. - } - ) { - Surface( - modifier = Modifier.wrapContentWidth().wrapContentHeight(), - shape = MaterialTheme.shapes.large, - tonalElevation = AlertDialogDefaults.TonalElevation, - color = MaterialTheme.colorScheme.containerBackground + } ) { - Column(modifier = Modifier.padding(30.dp)) { - Text( - text = if (uiState.isSuccessful) { - stringResource(R.string.text_save_successful) - } else { - stringResource(R.string.text_save_unsuccessful) - }, - fontSize = 16.sp, - fontWeight = FontWeight.SemiBold, - textAlign = TextAlign.Center, - color = MaterialTheme.colorScheme.title - ) - Spacer(modifier = Modifier.height(24.dp)) - TextButton( - onClick = { - if (uiState.isSuccessful) onCompleted() - viewModel.updateCompletionStatus(false) // Set false for completion status for marking a new transaction is ready to start. - }, - modifier = Modifier.align(Alignment.End) - ) { + Surface( + modifier = Modifier.wrapContentWidth().wrapContentHeight(), + shape = MaterialTheme.shapes.large, + tonalElevation = AlertDialogDefaults.TonalElevation, + color = MaterialTheme.colorScheme.secondaryBackground + ) { + Column(modifier = Modifier.padding(30.dp)) { Text( - text = stringResource(R.string.btn_confirm), + text = if (uiState.isSuccessful) { + stringResource(R.string.text_save_successful) + } else { + stringResource(R.string.text_save_unsuccessful) + }, + fontSize = 16.sp, + fontWeight = FontWeight.SemiBold, textAlign = TextAlign.Center, - fontWeight = FontWeight.Normal, - color = MaterialTheme.colorScheme.textPurple + color = MaterialTheme.colorScheme.title ) + Spacer(modifier = Modifier.height(24.dp)) + TextButton( + onClick = { + if (uiState.isSuccessful) onCompleted() + viewModel.updateCompletionStatus(false) // Set false for completion status for marking a new transaction is ready to start. + }, + modifier = Modifier.align(Alignment.End) + ) { + Text( + text = stringResource(R.string.btn_confirm), + textAlign = TextAlign.Center, + fontWeight = FontWeight.Normal, + color = MaterialTheme.colorScheme.variantPurple + ) + } } } } diff --git a/feature/bookmark/src/main/java/com/doyoonkim/bookmark/list/BookmarkListScreen.kt b/feature/bookmark/src/main/java/com/doyoonkim/bookmark/list/BookmarkListScreen.kt index 6d277925..f26027a0 100644 --- a/feature/bookmark/src/main/java/com/doyoonkim/bookmark/list/BookmarkListScreen.kt +++ b/feature/bookmark/src/main/java/com/doyoonkim/bookmark/list/BookmarkListScreen.kt @@ -2,44 +2,63 @@ package com.doyoonkim.bookmark.list import android.util.Log import androidx.activity.compose.BackHandler +import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.calculateEndPadding +import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.doyoonkim.bookmark.viewmodel.BookmarkListViewModel import com.doyoonkim.common.navigation.BookmarkInfo -import com.doyoonkim.common.theme.containerBackgroundSolid import com.doyoonkim.common.R +import com.doyoonkim.common.theme.displayBackground import com.doyoonkim.common.theme.subTitle +import com.doyoonkim.common.theme.title import com.doyoonkim.common.ui.NotificationPreviewCardMarked +import com.doyoonkim.common.ui.TopAppBarWithActions +@OptIn(ExperimentalMaterial3Api::class) @Composable fun BookmarkListScreen( modifier: Modifier = Modifier, viewModel: BookmarkListViewModel, bottomPadding: Dp = 0.dp, + onSettingsRequested: () -> Unit, onBookmarkSelected: (BookmarkInfo) -> Unit, onBackPressed: () -> Unit ) { @@ -51,29 +70,54 @@ fun BookmarkListScreen( viewModel.getAllBookmarks() } - Box( - modifier = modifier.fillMaxSize() - .background(MaterialTheme.colorScheme.containerBackgroundSolid) - ) { + Scaffold( + modifier = modifier.fillMaxSize(), + topBar = { + TopAppBarWithActions( + titleText = stringResource(R.string.bottom_bar_bookmark) + ) { + IconButton( + onClick = onSettingsRequested + ) { + Image( + painter = painterResource(R.drawable.baseline_settings_24), + contentDescription = "Settings", + modifier = Modifier.wrapContentSize(), + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.title) + ) + } + } + }, + containerColor = MaterialTheme.colorScheme.displayBackground + ) { innerPadding -> + if (uiState.bookmarks.isEmpty()) { Column( - modifier = Modifier.fillMaxSize(), - verticalArrangement = Arrangement.Center, + modifier = modifier.fillMaxSize().padding(innerPadding), + verticalArrangement = Arrangement.spacedBy(3.dp), horizontalAlignment = Alignment.CenterHorizontally ) { - Text( - text = stringResource(R.string.text_no_bookmark), - fontSize = 16.sp, - fontWeight = FontWeight.SemiBold, - color = MaterialTheme.colorScheme.subTitle - ) + Box( + modifier = Modifier.wrapContentSize() + .weight(1f) + ) { + Text( + text = stringResource(R.string.text_no_bookmark), + fontSize = 16.sp, + fontWeight = FontWeight.SemiBold, + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.subTitle, + modifier = Modifier.wrapContentSize() + .align(Alignment.Center) + ) + } Spacer(Modifier.height(bottomPadding)) } } else { LazyColumn( - modifier = Modifier.wrapContentHeight() + modifier = modifier.wrapContentHeight() .fillMaxWidth() - .padding(top = 12.dp, bottom = bottomPadding) + .padding(top = innerPadding.calculateTopPadding() + 12.dp) .background(Color.Transparent), verticalArrangement = Arrangement.spacedBy(12.dp), horizontalAlignment = Alignment.CenterHorizontally, @@ -87,17 +131,22 @@ fun BookmarkListScreen( NotificationPreviewCardMarked( noticeTitle = it.second.title, noticeSubtitle = "[${it.second.departName}] ${it.second.timestamp}", - onItemClicked = { onBookmarkSelected( - it.second.run { - BookmarkInfo( - noticeId = this.nttId, - noticeTitle = this.title, - noticeInfo = "[${this.departName}] ${this.timestamp}" - ) - } - ) } + onItemClicked = { + onBookmarkSelected( + it.second.run { + BookmarkInfo( + noticeId = this.nttId, + noticeTitle = this.title, + noticeInfo = "[${this.departName}] ${this.timestamp}" + ) + } + ) + } ) } + item { + Spacer(Modifier.height(bottomPadding)) + } } } } diff --git a/feature/main/src/main/java/com/doyoonkim/main/MainServiceNavGraph.kt b/feature/main/src/main/java/com/doyoonkim/main/MainServiceNavGraph.kt index 63dd317a..5fe9e872 100644 --- a/feature/main/src/main/java/com/doyoonkim/main/MainServiceNavGraph.kt +++ b/feature/main/src/main/java/com/doyoonkim/main/MainServiceNavGraph.kt @@ -1,6 +1,12 @@ package com.doyoonkim.main import android.net.Uri +import androidx.compose.animation.AnimatedContentScope +import androidx.compose.animation.AnimatedContentTransitionScope +import androidx.compose.animation.EnterTransition +import androidx.compose.animation.core.EaseIn +import androidx.compose.animation.core.EaseOut +import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding @@ -9,6 +15,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavBackStackEntry import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable @@ -41,12 +48,15 @@ fun NavGraphBuilder.mainServiceNavGraph( onBookmarkServiceRequested: (BookmarkInfo) -> Unit, onExit: () -> Unit = { } ) { + // ViewModels will be injected via ViewModelFactory composable(NavRoutes.Home.route) { HomeScreen( - modifier = Modifier.padding(5.dp), + modifier = Modifier.padding(horizontal = 5.dp), viewModel = viewModel(factory = viewModelFactory), bottomPadding = contentPadding.calculateBottomPadding(), + onSearchRequested = { navController.navigate(NavRoutes.NoticeSearch.route) }, + onSettingsRequested = { navController.navigate(NavRoutes.Settings.route) }, onGoBackAction = { navController.popBackStack().also { if (!it) onExit() } }, @@ -66,9 +76,23 @@ fun NavGraphBuilder.mainServiceNavGraph( ) } - composable(NavRoutes.NoticeSearch.route) { + composable( + route = NavRoutes.NoticeSearch.route, + enterTransition = { + slideIntoContainer( + animationSpec = tween(300, easing = EaseIn), + towards = AnimatedContentTransitionScope.SlideDirection.Up + ) + }, + exitTransition = { + slideOutOfContainer( + animationSpec = tween(300, easing = EaseOut), + towards = AnimatedContentTransitionScope.SlideDirection.Down + ) + } + ) { NoticeSearchScreen( - modifier = Modifier.padding(5.dp), + modifier = Modifier, viewModel = viewModel(factory = viewModelFactory), onBackPressed = { navController.popBackStack() }, onNoticeSelected = { id, url -> @@ -77,9 +101,23 @@ fun NavGraphBuilder.mainServiceNavGraph( ) } - composable(NavRoutes.GeneralNotices.route) { + composable( + route = NavRoutes.GeneralNotices.route, + enterTransition = { + slideIntoContainer( + animationSpec = tween(300, easing = EaseIn), + towards = AnimatedContentTransitionScope.SlideDirection.Start + ) + }, + exitTransition = { + slideOutOfContainer( + animationSpec = tween(300, easing = EaseOut), + towards = AnimatedContentTransitionScope.SlideDirection.End + ) + } + ) { NoticesInCategoryScreen( - modifier = Modifier.padding(5.dp), + modifier = Modifier, category = NoticeCategory.GENERAL_NEWS, viewModel = viewModel(factory = viewModelFactory), onBackButtonPressed = { navController.popBackStack() }, @@ -89,9 +127,23 @@ fun NavGraphBuilder.mainServiceNavGraph( ) } - composable(NavRoutes.AcademicNotices.route) { + composable( + route = NavRoutes.AcademicNotices.route, + enterTransition = { + slideIntoContainer( + animationSpec = tween(300, easing = EaseIn), + towards = AnimatedContentTransitionScope.SlideDirection.Start + ) + }, + exitTransition = { + slideOutOfContainer( + animationSpec = tween(300, easing = EaseOut), + towards = AnimatedContentTransitionScope.SlideDirection.End + ) + } + ) { NoticesInCategoryScreen( - modifier = Modifier.padding(5.dp), + modifier = Modifier, category = NoticeCategory.ACADEMIC_NEWS, viewModel = viewModel(factory = viewModelFactory), onBackButtonPressed = { navController.popBackStack() }, @@ -101,9 +153,23 @@ fun NavGraphBuilder.mainServiceNavGraph( ) } - composable(NavRoutes.ScholarshipNotices.route) { + composable( + route = NavRoutes.ScholarshipNotices.route, + enterTransition = { + slideIntoContainer( + animationSpec = tween(300, easing = EaseIn), + towards = AnimatedContentTransitionScope.SlideDirection.Start + ) + }, + exitTransition = { + slideOutOfContainer( + animationSpec = tween(300, easing = EaseOut), + towards = AnimatedContentTransitionScope.SlideDirection.End + ) + } + ) { NoticesInCategoryScreen( - modifier = Modifier.padding(5.dp), + modifier = Modifier, category = NoticeCategory.SCHOLARSHIP_NEWS, viewModel = viewModel(factory = viewModelFactory), onBackButtonPressed = { navController.popBackStack() }, @@ -113,9 +179,23 @@ fun NavGraphBuilder.mainServiceNavGraph( ) } - composable(NavRoutes.EventNotices.route) { + composable( + route = NavRoutes.EventNotices.route, + enterTransition = { + slideIntoContainer( + animationSpec = tween(300, easing = EaseIn), + towards = AnimatedContentTransitionScope.SlideDirection.Start + ) + }, + exitTransition = { + slideOutOfContainer( + animationSpec = tween(300, easing = EaseOut), + towards = AnimatedContentTransitionScope.SlideDirection.End + ) + } + ) { NoticesInCategoryScreen( - modifier = Modifier.padding(5.dp), + modifier = Modifier, category = NoticeCategory.EVENT_NEWS, viewModel = viewModel(factory = viewModelFactory), onBackButtonPressed = { navController.popBackStack() }, @@ -126,9 +206,23 @@ fun NavGraphBuilder.mainServiceNavGraph( } // preferences - composable(NavRoutes.Settings.route) { + composable( + route = NavRoutes.Settings.route, + enterTransition = { + slideIntoContainer( + animationSpec = tween(300, easing = EaseIn), + towards = AnimatedContentTransitionScope.SlideDirection.Start + ) + }, + exitTransition = { + slideOutOfContainer( + animationSpec = tween(300, easing = EaseOut), + towards = AnimatedContentTransitionScope.SlideDirection.End + ) + } + ) { UserPreferenceScreen( - modifier = Modifier.padding(5.dp), + modifier = Modifier.padding(horizontal = 10.dp), onNotificationPreferenceClicked = { navController.navigate(NavRoutes.NotificationPreferences.route) }, onCustomerServiceClicked = { navController.navigate(NavRoutes.CustomerService.route) }, onOssClicked = { navController.navigate(NavRoutes.OpenSource.route) }, @@ -136,25 +230,67 @@ fun NavGraphBuilder.mainServiceNavGraph( ) } - composable(NavRoutes.NotificationPreferences.route) { + composable( + route = NavRoutes.NotificationPreferences.route, + enterTransition = { + slideIntoContainer( + animationSpec = tween(300, easing = EaseIn), + towards = AnimatedContentTransitionScope.SlideDirection.Start + ) + }, + exitTransition = { + slideOutOfContainer( + animationSpec = tween(300, easing = EaseOut), + towards = AnimatedContentTransitionScope.SlideDirection.End + ) + } + ) { NotificationPreferencesScreen( - modifier = Modifier.padding(5.dp), + modifier = Modifier.padding(horizontal = 10.dp), viewModel = viewModel(factory = viewModelFactory), onBackPressed = { navController.popBackStack() } ) } - composable(NavRoutes.CustomerService.route) { + composable( + route = NavRoutes.CustomerService.route, + enterTransition = { + slideIntoContainer( + animationSpec = tween(300, easing = EaseIn), + towards = AnimatedContentTransitionScope.SlideDirection.Start + ) + }, + exitTransition = { + slideOutOfContainer( + animationSpec = tween(300, easing = EaseOut), + towards = AnimatedContentTransitionScope.SlideDirection.End + ) + } + ) { CustomerServiceScreen( - modifier = Modifier.padding(5.dp), + modifier = Modifier.padding(horizontal = 10.dp), viewModel = viewModel(factory = viewModelFactory), onBackPressed = { navController.popBackStack() } ) } - composable(NavRoutes.OpenSource.route) { + composable( + route = NavRoutes.OpenSource.route, + enterTransition = { + slideIntoContainer( + animationSpec = tween(300, easing = EaseIn), + towards = AnimatedContentTransitionScope.SlideDirection.Start + ) + }, + exitTransition = { + slideOutOfContainer( + animationSpec = tween(300, easing = EaseOut), + towards = AnimatedContentTransitionScope.SlideDirection.End + ) + } + ) { OssNoticeScreen( - modifier = Modifier.padding(5.dp), + modifier = Modifier.padding(horizontal = 10.dp), onBackPressed = { navController.popBackStack() } ) } @@ -166,7 +302,19 @@ fun NavGraphBuilder.mainServiceNavGraph( navDeepLink { uriPattern = "knutice://service/noticeDetail/{nttId}/{contentUrl}/{isFabVisible}" } - ) + ), + enterTransition = { + slideIntoContainer( + animationSpec = tween(300, easing = EaseIn), + towards = AnimatedContentTransitionScope.SlideDirection.Start + ) + }, + exitTransition = { + slideOutOfContainer( + animationSpec = tween(300, easing = EaseOut), + towards = AnimatedContentTransitionScope.SlideDirection.End + ) + } ) { backStackEntry -> val noticeInfo = backStackEntry.arguments?.let { Triple( diff --git a/feature/main/src/main/java/com/doyoonkim/main/home/HomeScreen.kt b/feature/main/src/main/java/com/doyoonkim/main/home/HomeScreen.kt index a20af81e..083bba52 100644 --- a/feature/main/src/main/java/com/doyoonkim/main/home/HomeScreen.kt +++ b/feature/main/src/main/java/com/doyoonkim/main/home/HomeScreen.kt @@ -1,20 +1,28 @@ package com.doyoonkim.main.home import androidx.activity.compose.BackHandler +import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TextButton +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState @@ -22,8 +30,11 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -34,15 +45,22 @@ import com.doyoonkim.common.theme.notificationType4 import com.doyoonkim.common.theme.subTitle import com.doyoonkim.common.R import com.doyoonkim.common.navigation.Destination +import com.doyoonkim.common.navigation.NavRoutes +import com.doyoonkim.common.theme.displayBackground +import com.doyoonkim.common.theme.title import com.doyoonkim.common.ui.NotificationPreviewCard +import com.doyoonkim.common.ui.TopAppBarWithActions import com.doyoonkim.main.viewmodel.HomeViewModel import com.doyoonkim.model.NoticeVO +@OptIn(ExperimentalMaterial3Api::class) @Composable fun HomeScreen( modifier: Modifier = Modifier, viewModel: HomeViewModel, bottomPadding: Dp = 0.dp, + onSearchRequested: () -> Unit, + onSettingsRequested: () -> Unit, onGoBackAction: () -> Unit, onMoreNoticeRequested: (Destination) -> Unit, onFullContentRequested: (Int, String) -> Unit @@ -58,54 +76,87 @@ fun HomeScreen( viewModel.getTopThreeNotices() } - Column( - modifier = modifier.verticalScroll( - rememberScrollState(0) - ), - verticalArrangement = Arrangement.Top, - horizontalAlignment = Alignment.CenterHorizontally - ) { - NotificationPreviewList ( - listTitle = stringResource(R.string.general_news), - titleColor = MaterialTheme.colorScheme.notificationType1, - isContentLoading = uiState.isLoading, - contents = uiState.notificationGeneral, - onMoreClicked = { onMoreNoticeRequested(Destination.MORE_GENERAL) } + Scaffold( + modifier = Modifier.fillMaxSize(), + topBar = { + TopAppBarWithActions( + titleText = stringResource(R.string.app_name) + ) { + IconButton( + onClick = onSearchRequested + ) { + Image( + painter = painterResource(R.drawable.baseline_search_24), + contentDescription = "Search", + modifier = Modifier.wrapContentSize(), + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.title) + ) + } + IconButton( + onClick = onSettingsRequested + ) { + Image( + painter = painterResource(R.drawable.baseline_settings_24), + contentDescription = "Settings", + modifier = Modifier.wrapContentSize(), + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.title) + ) + } + } + }, + containerColor = MaterialTheme.colorScheme.displayBackground + ) { innerPadding -> + Column( + modifier = modifier + .padding(innerPadding) + .verticalScroll(rememberScrollState(0)), + verticalArrangement = Arrangement.Top, + horizontalAlignment = Alignment.CenterHorizontally ) { - onFullContentRequested(it.nttId, it.url) - } - NotificationPreviewList( - listTitle = stringResource(R.string.academic_news), - titleColor = MaterialTheme.colorScheme.notificationType2, - isContentLoading = uiState.isLoading, - contents = uiState.notificationAcademic, - onMoreClicked = { onMoreNoticeRequested(Destination.MORE_ACADEMIC) } - ) { - onFullContentRequested(it.nttId, it.url) - } - NotificationPreviewList( - listTitle = stringResource(R.string.scholarship_news), - titleColor = MaterialTheme.colorScheme.notificationType3, - isContentLoading = uiState.isLoading, - contents = uiState.notificationScholarship, - onMoreClicked = { onMoreNoticeRequested(Destination.MORE_SCHOLARSHIP) } - ) { - onFullContentRequested(it.nttId, it.url) - } + NotificationPreviewList ( + listTitle = stringResource(R.string.general_news), + titleColor = MaterialTheme.colorScheme.notificationType1, + isContentLoading = uiState.isLoading, + contents = uiState.notificationGeneral, + onMoreClicked = { onMoreNoticeRequested(Destination.MORE_GENERAL) } + ) { + onFullContentRequested(it.nttId, it.url) + } - NotificationPreviewList( - listTitle = stringResource(R.string.event_news), - titleColor = MaterialTheme.colorScheme.notificationType4, - isContentLoading = uiState.isLoading, - contents = uiState.notificationEvent, - onMoreClicked = { onMoreNoticeRequested(Destination.MORE_EVENT) } - ) { - onFullContentRequested(it.nttId, it.url) - } + NotificationPreviewList( + listTitle = stringResource(R.string.academic_news), + titleColor = MaterialTheme.colorScheme.notificationType2, + isContentLoading = uiState.isLoading, + contents = uiState.notificationAcademic, + onMoreClicked = { onMoreNoticeRequested(Destination.MORE_ACADEMIC) } + ) { + onFullContentRequested(it.nttId, it.url) + } - Spacer(Modifier.height(bottomPadding)) + NotificationPreviewList( + listTitle = stringResource(R.string.scholarship_news), + titleColor = MaterialTheme.colorScheme.notificationType3, + isContentLoading = uiState.isLoading, + contents = uiState.notificationScholarship, + onMoreClicked = { onMoreNoticeRequested(Destination.MORE_SCHOLARSHIP) } + ) { + onFullContentRequested(it.nttId, it.url) + } + + NotificationPreviewList( + listTitle = stringResource(R.string.event_news), + titleColor = MaterialTheme.colorScheme.notificationType4, + isContentLoading = uiState.isLoading, + contents = uiState.notificationEvent, + onMoreClicked = { onMoreNoticeRequested(Destination.MORE_EVENT) } + ) { + onFullContentRequested(it.nttId, it.url) + } + + Spacer(Modifier.height(bottomPadding)) + } } } @@ -135,7 +186,7 @@ fun NotificationPreviewList( text = listTitle, color = titleColor, fontSize = 18.sp, - fontWeight = FontWeight.Bold + fontWeight = FontWeight.ExtraBold ) TextButton( diff --git a/feature/main/src/main/java/com/doyoonkim/main/notice/NoticeDetailScreen.kt b/feature/main/src/main/java/com/doyoonkim/main/notice/NoticeDetailScreen.kt index 39e3402d..8d8b2c3a 100644 --- a/feature/main/src/main/java/com/doyoonkim/main/notice/NoticeDetailScreen.kt +++ b/feature/main/src/main/java/com/doyoonkim/main/notice/NoticeDetailScreen.kt @@ -34,12 +34,14 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView @@ -48,8 +50,10 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.doyoonkim.main.viewmodel.NoticeDetailViewModel import com.doyoonkim.model.NoticeVO import com.doyoonkim.common.R +import com.doyoonkim.common.theme.displayBackground import com.doyoonkim.common.theme.subTitle -import com.doyoonkim.common.theme.textPurple +import com.doyoonkim.common.theme.variantPurple +import com.doyoonkim.common.ui.TopAppBarWithBackButton @Composable fun NoticeDetailScreen( @@ -67,127 +71,134 @@ fun NoticeDetailScreen( if (!uiState.isReceived) viewModel.getTargetNoticeById(noticeInfo.first) } - Column( - modifier = modifier - .windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Bottom)), - verticalArrangement = Arrangement.Top, - horizontalAlignment = Alignment.CenterHorizontally - ) { - if (noticeInfo.second.isNotBlank()) { - if (!uiState.isLoadingCompleted) { - LinearProgressIndicator( - modifier = Modifier.fillMaxWidth().wrapContentHeight(), - progress = { - uiState.loadingStatus - } - ) - } - Box( - modifier = Modifier.fillMaxSize() - ) { - AndroidView( - modifier = Modifier.fillMaxSize(), - factory = { context -> - WebView(context).apply { - //Enable Javascript - // Security Alert: XSS Vulnerability - settings.javaScriptEnabled = true - settings.defaultTextEncodingName = "UTF-8" + Scaffold( + topBar = { + TopAppBarWithBackButton( + titleText = uiState.receivedNotice?.title ?: "", + onBackPressed = onBackPressed + ) + }, + containerColor = MaterialTheme.colorScheme.displayBackground + ) { innerPadding -> + Column( + modifier = modifier + .padding(innerPadding), + verticalArrangement = Arrangement.Top, + horizontalAlignment = Alignment.CenterHorizontally + ) { + if (noticeInfo.second.isNotBlank()) { + if (!uiState.isLoadingCompleted) { + LinearProgressIndicator( + modifier = Modifier.fillMaxWidth().wrapContentHeight(), + progress = { + uiState.loadingStatus + } + ) + } + Box( + modifier = Modifier.fillMaxSize() + ) { + AndroidView( + modifier = Modifier.fillMaxSize(), + factory = { context -> + WebView(context).apply { + //Enable Javascript + // Security Alert: XSS Vulnerability + settings.javaScriptEnabled = true + settings.defaultTextEncodingName = "UTF-8" - webViewClient = object : WebViewClient() { - override fun onPageFinished(view: WebView?, url: String?) { - val theme = context.resources.configuration.uiMode.and(Configuration.UI_MODE_NIGHT_MASK) + webViewClient = object : WebViewClient() { + override fun onPageFinished(view: WebView?, url: String?) { - evaluateJavascript( - """ - let div_accessibility = document.getElementById('accessibility'); - let div_header = document.getElementById('header'); - let div_point = document.getElementById('point'); - let div_footer = document.getElementById('footer'); - let div_footer_root = document.getElementById('fb-root'); - - let section_svisual = document.getElementById('svisual'); - let section_location = document.getElementById('location'); - let aside_remote = document.getElementById('remote'); - - let p_board_butt = document.getElementsByClassName('board_butt'); - - div_accessibility.remove(); - div_header.remove(); - div_footer.remove(); - - aside_remote.remove(); - p_board_butt[0].remove(); - - """.trimIndent(), - ) { result -> - Log.d("Android Web View Client", "RESULT: $result") - visibility = View.VISIBLE + evaluateJavascript( + """ + let div_accessibility = document.getElementById('accessibility'); + let div_header = document.getElementById('header'); + let div_point = document.getElementById('point'); + let div_footer = document.getElementById('footer'); + let div_footer_root = document.getElementById('fb-root'); + + let section_svisual = document.getElementById('svisual'); + let section_location = document.getElementById('location'); + let aside_remote = document.getElementById('remote'); + + let p_board_butt = document.getElementsByClassName('board_butt'); + + div_accessibility.remove(); + div_header.remove(); + div_footer.remove(); + + aside_remote.remove(); + p_board_butt[0].remove(); + """.trimIndent(), + ) { result -> + Log.d("Android Web View Client", "RESULT: $result") + visibility = View.VISIBLE + } + super.onPageFinished(view, url) } - super.onPageFinished(view, url) } - } - // For Progress Indicator - webChromeClient = object: WebChromeClient() { - override fun onProgressChanged(view: WebView?, newProgress: Int) { - // Update progress status - viewModel.updateLoadingStatus(newProgress) - super.onProgressChanged(view, newProgress) + // For Progress Indicator + webChromeClient = object: WebChromeClient() { + override fun onProgressChanged(view: WebView?, newProgress: Int) { + // Update progress status + viewModel.updateLoadingStatus(newProgress) + super.onProgressChanged(view, newProgress) + } } - } - setDownloadListener { url, userAgent, contentDisposition, mimetype, contentLength -> - val request = DownloadManager.Request(url.toUri()) - val filename = URLUtil.guessFileName(url, contentDisposition, mimetype).also { Log.d("DownloadManager", "Filename: $it") } - // save session data before downloading the target file. - val cookies = CookieManager.getInstance().getCookie(url) + setDownloadListener { url, userAgent, contentDisposition, mimetype, contentLength -> + val request = DownloadManager.Request(url.toUri()) + val filename = URLUtil.guessFileName(url, contentDisposition, mimetype).also { Log.d("DownloadManager", "Filename: $it") } + // save session data before downloading the target file. + val cookies = CookieManager.getInstance().getCookie(url) - request.apply { - setMimeType(mimetype) - addRequestHeader("cookie", cookies) - addRequestHeader("User-Agent", userAgent) - setDescription("Downloading File") - setTitle(filename) -// allowScanningByMediaScanner() Deprecated. - setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) - setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename) - } - val downloadManager = context.getSystemService(DOWNLOAD_SERVICE) as DownloadManager - downloadManager.enqueue(request).also { - Toast.makeText(context, R.string.text_download, Toast.LENGTH_LONG).show() - // Guide user to the File application - context.startActivity(Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)) + request.apply { + setMimeType(mimetype) + addRequestHeader("cookie", cookies) + addRequestHeader("User-Agent", userAgent) + setDescription("Downloading File") + setTitle(filename) +// allowScanningByMediaScanner() Deprecated. + setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) + setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename) + } + val downloadManager = context.getSystemService(DOWNLOAD_SERVICE) as DownloadManager + downloadManager.enqueue(request).also { + Toast.makeText(context, R.string.text_download, Toast.LENGTH_LONG).show() + // Guide user to the File application + context.startActivity(Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)) + } } - } - visibility = View.INVISIBLE - settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW - loadUrl(noticeInfo.second) + visibility = View.INVISIBLE + settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW + loadUrl(noticeInfo.second) + } } - } - ) + ) - if (noticeInfo.third) { - FloatingActionButton( - modifier = Modifier.wrapContentSize() - .windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Bottom)) - .padding(end = 10.dp, bottom = 30.dp) - .align(Alignment.BottomEnd), - onClick = { - if (uiState.isReceived) uiState.receivedNotice?.let(onBookmarkCreate) - }, - containerColor = if (uiState.isReceived) { - MaterialTheme.colorScheme.textPurple - } else { - MaterialTheme.colorScheme.subTitle + if (noticeInfo.third) { + FloatingActionButton( + modifier = Modifier.wrapContentSize() + .padding(end = 10.dp, bottom = 30.dp) + .align(Alignment.BottomEnd), + onClick = { + if (uiState.isReceived) uiState.receivedNotice?.let(onBookmarkCreate) + }, + containerColor = if (uiState.isReceived) { + MaterialTheme.colorScheme.variantPurple + } else { + MaterialTheme.colorScheme.subTitle + } + ) { + Icon( + imageVector = Icons.Filled.Add, + contentDescription = "Add to bookmark", + tint = Color.White + ) } - ) { - Icon( - imageVector = Icons.Filled.Add, - contentDescription = "Add to bookmark", - tint = Color.White - ) } } } @@ -198,29 +209,5 @@ fun NoticeDetailScreen( @Preview(showSystemUi = true, showBackground = true) @Composable fun NoticeDetailScreen_Preview() { - Box( - modifier = Modifier.fillMaxSize() - ) { - FloatingActionButton( - modifier = Modifier.wrapContentSize() - .padding(end = 10.dp, bottom = 30.dp) - .align(Alignment.BottomEnd), - onClick = { - // TODO Set proper paramter for onBookmarkCreate() -// if (true) uiState.receivedNotice?.let() - }, - containerColor = if (true) { - MaterialTheme.colorScheme.textPurple - } else { - MaterialTheme.colorScheme.subTitle - } - ) { - Icon( - imageVector = Icons.Filled.Add, - contentDescription = "Add to bookmark", - tint = Color.White - ) - } - } } \ No newline at end of file diff --git a/feature/main/src/main/java/com/doyoonkim/main/notice/NoticeSearchScreen.kt b/feature/main/src/main/java/com/doyoonkim/main/notice/NoticeSearchScreen.kt index cc423a90..288c6dc0 100644 --- a/feature/main/src/main/java/com/doyoonkim/main/notice/NoticeSearchScreen.kt +++ b/feature/main/src/main/java/com/doyoonkim/main/notice/NoticeSearchScreen.kt @@ -4,47 +4,53 @@ import androidx.activity.compose.BackHandler import androidx.compose.animation.scaleIn import androidx.compose.animation.scaleOut import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.systemBars -import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.KeyboardArrowDown import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.material3.TextFieldDefaults +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.doyoonkim.main.viewmodel.NoticeSearchViewModel import com.doyoonkim.common.R -import com.doyoonkim.common.theme.containerBackground +import com.doyoonkim.common.theme.secondaryBackground +import com.doyoonkim.common.theme.displayBackground import com.doyoonkim.common.theme.subTitle -import com.doyoonkim.common.theme.textPurple import com.doyoonkim.common.theme.title +import com.doyoonkim.common.theme.variantPurple import com.doyoonkim.common.ui.NotificationPreview +@OptIn(ExperimentalMaterial3Api::class) @Composable fun NoticeSearchScreen( modifier: Modifier = Modifier, @@ -53,6 +59,7 @@ fun NoticeSearchScreen( onNoticeSelected: (Int, String) -> Unit ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val localFocusManager = LocalFocusManager.current BackHandler { onBackPressed() } @@ -60,55 +67,73 @@ fun NoticeSearchScreen( viewModel.observeKeywordInput() } - Column( - modifier = modifier - .fillMaxWidth() - .wrapContentHeight() - .windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Bottom)) - ) { - Row( - modifier = Modifier - .fillMaxWidth() - .wrapContentHeight(), - horizontalArrangement = Arrangement.spacedBy(3.dp), - verticalAlignment = Alignment.CenterVertically - ) { - TextField( - modifier = Modifier - .weight(8f) - .wrapContentHeight() - .padding(2.dp), - value = uiState.searchKeyword, - placeholder = { Text(stringResource(R.string.title_search)) }, - onValueChange = { viewModel.updateSearchKeyword(it) }, - colors = TextFieldDefaults.colors( - focusedTextColor = MaterialTheme.colorScheme.title, - unfocusedTextColor = MaterialTheme.colorScheme.subTitle, - focusedContainerColor = MaterialTheme.colorScheme.containerBackground, - unfocusedContainerColor = MaterialTheme.colorScheme.containerBackground, - focusedIndicatorColor = Color.Transparent, - unfocusedIndicatorColor = Color.Transparent, - disabledIndicatorColor = Color.Transparent - ), - shape = RoundedCornerShape(15.dp) + Scaffold( + modifier = Modifier.fillMaxSize(), + topBar = { + TopAppBar( + modifier = Modifier.padding(vertical = 10.dp), + title = { + TextField( + modifier = Modifier + .fillMaxSize() + .wrapContentHeight() + .padding(2.dp), + value = uiState.searchKeyword, + placeholder = { Text(stringResource(R.string.title_search)) }, + onValueChange = { viewModel.updateSearchKeyword(it) }, + colors = TextFieldDefaults.colors( + focusedTextColor = MaterialTheme.colorScheme.title, + unfocusedTextColor = MaterialTheme.colorScheme.subTitle, + focusedContainerColor = MaterialTheme.colorScheme.secondaryBackground, + unfocusedContainerColor = MaterialTheme.colorScheme.secondaryBackground, + focusedIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent, + disabledIndicatorColor = Color.Transparent + ), + shape = RoundedCornerShape(15.dp), + singleLine = true + ) + }, + actions = { + IconButton( + onClick = { onBackPressed() } + ) { + Icon( + imageVector = Icons.Default.KeyboardArrowDown, + contentDescription = null, + tint = MaterialTheme.colorScheme.title + ) + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.displayBackground, + titleContentColor = MaterialTheme.colorScheme.title + ) ) - } - + }, + containerColor = MaterialTheme.colorScheme.displayBackground + ) { innerPadding -> Box( modifier = Modifier .fillMaxSize() - .align(Alignment.CenterHorizontally) + .padding(innerPadding) + .pointerInput(Unit) { + detectTapGestures( + onTap = { localFocusManager.clearFocus() } + ) + } ) { LazyColumn( modifier = Modifier .fillMaxWidth() - .wrapContentHeight(), + .wrapContentHeight() + .align(Alignment.TopCenter), contentPadding = PaddingValues(3.dp) ) { items(uiState.fetchResult) { notice -> HorizontalDivider( Modifier.fillMaxWidth().padding(start = 10.dp, end = 10.dp), - color = MaterialTheme.colorScheme.containerBackground + color = MaterialTheme.colorScheme.secondaryBackground ) Row( @@ -128,15 +153,15 @@ fun NoticeSearchScreen( } } - androidx.compose.animation.AnimatedVisibility( + androidx.compose.animation.AnimatedVisibility( visible = uiState.isFetching, modifier = Modifier.wrapContentSize().align(Alignment.Center), enter = scaleIn(), exit = scaleOut() ) { CircularProgressIndicator( - color = MaterialTheme.colorScheme.textPurple, - trackColor = MaterialTheme.colorScheme.containerBackground + color = MaterialTheme.colorScheme.variantPurple, + trackColor = MaterialTheme.colorScheme.secondaryBackground ) } } diff --git a/feature/main/src/main/java/com/doyoonkim/main/notice/NoticesInCategoryScreen.kt b/feature/main/src/main/java/com/doyoonkim/main/notice/NoticesInCategoryScreen.kt index e3d41858..efd69c4a 100644 --- a/feature/main/src/main/java/com/doyoonkim/main/notice/NoticesInCategoryScreen.kt +++ b/feature/main/src/main/java/com/doyoonkim/main/notice/NoticesInCategoryScreen.kt @@ -1,7 +1,6 @@ package com.doyoonkim.main.notice import androidx.activity.compose.BackHandler -import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -17,27 +16,44 @@ import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Text +import androidx.compose.material.TopAppBar +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.pullrefresh.PullRefreshIndicator import androidx.compose.material.pullrefresh.pullRefresh import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.doyoonkim.common.theme.containerBackground -import com.doyoonkim.common.theme.containerBackgroundSolid -import com.doyoonkim.common.theme.textPurple +import com.doyoonkim.common.R +import com.doyoonkim.common.theme.secondaryBackground +import com.doyoonkim.common.theme.displayBackground +import com.doyoonkim.common.theme.onAnyBackground +import com.doyoonkim.common.theme.title +import com.doyoonkim.common.theme.variantPurple import com.doyoonkim.common.ui.NotificationPreview +import com.doyoonkim.common.ui.TopAppBarWithBackButton import com.doyoonkim.main.viewmodel.NoticesInCategoryViewModel import com.doyoonkim.model.NoticeCategory -@OptIn(ExperimentalMaterialApi::class) +@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class) @Composable fun NoticesInCategoryScreen( modifier: Modifier, @@ -47,7 +63,13 @@ fun NoticesInCategoryScreen( onNoticeSelected: (Int, String) -> Unit ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() - + val scaffoldTitle = when (category) { + NoticeCategory.GENERAL_NEWS -> R.string.general_news + NoticeCategory.ACADEMIC_NEWS -> R.string.academic_news + NoticeCategory.SCHOLARSHIP_NEWS -> R.string.scholarship_news + NoticeCategory.EVENT_NEWS -> R.string.event_news + else -> R.string.app_name + } // Back Handler BackHandler { onBackButtonPressed() } @@ -63,60 +85,70 @@ fun NoticesInCategoryScreen( viewModel.getNoticesPerPageInCategory(category) } - Box( - modifier = modifier.fillMaxWidth() - .background(MaterialTheme.colorScheme.containerBackground) - .windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Bottom)) - .pullRefresh(pullRefreshState) - ) { - LazyColumn( - Modifier.fillMaxWidth().wrapContentHeight(), - verticalArrangement = Arrangement.spacedBy(5.dp), - userScrollEnabled = true + Scaffold( + topBar = { + TopAppBarWithBackButton( + titleText = stringResource(scaffoldTitle), + onBackPressed = onBackButtonPressed + ) + }, + containerColor = MaterialTheme.colorScheme.displayBackground + ) { innerPadding -> + Box( + modifier = modifier.fillMaxWidth() + .padding(innerPadding) +// .windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Bottom)) + .pullRefresh(pullRefreshState) ) { - items(uiState.notices.size) { index -> - if (index == uiState.notices.size - 1) { - Row( - modifier = Modifier.fillMaxWidth().wrapContentHeight(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center - ) { - CircularProgressIndicator( - modifier = Modifier.wrapContentSize(), - color = MaterialTheme.colorScheme.textPurple, - trackColor = MaterialTheme.colorScheme.containerBackground - ) - } - viewModel.requestMoreNotices() - } else { - if (index != 0) { - HorizontalDivider( - Modifier.fillMaxWidth(), - color =MaterialTheme.colorScheme.containerBackgroundSolid, - thickness = 1.2.dp - ) - } - val notice = uiState.notices[index] - Row( - modifier = Modifier.wrapContentSize() - .clickable { onNoticeSelected(notice.nttId, notice.url) } - ) { - NotificationPreview( - isLoading = uiState.isLoading, - notificationTitle = notice.title, - notificationInfo = "[${notice.departName}] ${notice.timestamp}", - isImageContained = notice.imageUrl != null, - imageUrl = notice.imageUrl ?: "" - ) + LazyColumn( + Modifier.fillMaxWidth().wrapContentHeight(), + verticalArrangement = Arrangement.spacedBy(5.dp), + userScrollEnabled = true + ) { + items(uiState.notices.size) { index -> + if (index == uiState.notices.size - 1) { + Row( + modifier = Modifier.fillMaxWidth().wrapContentHeight(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + CircularProgressIndicator( + modifier = Modifier.wrapContentSize(), + color = MaterialTheme.colorScheme.variantPurple, + trackColor = MaterialTheme.colorScheme.displayBackground + ) + } + viewModel.requestMoreNotices() + } else { + if (index != 0) { + HorizontalDivider( + Modifier.fillMaxWidth(), + color =MaterialTheme.colorScheme.onAnyBackground, + thickness = 1.2.dp + ) + } + val notice = uiState.notices[index] + Row( + modifier = Modifier.wrapContentSize() + .clickable { onNoticeSelected(notice.nttId, notice.url) } + ) { + NotificationPreview( + isLoading = uiState.isLoading, + notificationTitle = notice.title, + notificationInfo = "[${notice.departName}] ${notice.timestamp}", + isImageContained = notice.imageUrl != null, + imageUrl = notice.imageUrl ?: "" + ) + } } } } + PullRefreshIndicator( + modifier = Modifier.align(Alignment.TopCenter) + .padding(top = 10.dp), + refreshing = uiState.isRefreshRequested, + state = pullRefreshState + ) } - PullRefreshIndicator( - modifier = Modifier.align(Alignment.TopCenter) - .padding(top = 10.dp), - refreshing = uiState.isRefreshRequested, - state = pullRefreshState - ) } } \ No newline at end of file diff --git a/feature/main/src/main/java/com/doyoonkim/main/preference/CustomerServiceScreen.kt b/feature/main/src/main/java/com/doyoonkim/main/preference/CustomerServiceScreen.kt index ddce10dd..d6d3877d 100644 --- a/feature/main/src/main/java/com/doyoonkim/main/preference/CustomerServiceScreen.kt +++ b/feature/main/src/main/java/com/doyoonkim/main/preference/CustomerServiceScreen.kt @@ -4,28 +4,24 @@ import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.scaleIn import androidx.compose.animation.scaleOut +import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.ime import androidx.compose.foundation.layout.imePadding -import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.systemBars -import androidx.compose.foundation.layout.systemBarsPadding -import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button -import androidx.compose.material3.ButtonColors import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextField @@ -36,6 +32,8 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp @@ -43,12 +41,12 @@ import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.doyoonkim.main.viewmodel.CustomerServiceViewModel import com.doyoonkim.common.R -import com.doyoonkim.common.theme.buttonContainer -import com.doyoonkim.common.theme.buttonPurple -import com.doyoonkim.common.theme.containerBackground +import com.doyoonkim.common.theme.displayBackground +import com.doyoonkim.common.theme.secondaryBackground import com.doyoonkim.common.theme.subTitle -import com.doyoonkim.common.theme.textPurple import com.doyoonkim.common.theme.title +import com.doyoonkim.common.theme.variantPurple +import com.doyoonkim.common.ui.TopAppBarWithBackButton @Composable fun CustomerServiceScreen( @@ -60,135 +58,147 @@ fun CustomerServiceScreen( // Version Information for Report Submission val versionInfo = stringResource(R.string.version_code) val adjustImePadding = Modifier.consumeWindowInsets(WindowInsets.ime).imePadding() - + val localFocusManager = LocalFocusManager.current BackHandler { onBackPressed() } - Box( - modifier = modifier.fillMaxSize() - .windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Bottom)) - ) { - Column( - verticalArrangement = Arrangement.Top, - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text( - text = stringResource(R.string.customer_service_subtitile_1), - fontWeight = FontWeight.SemiBold, - color = MaterialTheme.colorScheme.textPurple, - fontSize = 14.sp, - modifier = Modifier.fillMaxWidth() - ) - Text( - text = stringResource(R.string.customer_service_subtitle_2), - fontWeight = FontWeight.SemiBold, - color = MaterialTheme.colorScheme.textPurple, - fontSize = 14.sp, - modifier = Modifier.fillMaxWidth() + Scaffold( + topBar = { + TopAppBarWithBackButton( + titleText = stringResource(R.string.title_customer_service), + onBackPressed = onBackPressed ) - - - Box( - modifier = Modifier.fillMaxWidth().weight(5f) - .padding(top = 25.dp, bottom = 25.dp) - .then(adjustImePadding) + }, + containerColor = MaterialTheme.colorScheme.displayBackground + ) { innerPadding -> + Box( + modifier = modifier.fillMaxSize() + .padding(innerPadding) + .pointerInput(Unit) { + detectTapGestures( + onTap = { localFocusManager.clearFocus() } + ) + } + ) { + Column( + verticalArrangement = Arrangement.Top, + horizontalAlignment = Alignment.CenterHorizontally ) { - TextField( - modifier = Modifier.fillMaxSize(), - value = uiState.userReport, - placeholder = { Text(stringResource(R.string.placeholder_customer_report)) }, - enabled = !uiState.isSubmissionCompleted, - onValueChange = { - viewModel.updateUserReportContent(it) - }, - colors = TextFieldDefaults.colors( - focusedTextColor = MaterialTheme.colorScheme.title, - unfocusedTextColor = MaterialTheme.colorScheme.subTitle, - focusedContainerColor = MaterialTheme.colorScheme.containerBackground, - unfocusedContainerColor = MaterialTheme.colorScheme.containerBackground, - focusedIndicatorColor = Color.Transparent, - unfocusedIndicatorColor = Color.Transparent, - disabledIndicatorColor = Color.Transparent - ), - shape = RoundedCornerShape(15.dp) - ) - Text( - text = "${uiState.userReport.length}/500", - fontSize = 12.sp, - fontWeight = FontWeight.Medium, - color = MaterialTheme.colorScheme.subTitle, - modifier = Modifier.wrapContentSize() - .padding(15.dp) - .align(Alignment.BottomEnd) + text = stringResource(R.string.customer_service_subtitile_1), + fontWeight = FontWeight.SemiBold, + color = MaterialTheme.colorScheme.variantPurple, + fontSize = 14.sp, + modifier = Modifier.fillMaxWidth() ) - } - - Button( - modifier = Modifier - .fillMaxWidth() - .wrapContentHeight() - .padding(start = 3.dp, end = 3.dp) - , - enabled = !uiState.isSubmissionCompleted && uiState.exceedMinCharacters, - shape = RoundedCornerShape(10.dp), - colors = ButtonDefaults.buttonColors().copy( - containerColor = MaterialTheme.colorScheme.buttonPurple, - contentColor = Color.White, - ), - onClick = { viewModel.submitUserReport(versionInfo) } - ) { Text( - text = stringResource(R.string.btn_submit), - fontSize = 16.sp, - fontWeight = FontWeight.Bold, - modifier = Modifier.padding(10.dp) + text = stringResource(R.string.customer_service_subtitle_2), + fontWeight = FontWeight.SemiBold, + color = MaterialTheme.colorScheme.variantPurple, + fontSize = 14.sp, + modifier = Modifier.fillMaxWidth() ) - } - } - AnimatedVisibility( - modifier = Modifier.wrapContentSize().align(Alignment.Center), - visible = uiState.isSubmissionCompleted, - enter = scaleIn(), - exit = scaleOut() - ) { - Surface( - modifier = Modifier.padding(15.dp) - .clip(RoundedCornerShape(15.dp)), - color = MaterialTheme.colorScheme.surfaceBright - ) { - Column( - modifier = Modifier.wrapContentHeight() - .padding(30.dp), - verticalArrangement = Arrangement.spacedBy(10.dp) + Box( + modifier = Modifier.fillMaxWidth().weight(5f) + .padding(top = 25.dp, bottom = 25.dp) + .then(adjustImePadding) ) { + TextField( + modifier = Modifier.fillMaxSize(), + value = uiState.userReport, + placeholder = { Text(stringResource(R.string.placeholder_customer_report)) }, + enabled = !uiState.isSubmissionCompleted, + onValueChange = { + viewModel.updateUserReportContent(it) + }, + colors = TextFieldDefaults.colors( + focusedTextColor = MaterialTheme.colorScheme.title, + unfocusedTextColor = MaterialTheme.colorScheme.subTitle, + focusedContainerColor = MaterialTheme.colorScheme.secondaryBackground, + unfocusedContainerColor = MaterialTheme.colorScheme.secondaryBackground, + focusedIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent, + disabledIndicatorColor = Color.Transparent + ), + shape = RoundedCornerShape(15.dp) + ) + Text( - fontSize = 20.sp, - fontWeight = FontWeight.Bold, - text = stringResource(R.string.submission_completed_title) + text = "${uiState.userReport.length}/500", + fontSize = 12.sp, + fontWeight = FontWeight.Medium, + color = MaterialTheme.colorScheme.subTitle, + modifier = Modifier.wrapContentSize() + .padding(15.dp) + .align(Alignment.BottomEnd) ) + } + + Button( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(start = 3.dp, end = 3.dp) + , + enabled = !uiState.isSubmissionCompleted && uiState.exceedMinCharacters, + shape = RoundedCornerShape(10.dp), + colors = ButtonDefaults.buttonColors().copy( + containerColor = MaterialTheme.colorScheme.variantPurple, + contentColor = Color.White, + ), + onClick = { viewModel.submitUserReport(versionInfo) } + ) { Text( - fontSize = 14.sp, + text = stringResource(R.string.btn_submit), + fontSize = 16.sp, fontWeight = FontWeight.Bold, - text = stringResource(R.string.submission_completed__subtitle) + modifier = Modifier.padding(10.dp) ) - Button( - onClick = { viewModel.resetSubmissionStatus() }, - modifier = Modifier.fillMaxWidth() + } + } + + AnimatedVisibility( + modifier = Modifier.wrapContentSize().align(Alignment.Center), + visible = uiState.isSubmissionCompleted, + enter = scaleIn(), + exit = scaleOut() + ) { + Surface( + modifier = Modifier.padding(15.dp) + .clip(RoundedCornerShape(15.dp)), + color = MaterialTheme.colorScheme.surfaceBright + ) { + Column( + modifier = Modifier.wrapContentHeight() + .padding(30.dp), + verticalArrangement = Arrangement.spacedBy(10.dp) ) { + Text( + fontSize = 20.sp, + fontWeight = FontWeight.Bold, + text = stringResource(R.string.submission_completed_title) + ) Text( fontSize = 14.sp, fontWeight = FontWeight.Bold, - text = stringResource(R.string.btn_confirm) + text = stringResource(R.string.submission_completed__subtitle) ) + Button( + onClick = { viewModel.resetSubmissionStatus() }, + modifier = Modifier.fillMaxWidth() + ) { + Text( + fontSize = 14.sp, + fontWeight = FontWeight.Bold, + text = stringResource(R.string.btn_confirm) + ) + } } } - } } - } } \ No newline at end of file diff --git a/feature/main/src/main/java/com/doyoonkim/main/preference/NotificationPreferencesScreen.kt b/feature/main/src/main/java/com/doyoonkim/main/preference/NotificationPreferencesScreen.kt index 84e24106..0189e226 100644 --- a/feature/main/src/main/java/com/doyoonkim/main/preference/NotificationPreferencesScreen.kt +++ b/feature/main/src/main/java/com/doyoonkim/main/preference/NotificationPreferencesScreen.kt @@ -9,12 +9,14 @@ import android.content.pm.PackageManager import androidx.activity.compose.BackHandler import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Switch import androidx.compose.material3.SwitchDefaults @@ -33,13 +35,15 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.compose.LifecycleEventEffect import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.doyoonkim.common.R -import com.doyoonkim.common.theme.buttonPurple -import com.doyoonkim.common.theme.containerBackground +import com.doyoonkim.common.theme.displayBackground +import com.doyoonkim.common.theme.onAnyBackground +import com.doyoonkim.common.theme.secondaryBackground import com.doyoonkim.common.theme.subTitle -import com.doyoonkim.common.theme.textPurple import com.doyoonkim.common.theme.title +import com.doyoonkim.common.theme.variantPurple import com.doyoonkim.common.ui.RoundedCornerColumn import com.doyoonkim.common.ui.RoundedCornerColumnTextItemWithExtraOnRight +import com.doyoonkim.common.ui.TopAppBarWithBackButton import com.doyoonkim.main.viewmodel.NotificationPreferencesViewModel @Composable @@ -72,145 +76,154 @@ fun NotificationPreferencesScreen( ) } - RoundedCornerColumn( - modifier = Modifier.fillMaxWidth().padding(10.dp), - backgroundColor = MaterialTheme.colorScheme.containerBackground - ) { - RoundedCornerColumnTextItemWithExtraOnRight( - verticalPadding = 15.dp, - titleText = stringResource(R.string.enable_notification_title), - subTitleText = stringResource(R.string.enable_service_notification_sub), - primaryColor = MaterialTheme.colorScheme.title, - secondaryColor = MaterialTheme.colorScheme.subTitle, - hasBottomDivider = true - ) { - Switch( - checked = uiStatus.isMainNotificationPermissionGranted, - colors = SwitchDefaults.colors().copy( - checkedTrackColor = MaterialTheme.colorScheme.buttonPurple, - checkedThumbColor = Color.White - ), - onCheckedChange = { - val settingIntent = Intent( - "android.settings.APP_NOTIFICATION_SETTINGS" - ).apply { - this.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - this.putExtra( - "android.provider.extra.APP_PACKAGE", - context.packageName - ) - } - context.startActivity(settingIntent) - }, - enabled = uiStatus.isSyncCompleted + Scaffold( + topBar = { + TopAppBarWithBackButton( + titleText = stringResource(R.string.title_notification_pref), + onBackPressed = onBackPressed ) - } - - RoundedCornerColumnTextItemWithExtraOnRight( - modifier = Modifier.padding(start = 10.dp), - verticalPadding = 15.dp, - titleText = stringResource(R.string.general_notificaiton_channel_name), - subTitleText = stringResource(R.string.general_notification_channel_description), - primaryColor = MaterialTheme.colorScheme.title, - secondaryColor = MaterialTheme.colorScheme.subTitle, - hasBottomDivider = true + }, + containerColor = MaterialTheme.colorScheme.displayBackground + ) { innerPadding -> + RoundedCornerColumn( + modifier = modifier.fillMaxWidth().padding(innerPadding), + backgroundColor = MaterialTheme.colorScheme.secondaryBackground ) { - Switch( - checked = uiStatus.isEachChannelAllowed[0], - colors = SwitchDefaults.colors().copy( - checkedTrackColor = MaterialTheme.colorScheme.buttonPurple, - checkedThumbColor = Color.White - ), - onCheckedChange = { - viewModel.updateChannelPreferenceState(0, it) - }, - enabled = uiStatus.isMainNotificationPermissionGranted && uiStatus.isSyncCompleted - ) - } + RoundedCornerColumnTextItemWithExtraOnRight( + verticalPadding = 15.dp, + titleText = stringResource(R.string.enable_notification_title), + subTitleText = stringResource(R.string.enable_service_notification_sub), + primaryColor = MaterialTheme.colorScheme.title, + secondaryColor = MaterialTheme.colorScheme.subTitle, + hasBottomDivider = true + ) { + Switch( + checked = uiStatus.isMainNotificationPermissionGranted, + colors = SwitchDefaults.colors().copy( + checkedTrackColor = MaterialTheme.colorScheme.variantPurple, + checkedThumbColor = Color.White + ), + onCheckedChange = { + val settingIntent = Intent( + "android.settings.APP_NOTIFICATION_SETTINGS" + ).apply { + this.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + this.putExtra( + "android.provider.extra.APP_PACKAGE", + context.packageName + ) + } + context.startActivity(settingIntent) + }, + enabled = uiStatus.isSyncCompleted + ) + } - RoundedCornerColumnTextItemWithExtraOnRight( - modifier = Modifier.padding(start = 10.dp), - verticalPadding = 15.dp, - titleText = stringResource(R.string.academic_notification_channel_name), - subTitleText = stringResource(R.string.academic_notification_channel_description), - primaryColor = MaterialTheme.colorScheme.title, - secondaryColor = MaterialTheme.colorScheme.subTitle, - hasBottomDivider = true - ) { - Switch( - checked = uiStatus.isEachChannelAllowed[1], - colors = SwitchDefaults.colors().copy( - checkedTrackColor = MaterialTheme.colorScheme.buttonPurple, - checkedThumbColor = Color.White - ), - onCheckedChange = { - viewModel.updateChannelPreferenceState(1, it) - }, - enabled = uiStatus.isMainNotificationPermissionGranted && uiStatus.isSyncCompleted - ) - } + RoundedCornerColumnTextItemWithExtraOnRight( + modifier = Modifier.padding(start = 10.dp), + verticalPadding = 15.dp, + titleText = stringResource(R.string.general_notificaiton_channel_name), + subTitleText = stringResource(R.string.general_notification_channel_description), + primaryColor = MaterialTheme.colorScheme.title, + secondaryColor = MaterialTheme.colorScheme.subTitle, + hasBottomDivider = true + ) { + Switch( + checked = uiStatus.isEachChannelAllowed[0], + colors = SwitchDefaults.colors().copy( + checkedTrackColor = MaterialTheme.colorScheme.variantPurple, + checkedThumbColor = Color.White + ), + onCheckedChange = { + viewModel.updateChannelPreferenceState(0, it) + }, + enabled = uiStatus.isMainNotificationPermissionGranted && uiStatus.isSyncCompleted + ) + } - RoundedCornerColumnTextItemWithExtraOnRight( - modifier = Modifier.padding(start = 10.dp), - verticalPadding = 15.dp, - titleText = stringResource(R.string.scholarship_notification_channel_name), - subTitleText = stringResource(R.string.scholarship_notification_channel_description), - primaryColor = MaterialTheme.colorScheme.title, - secondaryColor = MaterialTheme.colorScheme.subTitle, - hasBottomDivider = true - ) { - Switch( - checked = uiStatus.isEachChannelAllowed[2], - colors = SwitchDefaults.colors().copy( - checkedTrackColor = MaterialTheme.colorScheme.buttonPurple, - checkedThumbColor = Color.White - ), - onCheckedChange = { - viewModel.updateChannelPreferenceState(2, it) - }, - enabled = uiStatus.isMainNotificationPermissionGranted && uiStatus.isSyncCompleted - ) - } + RoundedCornerColumnTextItemWithExtraOnRight( + modifier = Modifier.padding(start = 10.dp), + verticalPadding = 15.dp, + titleText = stringResource(R.string.academic_notification_channel_name), + subTitleText = stringResource(R.string.academic_notification_channel_description), + primaryColor = MaterialTheme.colorScheme.title, + secondaryColor = MaterialTheme.colorScheme.subTitle, + hasBottomDivider = true + ) { + Switch( + checked = uiStatus.isEachChannelAllowed[1], + colors = SwitchDefaults.colors().copy( + checkedTrackColor = MaterialTheme.colorScheme.variantPurple, + checkedThumbColor = Color.White + ), + onCheckedChange = { + viewModel.updateChannelPreferenceState(1, it) + }, + enabled = uiStatus.isMainNotificationPermissionGranted && uiStatus.isSyncCompleted + ) + } - RoundedCornerColumnTextItemWithExtraOnRight( - modifier = Modifier.padding(start = 10.dp), - verticalPadding = 15.dp, - titleText = stringResource(R.string.event_notification_channel_name), - subTitleText = stringResource(R.string.event_notification_channel_description), - primaryColor = MaterialTheme.colorScheme.title, - secondaryColor = MaterialTheme.colorScheme.subTitle, - hasBottomDivider = false - ) { - Switch( - checked = uiStatus.isEachChannelAllowed[3], - colors = SwitchDefaults.colors().copy( - checkedTrackColor = MaterialTheme.colorScheme.buttonPurple, - checkedThumbColor = Color.White - ), - onCheckedChange = { - viewModel.updateChannelPreferenceState(3, it) - }, - enabled = uiStatus.isMainNotificationPermissionGranted && uiStatus.isSyncCompleted - ) - } - } + RoundedCornerColumnTextItemWithExtraOnRight( + modifier = Modifier.padding(start = 10.dp), + verticalPadding = 15.dp, + titleText = stringResource(R.string.scholarship_notification_channel_name), + subTitleText = stringResource(R.string.scholarship_notification_channel_description), + primaryColor = MaterialTheme.colorScheme.title, + secondaryColor = MaterialTheme.colorScheme.subTitle, + hasBottomDivider = true + ) { + Switch( + checked = uiStatus.isEachChannelAllowed[2], + colors = SwitchDefaults.colors().copy( + checkedTrackColor = MaterialTheme.colorScheme.variantPurple, + checkedThumbColor = Color.White + ), + onCheckedChange = { + viewModel.updateChannelPreferenceState(2, it) + }, + enabled = uiStatus.isMainNotificationPermissionGranted && uiStatus.isSyncCompleted + ) + } - if (!uiStatus.isSyncCompleted) { - Box( - modifier = Modifier.fillMaxSize() - .background(Color.Transparent) - ) { - Surface( - modifier = Modifier.align(Alignment.Center) + RoundedCornerColumnTextItemWithExtraOnRight( + modifier = Modifier.padding(start = 10.dp), + verticalPadding = 15.dp, + titleText = stringResource(R.string.event_notification_channel_name), + subTitleText = stringResource(R.string.event_notification_channel_description), + primaryColor = MaterialTheme.colorScheme.title, + secondaryColor = MaterialTheme.colorScheme.subTitle, + hasBottomDivider = false + ) { + Switch( + checked = uiStatus.isEachChannelAllowed[3], + colors = SwitchDefaults.colors().copy( + checkedTrackColor = MaterialTheme.colorScheme.variantPurple, + checkedThumbColor = Color.White + ), + onCheckedChange = { + viewModel.updateChannelPreferenceState(3, it) + }, + enabled = uiStatus.isMainNotificationPermissionGranted && uiStatus.isSyncCompleted + ) + } + } + if (!uiStatus.isSyncCompleted) { + Box( + modifier = Modifier.fillMaxSize() .background(Color.Transparent) - .clip(RoundedCornerShape(20.dp)), - color = MaterialTheme.colorScheme.containerBackground ) { - CircularProgressIndicator( + Surface( modifier = Modifier.align(Alignment.Center) - .padding(25.dp), - color = MaterialTheme.colorScheme.textPurple - ) + .background(Color.Transparent) + .clip(RoundedCornerShape(20.dp)), + color = MaterialTheme.colorScheme.onAnyBackground + ) { + CircularProgressIndicator( + modifier = Modifier.align(Alignment.Center) + .padding(25.dp), + color = MaterialTheme.colorScheme.variantPurple + ) + } } } } diff --git a/feature/main/src/main/java/com/doyoonkim/main/preference/OssNoticeScreen.kt b/feature/main/src/main/java/com/doyoonkim/main/preference/OssNoticeScreen.kt index ddcf9867..b934b2f4 100644 --- a/feature/main/src/main/java/com/doyoonkim/main/preference/OssNoticeScreen.kt +++ b/feature/main/src/main/java/com/doyoonkim/main/preference/OssNoticeScreen.kt @@ -4,12 +4,20 @@ import android.webkit.WebView import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.only +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.viewinterop.AndroidView +import com.doyoonkim.common.ui.TopAppBarWithBackButton +import com.doyoonkim.common.R +import com.doyoonkim.common.theme.displayBackground @Composable fun OssNoticeScreen( @@ -18,12 +26,22 @@ fun OssNoticeScreen( ) { BackHandler { onBackPressed() } - AndroidView( - modifier = modifier.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Bottom)), - factory = { context -> - WebView(context).apply { - loadUrl("https://knutice.github.io/KNUTICE-OpenSourceLicense/Android/opensource.html") + Scaffold( + topBar = { + TopAppBarWithBackButton( + titleText = stringResource(R.string.oss_notice), + onBackPressed = onBackPressed + ) + }, + containerColor = MaterialTheme.colorScheme.displayBackground + ) { innerPadding -> + AndroidView( + modifier = modifier.fillMaxSize().padding(innerPadding), + factory = { context -> + WebView(context).apply { + loadUrl("https://knutice.github.io/KNUTICE-OpenSourceLicense/Android/opensource.html") + } } - } - ) + ) + } } \ No newline at end of file diff --git a/feature/main/src/main/java/com/doyoonkim/main/preference/UserPreferencesScreen.kt b/feature/main/src/main/java/com/doyoonkim/main/preference/UserPreferencesScreen.kt index 5b185e31..e20ab27d 100644 --- a/feature/main/src/main/java/com/doyoonkim/main/preference/UserPreferencesScreen.kt +++ b/feature/main/src/main/java/com/doyoonkim/main/preference/UserPreferencesScreen.kt @@ -5,22 +5,35 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.material.Text +import androidx.compose.material.TopAppBar +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import com.doyoonkim.common.R -import com.doyoonkim.common.theme.buttonContainer -import com.doyoonkim.common.theme.containerBackground +import com.doyoonkim.common.theme.buttonOnBackground +import com.doyoonkim.common.theme.secondaryBackground +import com.doyoonkim.common.theme.displayBackground import com.doyoonkim.common.theme.subTitle import com.doyoonkim.common.theme.title import com.doyoonkim.common.ui.CircleGoButton import com.doyoonkim.common.ui.RoundedCornerColumn import com.doyoonkim.common.ui.RoundedCornerColumnTextItem import com.doyoonkim.common.ui.RoundedCornerColumnTextItemWithExtraOnRight +import com.doyoonkim.common.ui.TopAppBarWithBackButton @Composable fun UserPreferenceScreen( @@ -32,78 +45,88 @@ fun UserPreferenceScreen( ) { BackHandler { onBackPressed() } - Column( - modifier = modifier.fillMaxWidth() - .padding(10.dp), - verticalArrangement = Arrangement.spacedBy(30.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - RoundedCornerColumn( - backgroundColor = MaterialTheme.colorScheme.containerBackground + Scaffold( + topBar = { + TopAppBarWithBackButton( + titleText = stringResource(R.string.title_preference), + onBackPressed = onBackPressed + ) + }, + containerColor = MaterialTheme.colorScheme.displayBackground + ) { innerPadding -> + Column( + modifier = modifier.fillMaxWidth() + .padding(innerPadding), + verticalArrangement = Arrangement.spacedBy(30.dp), + horizontalAlignment = Alignment.CenterHorizontally ) { - RoundedCornerColumnTextItemWithExtraOnRight( - verticalPadding = 10.dp, - titleText = stringResource(R.string.enable_notification_title), - subTitleText = null, - primaryColor = MaterialTheme.colorScheme.title, - secondaryColor = MaterialTheme.colorScheme.subTitle, - hasBottomDivider = false + RoundedCornerColumn( + backgroundColor = MaterialTheme.colorScheme.secondaryBackground ) { - CircleGoButton( - modifier = Modifier.weight(1f), - containerColor = MaterialTheme.colorScheme.buttonContainer, - contentColor = MaterialTheme.colorScheme.subTitle, - onClick = onNotificationPreferenceClicked - ) + RoundedCornerColumnTextItemWithExtraOnRight( + verticalPadding = 10.dp, + titleText = stringResource(R.string.enable_notification_title), + subTitleText = null, + primaryColor = MaterialTheme.colorScheme.title, + secondaryColor = MaterialTheme.colorScheme.subTitle, + hasBottomDivider = false + ) { + CircleGoButton( + modifier = Modifier.weight(1f), + containerColor = MaterialTheme.colorScheme.buttonOnBackground, + contentColor = MaterialTheme.colorScheme.subTitle, + onClick = onNotificationPreferenceClicked + ) + } } - } - RoundedCornerColumn( - backgroundColor = MaterialTheme.colorScheme.containerBackground - ) { - RoundedCornerColumnTextItemWithExtraOnRight( - verticalPadding = 10.dp, - titleText = stringResource(R.string.title_support), - subTitleText = null, - primaryColor = MaterialTheme.colorScheme.title, - secondaryColor = MaterialTheme.colorScheme.subTitle, - hasBottomDivider = false + RoundedCornerColumn( + backgroundColor = MaterialTheme.colorScheme.secondaryBackground ) { - CircleGoButton( - modifier = Modifier.weight(1f), - containerColor = MaterialTheme.colorScheme.buttonContainer, - contentColor = MaterialTheme.colorScheme.subTitle, - onClick = onCustomerServiceClicked - ) + RoundedCornerColumnTextItemWithExtraOnRight( + verticalPadding = 10.dp, + titleText = stringResource(R.string.title_support), + subTitleText = null, + primaryColor = MaterialTheme.colorScheme.title, + secondaryColor = MaterialTheme.colorScheme.subTitle, + hasBottomDivider = false + ) { + CircleGoButton( + modifier = Modifier.weight(1f), + containerColor = MaterialTheme.colorScheme.buttonOnBackground, + contentColor = MaterialTheme.colorScheme.subTitle, + onClick = onCustomerServiceClicked + ) + } } - } - RoundedCornerColumn( - backgroundColor = MaterialTheme.colorScheme.containerBackground - ) { - RoundedCornerColumnTextItem( - verticalPadding = 12.dp, - titleText = stringResource(R.string.about_version), - subTitleText = stringResource(R.string.version_code), - primaryColor = MaterialTheme.colorScheme.title, - secondaryColor = MaterialTheme.colorScheme.subTitle, - hasBottomDivider = true - ) - - RoundedCornerColumnTextItemWithExtraOnRight( - verticalPadding = 10.dp, - titleText = stringResource(R.string.about_oss), - subTitleText = null, - primaryColor = MaterialTheme.colorScheme.title, - secondaryColor = MaterialTheme.colorScheme.subTitle, - hasBottomDivider = false + RoundedCornerColumn( + backgroundColor = MaterialTheme.colorScheme.secondaryBackground ) { - CircleGoButton( - modifier = Modifier.weight(1f), - containerColor = MaterialTheme.colorScheme.buttonContainer, - contentColor = MaterialTheme.colorScheme.subTitle, - onClick = onOssClicked + RoundedCornerColumnTextItem( + verticalPadding = 12.dp, + titleText = stringResource(R.string.about_version), + subTitleText = stringResource(R.string.version_code), + primaryColor = MaterialTheme.colorScheme.title, + secondaryColor = MaterialTheme.colorScheme.subTitle, + hasBottomDivider = true ) + + RoundedCornerColumnTextItemWithExtraOnRight( + verticalPadding = 10.dp, + titleText = stringResource(R.string.about_oss), + subTitleText = null, + primaryColor = MaterialTheme.colorScheme.title, + secondaryColor = MaterialTheme.colorScheme.subTitle, + hasBottomDivider = false + ) { + CircleGoButton( + modifier = Modifier.weight(1f), + containerColor = MaterialTheme.colorScheme.buttonOnBackground, + contentColor = MaterialTheme.colorScheme.subTitle, + onClick = onOssClicked + ) + } } } }