diff --git a/app/src/main/java/de/pawcode/cardstore/navigation/Navigation.kt b/app/src/main/java/de/pawcode/cardstore/navigation/Navigation.kt index 5e4a6c6..eac5f44 100644 --- a/app/src/main/java/de/pawcode/cardstore/navigation/Navigation.kt +++ b/app/src/main/java/de/pawcode/cardstore/navigation/Navigation.kt @@ -55,6 +55,7 @@ fun Navigation(modifier: Modifier = Modifier) { snackbar = { snackbarData -> Snackbar( snackbarData = snackbarData, + shape = MaterialTheme.shapes.medium, containerColor = MaterialTheme.colorScheme.inverseSurface, contentColor = MaterialTheme.colorScheme.inverseOnSurface, actionColor = MaterialTheme.colorScheme.inversePrimary, diff --git a/app/src/main/java/de/pawcode/cardstore/ui/components/AddCardComponent.kt b/app/src/main/java/de/pawcode/cardstore/ui/components/AddCardComponent.kt index a85549f..0a4ea6b 100644 --- a/app/src/main/java/de/pawcode/cardstore/ui/components/AddCardComponent.kt +++ b/app/src/main/java/de/pawcode/cardstore/ui/components/AddCardComponent.kt @@ -30,6 +30,7 @@ fun AddCardComponent(hasCards: Boolean, onClick: () -> Unit) { modifier = Modifier.fillMaxWidth().aspectRatio(1.586f).clickable { onClick() }, colors = CardDefaults.outlinedCardColors(containerColor = MaterialTheme.colorScheme.surfaceContainer), + shape = MaterialTheme.shapes.large, ) { Column( horizontalAlignment = Alignment.CenterHorizontally, diff --git a/app/src/main/java/de/pawcode/cardstore/ui/components/AppBar.kt b/app/src/main/java/de/pawcode/cardstore/ui/components/AppBar.kt index 581e1b8..f6eda2d 100644 --- a/app/src/main/java/de/pawcode/cardstore/ui/components/AppBar.kt +++ b/app/src/main/java/de/pawcode/cardstore/ui/components/AppBar.kt @@ -5,6 +5,8 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.Sort import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.FilledIconButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -16,15 +18,21 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import de.pawcode.cardstore.R -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun AppBar( title: String, + subtitle: String? = null, onBack: (() -> Unit)? = null, actions: @Composable (RowScope.() -> Unit)? = null, ) { TopAppBar( title = { Text(text = title) }, + subtitle = { + if (subtitle != null) { + Text(text = subtitle) + } + }, navigationIcon = { if (onBack != null) { IconButton(onClick = { onBack() }) { @@ -41,6 +49,7 @@ fun AppBar( containerColor = MaterialTheme.colorScheme.primaryContainer, navigationIconContentColor = MaterialTheme.colorScheme.onPrimaryContainer, titleContentColor = MaterialTheme.colorScheme.onPrimaryContainer, + subtitleContentColor = MaterialTheme.colorScheme.onPrimaryContainer, actionIconContentColor = MaterialTheme.colorScheme.onPrimaryContainer, ), ) @@ -57,9 +66,10 @@ fun PreviewAppBar() { fun PreviewAppBarActions() { AppBar( title = "Card Store", + subtitle = "My cool card", onBack = {}, actions = { - IconButton(onClick = {}) { + FilledIconButton(onClick = {}) { Icon( Icons.AutoMirrored.Filled.Sort, contentDescription = stringResource(R.string.cards_sort), diff --git a/app/src/main/java/de/pawcode/cardstore/ui/components/CardComponent.kt b/app/src/main/java/de/pawcode/cardstore/ui/components/CardComponent.kt index 6f695c8..03c6c97 100644 --- a/app/src/main/java/de/pawcode/cardstore/ui/components/CardComponent.kt +++ b/app/src/main/java/de/pawcode/cardstore/ui/components/CardComponent.kt @@ -44,6 +44,7 @@ fun CardComponent(card: CardEntity, onClick: () -> Unit, onLongPress: () -> Unit ), elevation = CardDefaults.cardElevation(defaultElevation = 8.dp), colors = CardDefaults.cardColors(containerColor = color), + shape = MaterialTheme.shapes.large, ) { Column( horizontalAlignment = Alignment.CenterHorizontally, diff --git a/app/src/main/java/de/pawcode/cardstore/ui/components/EditCardForm.kt b/app/src/main/java/de/pawcode/cardstore/ui/components/EditCardForm.kt index 5c19f81..db309a0 100644 --- a/app/src/main/java/de/pawcode/cardstore/ui/components/EditCardForm.kt +++ b/app/src/main/java/de/pawcode/cardstore/ui/components/EditCardForm.kt @@ -1,5 +1,6 @@ package de.pawcode.cardstore.ui.components +import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -267,6 +268,7 @@ fun EditCardForm( val chipSelected = label.labelId == card.labels.find { it.labelId == label.labelId }?.labelId FilterChip( + modifier = Modifier.padding(bottom = 4.dp), selected = chipSelected, onClick = { onCardUpdate( @@ -282,13 +284,13 @@ fun EditCardForm( }, label = { Text( - modifier = Modifier.padding(vertical = 8.dp), + modifier = Modifier.padding(vertical = 10.dp), text = label.name, style = MaterialTheme.typography.bodyLarge, ) }, leadingIcon = { - if (chipSelected) { + AnimatedVisibility(visible = chipSelected) { Icon(Icons.Filled.Check, contentDescription = null) } }, diff --git a/app/src/main/java/de/pawcode/cardstore/ui/components/LabelsListComponent.kt b/app/src/main/java/de/pawcode/cardstore/ui/components/LabelsListComponent.kt index 0e6d150..ac8a0c5 100644 --- a/app/src/main/java/de/pawcode/cardstore/ui/components/LabelsListComponent.kt +++ b/app/src/main/java/de/pawcode/cardstore/ui/components/LabelsListComponent.kt @@ -1,5 +1,6 @@ package de.pawcode.cardstore.ui.components +import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row @@ -11,9 +12,11 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.EditNote -import androidx.compose.material3.FilledTonalIconButton +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.FilledIconButton import androidx.compose.material3.FilterChip import androidx.compose.material3.Icon +import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -27,6 +30,7 @@ import de.pawcode.cardstore.data.database.entities.EXAMPLE_LABEL import de.pawcode.cardstore.data.database.entities.EXAMPLE_LABEL_LIST import de.pawcode.cardstore.data.database.entities.LabelEntity +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun LabelsListComponent( labels: List, @@ -57,15 +61,16 @@ fun LabelsListComponent( FilterChip( selected = chipSelected, onClick = { onLabelClick(label) }, + shape = MaterialTheme.shapes.medium, label = { Text( - modifier = Modifier.padding(vertical = 8.dp), + modifier = Modifier.padding(vertical = 10.dp), text = label.name, style = MaterialTheme.typography.bodyLarge, ) }, leadingIcon = { - if (chipSelected) { + AnimatedVisibility(visible = chipSelected) { Icon(Icons.Filled.Check, contentDescription = null) } }, @@ -74,11 +79,23 @@ fun LabelsListComponent( } } - FilledTonalIconButton(shape = MaterialTheme.shapes.small, onClick = { onEdit() }) { + FilledIconButton( + modifier = + Modifier.padding(start = 8.dp) + .size( + IconButtonDefaults.smallContainerSize(IconButtonDefaults.IconButtonWidthOption.Wide) + ), + shapes = + IconButtonDefaults.shapes( + shape = IconButtonDefaults.smallSquareShape, + pressedShape = IconButtonDefaults.smallPressedShape, + ), + onClick = { onEdit() }, + ) { Icon( imageVector = if (labels.isNotEmpty()) Icons.Filled.EditNote else Icons.Filled.Add, contentDescription = stringResource(R.string.labels_edit), - modifier = Modifier.size(32.dp), + modifier = Modifier.size(IconButtonDefaults.smallIconSize), ) } } diff --git a/app/src/main/java/de/pawcode/cardstore/ui/components/SelectDropdownMenu.kt b/app/src/main/java/de/pawcode/cardstore/ui/components/SelectDropdownMenu.kt index 4ceb70d..dac751a 100644 --- a/app/src/main/java/de/pawcode/cardstore/ui/components/SelectDropdownMenu.kt +++ b/app/src/main/java/de/pawcode/cardstore/ui/components/SelectDropdownMenu.kt @@ -1,5 +1,9 @@ package de.pawcode.cardstore.ui.components +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.Sort import androidx.compose.material.icons.automirrored.filled.TrendingUp @@ -9,18 +13,24 @@ import androidx.compose.material.icons.filled.History import androidx.compose.material.icons.filled.SortByAlpha import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.IconButtonDefaults +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.DpOffset +import androidx.compose.ui.unit.dp import de.pawcode.cardstore.R import de.pawcode.cardstore.data.enums.SortAttribute @@ -30,6 +40,7 @@ data class DropdownOption>( val value: TValue, ) +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun > SelectDropdownMenu( icon: ImageVector, @@ -41,25 +52,52 @@ fun > SelectDropdownMenu( ) { var dropdownExpanded by remember { mutableStateOf(initiallyExpanded) } - IconButton(onClick = { dropdownExpanded = !dropdownExpanded }) { - Icon(icon, contentDescription = title) - } - DropdownMenu(expanded = dropdownExpanded, onDismissRequest = { dropdownExpanded = false }) { - values.forEach { option -> - DropdownMenuItem( - text = { Text(text = option.title, maxLines = 1, overflow = TextOverflow.Ellipsis) }, - leadingIcon = { Icon(imageVector = option.icon, contentDescription = option.title) }, - trailingIcon = { - if (value == option.value) { - Icon(Icons.Filled.Check, contentDescription = null) - } - }, - onClick = { - onValueChange(option.value) - dropdownExpanded = false - }, + Box { + IconButton( + modifier = + Modifier.size( + IconButtonDefaults.smallContainerSize(IconButtonDefaults.IconButtonWidthOption.Wide) + ), + onClick = { dropdownExpanded = !dropdownExpanded }, + shapes = + IconButtonDefaults.shapes( + shape = IconButtonDefaults.smallRoundShape, + pressedShape = IconButtonDefaults.smallPressedShape, + ), + ) { + Icon( + icon, + contentDescription = title, + modifier = Modifier.size(IconButtonDefaults.smallIconSize), ) } + DropdownMenu( + expanded = dropdownExpanded, + onDismissRequest = { dropdownExpanded = false }, + offset = DpOffset(0.dp, 4.dp), + shape = MaterialTheme.shapes.medium, + containerColor = MaterialTheme.colorScheme.surfaceVariant, + ) { + values.forEach { option -> + DropdownMenuItem( + text = { + Text( + modifier = Modifier.padding(4.dp), + text = option.title, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + }, + leadingIcon = { Icon(imageVector = option.icon, contentDescription = option.title) }, + trailingIcon = { + AnimatedVisibility(visible = value === option.value) { + Icon(Icons.Filled.Check, contentDescription = null) + } + }, + onClick = { onValueChange(option.value) }, + ) + } + } } } diff --git a/app/src/main/java/de/pawcode/cardstore/ui/components/SettingsGroup.kt b/app/src/main/java/de/pawcode/cardstore/ui/components/SettingsGroup.kt index e2d04dd..dfe3cb0 100644 --- a/app/src/main/java/de/pawcode/cardstore/ui/components/SettingsGroup.kt +++ b/app/src/main/java/de/pawcode/cardstore/ui/components/SettingsGroup.kt @@ -24,11 +24,7 @@ fun SettingsGroup(modifier: Modifier = Modifier, title: String, content: @Compos modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), ) - Surface( - modifier = Modifier.fillMaxWidth(), - color = MaterialTheme.colorScheme.surface, - shape = MaterialTheme.shapes.extraLarge, - ) { + Surface(modifier = Modifier.fillMaxWidth(), shape = MaterialTheme.shapes.extraLarge) { Column(verticalArrangement = Arrangement.spacedBy(2.dp)) { content() } } } @@ -40,27 +36,24 @@ fun PreviewSettingsGroup() { SettingsGroup(title = "About") { SettingsItem( icon = Icons.Default.Web, - iconColor = MaterialTheme.colorScheme.primaryContainer, - iconBackground = MaterialTheme.colorScheme.onPrimaryContainer, + iconColor = MaterialTheme.colorScheme.onPrimaryFixedVariant, + iconBackground = MaterialTheme.colorScheme.primaryFixed, title = "pawcode Development", subtitle = "View website", onClick = {}, ) SettingsItem( icon = Icons.Default.Web, - iconColor = MaterialTheme.colorScheme.secondaryContainer, - iconBackground = MaterialTheme.colorScheme.onSecondaryContainer, + iconColor = MaterialTheme.colorScheme.onSecondaryFixedVariant, + iconBackground = MaterialTheme.colorScheme.secondaryFixed, title = "pawcode Development", - subtitle = "View website", - onClick = {}, ) SettingsItem( icon = Icons.Default.Web, - iconColor = MaterialTheme.colorScheme.tertiaryContainer, - iconBackground = MaterialTheme.colorScheme.onTertiaryContainer, + iconColor = MaterialTheme.colorScheme.onTertiaryFixedVariant, + iconBackground = MaterialTheme.colorScheme.tertiaryFixed, title = "pawcode Development", subtitle = "View website", - onClick = {}, ) } } diff --git a/app/src/main/java/de/pawcode/cardstore/ui/components/SettingsItem.kt b/app/src/main/java/de/pawcode/cardstore/ui/components/SettingsItem.kt index 819ac9b..974e634 100644 --- a/app/src/main/java/de/pawcode/cardstore/ui/components/SettingsItem.kt +++ b/app/src/main/java/de/pawcode/cardstore/ui/components/SettingsItem.kt @@ -4,14 +4,13 @@ import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Web import androidx.compose.material3.Icon +import androidx.compose.material3.ListItem import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -32,44 +31,31 @@ fun SettingsItem( subtitle: String? = null, onClick: (() -> Unit)? = null, ) { - Row( + ListItem( modifier = - Modifier.fillMaxWidth() - .background( - color = MaterialTheme.colorScheme.surfaceContainer, - shape = MaterialTheme.shapes.extraSmall, - ) - .then(if (onClick != null) Modifier.clickable { onClick() } else Modifier) - .padding(16.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - Box( - modifier = Modifier.size(40.dp).clip(CircleShape).background(iconBackground), - contentAlignment = Alignment.Center, - ) { - Icon( - imageVector = icon, - contentDescription = null, - tint = iconColor, - modifier = Modifier.size(20.dp), - ) - } - - Column(modifier = Modifier.weight(1f).padding(horizontal = 16.dp)) { - Text( - text = title, - style = MaterialTheme.typography.bodyLarge, - color = MaterialTheme.colorScheme.onSurface, - ) - subtitle?.let { - Text( - text = it, - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant, + Modifier.clip(MaterialTheme.shapes.extraSmall) + .then(if (onClick != null) Modifier.clickable { onClick() } else Modifier), + tonalElevation = 2.dp, + headlineContent = { Text(text = title) }, + supportingContent = { subtitle?.let { Text(text = it) } }, + leadingContent = { + Box( + modifier = + Modifier.padding(vertical = 8.dp) + .size(40.dp) + .clip(CircleShape) + .background(iconBackground), + contentAlignment = Alignment.Center, + ) { + Icon( + imageVector = icon, + contentDescription = null, + tint = iconColor, + modifier = Modifier.size(20.dp), ) } - } - } + }, + ) } @Preview(showBackground = true) @@ -78,22 +64,22 @@ fun PreviewSettingsItem() { Column { SettingsItem( icon = Icons.Default.Web, - iconColor = MaterialTheme.colorScheme.primaryFixed, - iconBackground = MaterialTheme.colorScheme.onPrimaryFixedVariant, + iconColor = MaterialTheme.colorScheme.onPrimaryFixedVariant, + iconBackground = MaterialTheme.colorScheme.primaryFixed, title = "pawcode Development", subtitle = "View website", onClick = {}, ) SettingsItem( icon = Icons.Default.Web, - iconColor = MaterialTheme.colorScheme.secondaryFixed, - iconBackground = MaterialTheme.colorScheme.onSecondaryFixedVariant, + iconColor = MaterialTheme.colorScheme.onSecondaryFixedVariant, + iconBackground = MaterialTheme.colorScheme.secondaryFixed, title = "pawcode Development", ) SettingsItem( icon = Icons.Default.Web, - iconColor = MaterialTheme.colorScheme.tertiaryFixed, - iconBackground = MaterialTheme.colorScheme.onTertiaryFixedVariant, + iconColor = MaterialTheme.colorScheme.onTertiaryFixedVariant, + iconBackground = MaterialTheme.colorScheme.tertiaryFixed, title = "pawcode Development", subtitle = "View website", ) diff --git a/app/src/main/java/de/pawcode/cardstore/ui/screens/AboutScreen.kt b/app/src/main/java/de/pawcode/cardstore/ui/screens/AboutScreen.kt index 40dc00d..0ea031c 100644 --- a/app/src/main/java/de/pawcode/cardstore/ui/screens/AboutScreen.kt +++ b/app/src/main/java/de/pawcode/cardstore/ui/screens/AboutScreen.kt @@ -2,6 +2,8 @@ package de.pawcode.cardstore.ui.screens import android.content.Intent import android.content.pm.PackageInfo +import androidx.compose.foundation.Image +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize @@ -14,7 +16,6 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Android import androidx.compose.material.icons.filled.BugReport import androidx.compose.material.icons.filled.CameraAlt -import androidx.compose.material.icons.filled.Code import androidx.compose.material.icons.filled.Colorize import androidx.compose.material.icons.filled.DataObject import androidx.compose.material.icons.filled.Gesture @@ -23,8 +24,6 @@ import androidx.compose.material.icons.filled.Palette import androidx.compose.material.icons.filled.QrCode import androidx.compose.material.icons.filled.Scanner import androidx.compose.material.icons.filled.Storage -import androidx.compose.material.icons.filled.Store -import androidx.compose.material.icons.filled.Web import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable @@ -32,7 +31,9 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.res.vectorResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.core.net.toUri @@ -119,8 +120,15 @@ fun AboutScreenComponent( val versionName = packageInfo.versionName ?: "Unknown version" val isDebug = packageInfo.packageName.endsWith(".debug") - Scaffold(topBar = { AppBar(title = stringResource(R.string.app_name), onBack = { onBack() }) }) { - innerPadding -> + Scaffold( + topBar = { + AppBar( + title = stringResource(R.string.app_name), + subtitle = stringResource(R.string.about), + onBack = { onBack() }, + ) + } + ) { innerPadding -> Column( modifier = Modifier.padding(innerPadding).fillMaxSize().verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally, @@ -128,13 +136,14 @@ fun AboutScreenComponent( Column( modifier = Modifier.widthIn(max = 500.dp).fillMaxWidth().padding(8.dp), verticalArrangement = Arrangement.spacedBy(24.dp), + horizontalAlignment = Alignment.CenterHorizontally, ) { // App Information Group SettingsGroup(title = stringResource(R.string.about)) { SettingsItem( icon = Icons.Filled.Info, - iconColor = MaterialTheme.colorScheme.primaryFixed, - iconBackground = MaterialTheme.colorScheme.onPrimaryFixedVariant, + iconColor = MaterialTheme.colorScheme.onSecondaryFixedVariant, + iconBackground = MaterialTheme.colorScheme.primaryFixed, title = stringResource(R.string.version) + if (isDebug) " (debug)" else "", subtitle = versionName + " (${packageInfo.longVersionCode})", onClick = { @@ -148,27 +157,27 @@ fun AboutScreenComponent( // Links Group SettingsGroup(title = stringResource(R.string.links)) { SettingsItem( - icon = Icons.Filled.Web, - iconColor = MaterialTheme.colorScheme.secondaryFixed, - iconBackground = MaterialTheme.colorScheme.onSecondaryFixedVariant, + icon = ImageVector.vectorResource(R.drawable.icon), + iconColor = MaterialTheme.colorScheme.onSecondaryFixedVariant, + iconBackground = MaterialTheme.colorScheme.secondaryFixed, title = "pawcode Development", subtitle = stringResource(R.string.website), onClick = { onOpenWebsite(context.getString(R.string.website_link)) }, ) SettingsItem( - icon = Icons.Filled.Code, - iconColor = MaterialTheme.colorScheme.secondaryFixed, - iconBackground = MaterialTheme.colorScheme.onSecondaryFixedVariant, + icon = ImageVector.vectorResource(R.drawable.github_mark), + iconColor = MaterialTheme.colorScheme.onSecondaryFixedVariant, + iconBackground = MaterialTheme.colorScheme.secondaryFixed, title = stringResource(R.string.source_code), subtitle = stringResource(R.string.github_repository), onClick = { onOpenWebsite("https://github.com/pawcoding/card-store") }, ) SettingsItem( - icon = Icons.Filled.Store, - iconColor = MaterialTheme.colorScheme.secondaryFixed, - iconBackground = MaterialTheme.colorScheme.onSecondaryFixedVariant, + icon = ImageVector.vectorResource(R.drawable.google_play), + iconColor = MaterialTheme.colorScheme.onSecondaryFixedVariant, + iconBackground = MaterialTheme.colorScheme.secondaryFixed, title = stringResource(R.string.playstore), subtitle = stringResource(R.string.playstore_description), onClick = { @@ -178,8 +187,8 @@ fun AboutScreenComponent( SettingsItem( icon = Icons.Filled.BugReport, - iconColor = MaterialTheme.colorScheme.secondaryFixed, - iconBackground = MaterialTheme.colorScheme.onSecondaryFixedVariant, + iconColor = MaterialTheme.colorScheme.onSecondaryFixedVariant, + iconBackground = MaterialTheme.colorScheme.secondaryFixed, title = stringResource(R.string.report_issue), subtitle = stringResource(R.string.github_issues), onClick = { onOpenWebsite("https://github.com/pawcoding/card-store/issues") }, @@ -191,21 +200,29 @@ fun AboutScreenComponent( TECHNOLOGIES.forEach { technology -> SettingsItem( icon = technology.icon, - iconColor = MaterialTheme.colorScheme.tertiaryFixed, - iconBackground = MaterialTheme.colorScheme.onTertiaryFixedVariant, + iconColor = MaterialTheme.colorScheme.onTertiaryFixedVariant, + iconBackground = MaterialTheme.colorScheme.tertiaryFixed, title = technology.name, subtitle = null, onClick = { onOpenWebsite(technology.url) }, ) } } + + Image( + painter = + if (isSystemInDarkTheme()) painterResource(R.drawable.pawcode_light) + else painterResource(R.drawable.pawcode_dark), + contentDescription = "pawcode Development", + modifier = Modifier.padding(top = 24.dp).padding(12.dp).fillMaxWidth(.5f), + ) } } } } -@Preview -@Preview(device = "id:pixel_tablet") +@Preview(showSystemUi = true) +@Preview(device = "id:pixel_tablet", showSystemUi = true) @Composable fun PreviewAboutScreenComponent() { val packageInfo = PackageInfo() diff --git a/app/src/main/java/de/pawcode/cardstore/ui/screens/CardListScreen.kt b/app/src/main/java/de/pawcode/cardstore/ui/screens/CardListScreen.kt index 864e3f7..4c541e7 100644 --- a/app/src/main/java/de/pawcode/cardstore/ui/screens/CardListScreen.kt +++ b/app/src/main/java/de/pawcode/cardstore/ui/screens/CardListScreen.kt @@ -1,10 +1,13 @@ package de.pawcode.cardstore.ui.screens +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.lazy.grid.rememberLazyGridState @@ -13,6 +16,7 @@ import androidx.compose.material.icons.automirrored.filled.Sort import androidx.compose.material.icons.automirrored.filled.TrendingUp import androidx.compose.material.icons.filled.AddCard import androidx.compose.material.icons.filled.AutoFixHigh +import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.DeleteForever import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.History @@ -23,9 +27,14 @@ import androidx.compose.material.icons.outlined.Info import androidx.compose.material.icons.outlined.QrCodeScanner import androidx.compose.material.icons.twotone.CreditCard import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExtendedFloatingActionButton +import androidx.compose.material3.FloatingActionButtonMenu +import androidx.compose.material3.FloatingActionButtonMenuItem import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.IconButtonDefaults +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Scaffold import androidx.compose.material3.Text @@ -150,7 +159,7 @@ fun CardListScreen(navController: NavController, viewModel: CardViewModel = view ) } -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun CardListScreenComponent( cardsFlow: Flow>, @@ -183,7 +192,6 @@ fun CardListScreenComponent( val cardShareSheetState = rememberModalBottomSheetState() val cardImportSheetState = rememberModalBottomSheetState() val cardOptionSheetState = rememberModalBottomSheetState() - val cardCreateSheetState = rememberModalBottomSheetState() var selectedLabel by remember { mutableStateOf(null) } @@ -216,49 +224,114 @@ fun CardListScreenComponent( AppBar( title = stringResource(R.string.app_name), actions = { - IconButton(onClick = { onShowAbout() }) { - Icon(Icons.Outlined.Info, contentDescription = stringResource(R.string.about)) - } - SelectDropdownMenu( - icon = Icons.AutoMirrored.Filled.Sort, - title = stringResource(R.string.cards_sort), - value = sortBy, - values = - listOf( - DropdownOption( - title = stringResource(R.string.sort_intelligent), - icon = Icons.Filled.AutoFixHigh, - value = SortAttribute.INTELLIGENT, - ), - DropdownOption( - title = stringResource(R.string.sort_alphabetically), - icon = Icons.Filled.SortByAlpha, - value = SortAttribute.ALPHABETICALLY, + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + IconButton( + modifier = + Modifier.size( + IconButtonDefaults.smallContainerSize( + IconButtonDefaults.IconButtonWidthOption.Wide + ) ), - DropdownOption( - title = stringResource(R.string.sort_most_used), - icon = Icons.AutoMirrored.Filled.TrendingUp, - value = SortAttribute.MOST_USED, + onClick = { onShowAbout() }, + shapes = + IconButtonDefaults.shapes( + shape = IconButtonDefaults.smallRoundShape, + pressedShape = IconButtonDefaults.smallPressedShape, ), - DropdownOption( - title = stringResource(R.string.sort_recently_used), - icon = Icons.Filled.History, - value = SortAttribute.RECENTLY_USED, + ) { + Icon( + Icons.Outlined.Info, + contentDescription = stringResource(R.string.about), + modifier = Modifier.size(IconButtonDefaults.smallIconSize), + ) + } + + SelectDropdownMenu( + icon = Icons.AutoMirrored.Filled.Sort, + title = stringResource(R.string.cards_sort), + value = sortBy, + values = + listOf( + DropdownOption( + title = stringResource(R.string.sort_intelligent), + icon = Icons.Filled.AutoFixHigh, + value = SortAttribute.INTELLIGENT, + ), + DropdownOption( + title = stringResource(R.string.sort_alphabetically), + icon = Icons.Filled.SortByAlpha, + value = SortAttribute.ALPHABETICALLY, + ), + DropdownOption( + title = stringResource(R.string.sort_most_used), + icon = Icons.AutoMirrored.Filled.TrendingUp, + value = SortAttribute.MOST_USED, + ), + DropdownOption( + title = stringResource(R.string.sort_recently_used), + icon = Icons.Filled.History, + value = SortAttribute.RECENTLY_USED, + ), ), - ), - onValueChange = { onSortChange(it) }, - ) + onValueChange = { onSortChange(it) }, + ) + } }, ) }, floatingActionButton = { - ExtendedFloatingActionButton( - onClick = { showCardCreateSheet = true }, - text = { Text(stringResource(R.string.cards_new)) }, - icon = { - Icon(Icons.Filled.AddCard, contentDescription = stringResource(R.string.cards_new)) + FloatingActionButtonMenu( + expanded = showCardCreateSheet, + button = { + ExtendedFloatingActionButton( + onClick = { showCardCreateSheet = !showCardCreateSheet }, + text = { Text(stringResource(R.string.cards_new)) }, + expanded = !showCardCreateSheet, + icon = { + Icon( + imageVector = + if (!showCardCreateSheet) { + Icons.Filled.AddCard + } else { + Icons.Filled.Close + }, + contentDescription = stringResource(R.string.cards_new), + ) + }, + ) }, - ) + ) { + FloatingActionButtonMenuItem( + onClick = { + showBarcodeScanner = true + showCardCreateSheet = false + }, + text = { Text(stringResource(R.string.scan_barcode)) }, + icon = { Icon(Icons.Outlined.QrCodeScanner, contentDescription = null) }, + containerColor = MaterialTheme.colorScheme.primary, + contentColor = MaterialTheme.colorScheme.onPrimary, + ) + FloatingActionButtonMenuItem( + onClick = { + showPkpassPicker = true + showCardCreateSheet = false + }, + text = { Text(stringResource(R.string.card_create_pkpass)) }, + icon = { Icon(Icons.Outlined.FileOpen, contentDescription = null) }, + containerColor = MaterialTheme.colorScheme.primary, + contentColor = MaterialTheme.colorScheme.onPrimary, + ) + FloatingActionButtonMenuItem( + onClick = { + onCreateCard(null, null) + showCardCreateSheet = false + }, + text = { Text(stringResource(R.string.card_create_manual)) }, + icon = { Icon(Icons.Filled.Edit, contentDescription = null) }, + containerColor = MaterialTheme.colorScheme.primary, + contentColor = MaterialTheme.colorScheme.onPrimary, + ) + } }, ) { innerPadding -> Column(modifier = Modifier.padding(innerPadding).padding(horizontal = 8.dp)) { @@ -369,41 +442,6 @@ fun CardListScreenComponent( } } - if (showCardCreateSheet) { - ModalBottomSheet( - sheetState = cardCreateSheetState, - dragHandle = {}, - onDismissRequest = { showCardCreateSheet = false }, - ) { - OptionSheet( - Option( - label = stringResource(R.string.scan_barcode), - icon = Icons.Outlined.QrCodeScanner, - onClick = { - showBarcodeScanner = true - showCardCreateSheet = false - }, - ), - Option( - label = stringResource(R.string.card_create_pkpass), - icon = Icons.Outlined.FileOpen, - onClick = { - showPkpassPicker = true - showCardCreateSheet = false - }, - ), - Option( - label = stringResource(R.string.card_create_manual), - icon = Icons.Filled.Edit, - onClick = { - onCreateCard(null, null) - showCardCreateSheet = false - }, - ), - ) - } - } - openDeleteDialog?.let { ConfirmDialog( onDismissRequest = { openDeleteDialog = null }, @@ -447,8 +485,8 @@ fun CardListScreenComponent( } } -@Preview -@Preview(device = "id:pixel_tablet") +@Preview(showSystemUi = true) +@Preview(device = "id:pixel_tablet", showSystemUi = true) @Composable fun PreviewCardListScreenComponent() { CardListScreenComponent( @@ -466,8 +504,8 @@ fun PreviewCardListScreenComponent() { ) } -@Preview -@Preview(device = "id:pixel_tablet") +@Preview(showSystemUi = true) +@Preview(device = "id:pixel_tablet", showSystemUi = true) @Composable fun PreviewCardListScreenComponentEmpty() { CardListScreenComponent( diff --git a/app/src/main/java/de/pawcode/cardstore/ui/screens/EditCardScreen.kt b/app/src/main/java/de/pawcode/cardstore/ui/screens/EditCardScreen.kt index b74ced8..631c36a 100644 --- a/app/src/main/java/de/pawcode/cardstore/ui/screens/EditCardScreen.kt +++ b/app/src/main/java/de/pawcode/cardstore/ui/screens/EditCardScreen.kt @@ -153,6 +153,7 @@ fun EditCardScreenComponent( topBar = { AppBar( title = stringResource(if (!isCreateCard) R.string.card_edit else R.string.card_add), + subtitle = if (!isCreateCard) initialCard.card.storeName else null, onBack = { handleBack() }, ) }, @@ -179,8 +180,8 @@ fun EditCardScreenComponent( } } -@Preview -@Preview(device = "id:pixel_tablet") +@Preview(showSystemUi = true) +@Preview(device = "id:pixel_tablet", showSystemUi = true) @Composable fun PreviewEditCardScreenComponent() { EditCardScreenComponent( @@ -192,8 +193,8 @@ fun PreviewEditCardScreenComponent() { ) } -@Preview -@Preview(device = "id:pixel_tablet") +@Preview(showSystemUi = true) +@Preview(device = "id:pixel_tablet", showSystemUi = true) @Composable fun PreviewEditCardScreenComponentEmpty() { EditCardScreenComponent( diff --git a/app/src/main/java/de/pawcode/cardstore/ui/screens/EditLabelScreen.kt b/app/src/main/java/de/pawcode/cardstore/ui/screens/EditLabelScreen.kt index 1c32805..5d95e96 100644 --- a/app/src/main/java/de/pawcode/cardstore/ui/screens/EditLabelScreen.kt +++ b/app/src/main/java/de/pawcode/cardstore/ui/screens/EditLabelScreen.kt @@ -130,6 +130,7 @@ fun EditLabelScreenComponent( topBar = { AppBar( title = stringResource(if (!isCreateLabel) R.string.label_edit else R.string.label_add), + subtitle = initialLabel.name, onBack = { handleBack() }, ) }, @@ -187,8 +188,8 @@ fun EditLabelScreenComponent( } } -@Preview -@Preview(device = "id:pixel_tablet") +@Preview(showSystemUi = true) +@Preview(device = "id:pixel_tablet", showSystemUi = true) @Composable fun PreviewEditLabelScreenComponent() { EditLabelScreenComponent( @@ -199,8 +200,8 @@ fun PreviewEditLabelScreenComponent() { ) } -@Preview -@Preview(device = "id:pixel_tablet") +@Preview(showSystemUi = true) +@Preview(device = "id:pixel_tablet", showSystemUi = true) @Composable fun PreviewEditLabelScreenComponentEmpty() { EditLabelScreenComponent( diff --git a/app/src/main/java/de/pawcode/cardstore/ui/theme/Theme.kt b/app/src/main/java/de/pawcode/cardstore/ui/theme/Theme.kt index b55aeb8..ea128a5 100644 --- a/app/src/main/java/de/pawcode/cardstore/ui/theme/Theme.kt +++ b/app/src/main/java/de/pawcode/cardstore/ui/theme/Theme.kt @@ -1,20 +1,17 @@ package de.pawcode.cardstore.ui.theme import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.MaterialExpressiveTheme +import androidx.compose.material3.MotionScheme import androidx.compose.material3.darkColorScheme import androidx.compose.material3.dynamicDarkColorScheme import androidx.compose.material3.dynamicLightColorScheme -import androidx.compose.material3.lightColorScheme +import androidx.compose.material3.expressiveLightColorScheme import androidx.compose.runtime.Composable import androidx.compose.ui.platform.LocalContext -private val DarkColorScheme = - darkColorScheme(primary = Purple80, secondary = PurpleGrey80, tertiary = Pink80) - -private val LightColorScheme = - lightColorScheme(primary = Purple40, secondary = PurpleGrey40, tertiary = Pink40) - +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun CardStoreTheme( darkTheme: Boolean = isSystemInDarkTheme(), @@ -28,9 +25,14 @@ fun CardStoreTheme( if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) } - darkTheme -> DarkColorScheme - else -> LightColorScheme + darkTheme -> darkColorScheme() + else -> expressiveLightColorScheme() } - MaterialTheme(colorScheme = colorScheme, typography = Typography, content = content) + MaterialExpressiveTheme( + colorScheme = colorScheme, + typography = Typography, + motionScheme = MotionScheme.expressive(), + content = content, + ) } diff --git a/app/src/main/res/drawable/github_mark.xml b/app/src/main/res/drawable/github_mark.xml new file mode 100644 index 0000000..34241ea --- /dev/null +++ b/app/src/main/res/drawable/github_mark.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/google_play.xml b/app/src/main/res/drawable/google_play.xml new file mode 100644 index 0000000..0ae23c0 --- /dev/null +++ b/app/src/main/res/drawable/google_play.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/drawable/icon.xml b/app/src/main/res/drawable/icon.xml new file mode 100644 index 0000000..26920eb --- /dev/null +++ b/app/src/main/res/drawable/icon.xml @@ -0,0 +1,21 @@ + + + + + + + + + + diff --git a/app/src/main/res/drawable/pawcode_dark.xml b/app/src/main/res/drawable/pawcode_dark.xml new file mode 100644 index 0000000..1e99efc --- /dev/null +++ b/app/src/main/res/drawable/pawcode_dark.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/pawcode_light.xml b/app/src/main/res/drawable/pawcode_light.xml index e0a65dc..680ae15 100644 --- a/app/src/main/res/drawable/pawcode_light.xml +++ b/app/src/main/res/drawable/pawcode_light.xml @@ -1,39 +1,27 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4046569..8dce5ff 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,6 +14,7 @@ junitVersion = "1.3.0" kotlin = "2.2.20" kotlinxSerializationJson = "1.9.0" lifecycleRuntimeKtx = "2.9.4" +material3 = "1.5.0-alpha04" materialIconsExtended = "1.7.8" navigationCompose = "2.9.5" playServicesCodeScanner = "16.1.0" @@ -31,7 +32,7 @@ androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-co androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } androidx-material-icons-extended = { group = "androidx.compose.material", name = "material-icons-extended", version.ref = "materialIconsExtended" } -androidx-material3 = { group = "androidx.compose.material3", name = "material3" } +androidx-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" } androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" } androidx-room-common = { group = "androidx.room", name = "room-common", version.ref = "room" } androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }