Compare commits
1 Commits
f50c0c08a5
...
glassmorph
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d0bf4cb1c |
@@ -130,6 +130,7 @@ dependencies {
|
|||||||
implementation(libs.androidx.room.runtime) // ADDED: Explicitly add runtime
|
implementation(libs.androidx.room.runtime) // ADDED: Explicitly add runtime
|
||||||
implementation(libs.androidx.room.ktx)
|
implementation(libs.androidx.room.ktx)
|
||||||
implementation(libs.core.ktx)
|
implementation(libs.core.ktx)
|
||||||
|
implementation(libs.androidx.compose.foundation.layout)
|
||||||
ksp(libs.room.compiler) // CHANGED: Use ksp instead of implementation
|
ksp(libs.room.compiler) // CHANGED: Use ksp instead of implementation
|
||||||
|
|
||||||
// Networking
|
// Networking
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.rotate
|
import androidx.compose.ui.draw.rotate
|
||||||
import androidx.compose.ui.draw.shadow
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.painter.Painter
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@@ -159,14 +159,14 @@ private fun MenuItem(
|
|||||||
) {
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.shadow(elevation = 8.dp, shape = ComponentDefaults.DefaultShape)
|
.glassmorphic(shape = RoundedCornerShape(16.dp), alpha = 0.4f)
|
||||||
.clickable(
|
.clickable(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
indication = null
|
indication = null
|
||||||
),
|
),
|
||||||
shape = RoundedCornerShape(16.dp),
|
shape = RoundedCornerShape(16.dp),
|
||||||
color = MaterialTheme.colorScheme.surfaceContainer
|
color = Color.Transparent // Allow glassmorphic modifier to handle color
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp),
|
modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||||
@@ -196,16 +196,4 @@ private fun MenuItem(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Preview
|
|
||||||
@Composable
|
|
||||||
fun MenuItemPreview() {
|
|
||||||
@Suppress("HardCodedStringLiteral")
|
|
||||||
MenuItem(
|
|
||||||
text = "Menu Item",
|
|
||||||
imageVector = AppIcons.Add,
|
|
||||||
painter = null,
|
|
||||||
onClick = {}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
@@ -69,10 +69,8 @@ fun <T : TabItem> AppTabLayout(
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 8.dp, horizontal = 8.dp)
|
.padding(vertical = 8.dp, horizontal = 8.dp)
|
||||||
.height(56.dp)
|
.height(56.dp)
|
||||||
.background(
|
// Replace background with glassmorphic extension
|
||||||
color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f),
|
.glassmorphic(shape = ComponentDefaults.CardShape, alpha = 0.3f)
|
||||||
shape = ComponentDefaults.CardShape
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
val tabWidth = maxWidth / tabs.size
|
val tabWidth = maxWidth / tabs.size
|
||||||
|
|
||||||
@@ -89,7 +87,7 @@ fun <T : TabItem> AppTabLayout(
|
|||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
.padding(4.dp)
|
.padding(4.dp)
|
||||||
.background(
|
.background(
|
||||||
color = MaterialTheme.colorScheme.primary,
|
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.7f), // Glassy indicator
|
||||||
shape = RoundedCornerShape(12.dp)
|
shape = RoundedCornerShape(12.dp)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.RectangleShape
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@@ -41,16 +43,23 @@ fun AppTopAppBar(
|
|||||||
onNavigateBack: (() -> Unit)? = null,
|
onNavigateBack: (() -> Unit)? = null,
|
||||||
navigationIcon: @Composable (() -> Unit)? = null,
|
navigationIcon: @Composable (() -> Unit)? = null,
|
||||||
actions: @Composable RowScope.() -> Unit = {},
|
actions: @Composable RowScope.() -> Unit = {},
|
||||||
colors: TopAppBarColors = TopAppBarDefaults.topAppBarColors(),
|
colors: TopAppBarColors = TopAppBarDefaults.topAppBarColors(
|
||||||
|
containerColor = Color.Transparent,
|
||||||
|
scrolledContainerColor = Color.Transparent
|
||||||
|
),
|
||||||
hintContent: Hint? = null
|
hintContent: Hint? = null
|
||||||
) {
|
) {
|
||||||
val sheetState = rememberModalBottomSheetState()
|
val sheetState = rememberModalBottomSheetState()
|
||||||
var showBottomSheet by remember { mutableStateOf(false) }
|
var showBottomSheet by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
TopAppBar(
|
Surface(
|
||||||
modifier = modifier.height(56.dp),
|
modifier = modifier.glassmorphic(shape = RectangleShape, alpha = 0.2f),
|
||||||
windowInsets = WindowInsets(0.dp),
|
color = Color.Transparent
|
||||||
colors = colors,
|
) {
|
||||||
|
TopAppBar(
|
||||||
|
modifier = Modifier.height(56.dp),
|
||||||
|
windowInsets = WindowInsets(0.dp),
|
||||||
|
colors = colors,
|
||||||
title = {
|
title = {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxHeight(),
|
modifier = Modifier.fillMaxHeight(),
|
||||||
@@ -102,8 +111,9 @@ fun AppTopAppBar(
|
|||||||
// No navigation icon
|
// No navigation icon
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions = actions
|
actions = actions
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (showBottomSheet) {
|
if (showBottomSheet) {
|
||||||
HintBottomSheet(
|
HintBottomSheet(
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import androidx.compose.foundation.layout.WindowInsets
|
|||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.navigationBars
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.NavigationBar
|
import androidx.compose.material3.NavigationBar
|
||||||
@@ -28,6 +29,7 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.scale
|
import androidx.compose.ui.draw.scale
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
@@ -100,24 +102,25 @@ fun BottomNavigationBar(
|
|||||||
targetOffsetY = { it }
|
targetOffsetY = { it }
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val baseHeight = if (showLabels) 80.dp else 56.dp
|
val baseHeight = if (showLabels) 80.dp else 56.dp
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
val navBarDp = with(density) { WindowInsets.navigationBars.getBottom(this).toDp() }
|
val navBarDp = with(density) { WindowInsets.navigationBars.getBottom(this).toDp() }
|
||||||
val height = baseHeight + navBarDp
|
val height = baseHeight + navBarDp
|
||||||
|
|
||||||
NavigationBar(
|
NavigationBar(
|
||||||
modifier = modifier.height(height),
|
modifier = modifier
|
||||||
containerColor = MaterialTheme.colorScheme.surface, // Cleaner look than surfaceVariant
|
.height(height)
|
||||||
tonalElevation = 8.dp, // Slight elevation for depth
|
// Apply glassmorphism on the top corners
|
||||||
|
.glassmorphic(shape = RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp), alpha = 0.35f),
|
||||||
|
containerColor = Color.Transparent, // Let the glass shine through
|
||||||
|
tonalElevation = 0.dp,
|
||||||
) {
|
) {
|
||||||
screens.forEach { screen ->
|
screens.forEach { screen ->
|
||||||
val isSelected = screen == selectedItem
|
val isSelected = screen == selectedItem
|
||||||
val title = stringResource(id = screen.title)
|
val title = stringResource(id = screen.title)
|
||||||
|
|
||||||
// 1. Spring Animation for the Icon Scale
|
|
||||||
val scale by animateFloatAsState(
|
val scale by animateFloatAsState(
|
||||||
targetValue = if (isSelected) 1.2f else 1.0f, // Subtle pop effect
|
targetValue = if (isSelected) 1.2f else 1.0f,
|
||||||
animationSpec = spring(
|
animationSpec = spring(
|
||||||
dampingRatio = Spring.DampingRatioMediumBouncy,
|
dampingRatio = Spring.DampingRatioMediumBouncy,
|
||||||
stiffness = Spring.StiffnessLow
|
stiffness = Spring.StiffnessLow
|
||||||
@@ -129,7 +132,7 @@ fun BottomNavigationBar(
|
|||||||
selected = isSelected,
|
selected = isSelected,
|
||||||
onClick = {
|
onClick = {
|
||||||
if (!isSelected) {
|
if (!isSelected) {
|
||||||
haptic.performHapticFeedback(HapticFeedbackType.LongPress) // 2. Tactile feedback
|
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
onItemSelected(screen)
|
onItemSelected(screen)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -145,17 +148,16 @@ fun BottomNavigationBar(
|
|||||||
}
|
}
|
||||||
} else null,
|
} else null,
|
||||||
icon = {
|
icon = {
|
||||||
// 3. Crossfade between Outlined and Filled icons
|
|
||||||
Crossfade(targetState = isSelected, label = "iconFade") { selected ->
|
Crossfade(targetState = isSelected, label = "iconFade") { selected ->
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = if (selected) screen.selectedIcon else screen.unselectedIcon,
|
imageVector = if (selected) screen.selectedIcon else screen.unselectedIcon,
|
||||||
contentDescription = title,
|
contentDescription = title,
|
||||||
modifier = Modifier.scale(scale) // Apply the spring scale
|
modifier = Modifier.scale(scale)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
colors = NavigationBarItemDefaults.colors(
|
colors = NavigationBarItemDefaults.colors(
|
||||||
indicatorColor = MaterialTheme.colorScheme.primaryContainer,
|
indicatorColor = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.5f), // Glassy indicator
|
||||||
selectedIconColor = MaterialTheme.colorScheme.onPrimaryContainer,
|
selectedIconColor = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||||
selectedTextColor = MaterialTheme.colorScheme.primary,
|
selectedTextColor = MaterialTheme.colorScheme.primary,
|
||||||
unselectedIconColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
unselectedIconColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ package eu.gaudian.translator.view.composable
|
|||||||
import androidx.compose.animation.animateContentSize
|
import androidx.compose.animation.animateContentSize
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.foundation.BorderStroke
|
import androidx.compose.foundation.BorderStroke
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
@@ -43,6 +45,7 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.composed
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.draw.rotate
|
import androidx.compose.ui.draw.rotate
|
||||||
import androidx.compose.ui.draw.shadow
|
import androidx.compose.ui.draw.shadow
|
||||||
@@ -55,49 +58,51 @@ import androidx.compose.ui.unit.dp
|
|||||||
import eu.gaudian.translator.R
|
import eu.gaudian.translator.R
|
||||||
import eu.gaudian.translator.ui.theme.ThemePreviews
|
import eu.gaudian.translator.ui.theme.ThemePreviews
|
||||||
import eu.gaudian.translator.ui.theme.semanticColors
|
import eu.gaudian.translator.ui.theme.semanticColors
|
||||||
import eu.gaudian.translator.view.composable.ComponentDefaults.DefaultElevation
|
|
||||||
|
|
||||||
|
|
||||||
object ComponentDefaults {
|
object ComponentDefaults {
|
||||||
// Sizing
|
|
||||||
val DefaultButtonHeight = 48.dp
|
val DefaultButtonHeight = 48.dp
|
||||||
val CardPadding = 8.dp
|
val CardPadding = 8.dp
|
||||||
|
|
||||||
// Elevation
|
|
||||||
val DefaultElevation = 0.dp
|
val DefaultElevation = 0.dp
|
||||||
val NoElevation = 0.dp
|
val NoElevation = 0.dp
|
||||||
|
|
||||||
// Borders
|
|
||||||
val DefaultBorderWidth = 1.dp
|
val DefaultBorderWidth = 1.dp
|
||||||
|
|
||||||
// Shapes
|
|
||||||
val DefaultCornerRadius = 16.dp
|
val DefaultCornerRadius = 16.dp
|
||||||
val CardClipRadius = 8.dp
|
val CardClipRadius = 16.dp // Increased slightly for softer glass look
|
||||||
val NoRounding = 0.dp
|
val NoRounding = 0.dp
|
||||||
val DefaultShape = RoundedCornerShape(DefaultCornerRadius)
|
val DefaultShape = RoundedCornerShape(DefaultCornerRadius)
|
||||||
val CardClipShape = RoundedCornerShape(CardClipRadius)
|
val CardClipShape = RoundedCornerShape(CardClipRadius)
|
||||||
val CardShape = RoundedCornerShape(DefaultCornerRadius)
|
val CardShape = RoundedCornerShape(DefaultCornerRadius)
|
||||||
val NoShape = RoundedCornerShape(NoRounding)
|
val NoShape = RoundedCornerShape(NoRounding)
|
||||||
|
|
||||||
// Opacity Levels
|
|
||||||
const val ALPHA_HIGH = 0.6f
|
const val ALPHA_HIGH = 0.6f
|
||||||
const val ALPHA_MEDIUM = 0.5f
|
const val ALPHA_MEDIUM = 0.4f
|
||||||
const val ALPHA_LOW = 0.3f
|
const val ALPHA_LOW = 0.2f // Adjusted for glass
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A styled card container for displaying content with a consistent floating look.
|
* Standard Glassmorphism Modifier
|
||||||
*
|
|
||||||
* @param modifier The modifier to be applied to the card.
|
|
||||||
* @param content The content to be displayed inside the card.
|
|
||||||
*/
|
*/
|
||||||
|
fun Modifier.glassmorphic(
|
||||||
|
shape: Shape = ComponentDefaults.DefaultShape,
|
||||||
|
alpha: Float = ComponentDefaults.ALPHA_LOW,
|
||||||
|
borderAlpha: Float = 0.15f
|
||||||
|
): Modifier = composed {
|
||||||
|
this
|
||||||
|
.shadow(elevation = 8.dp, shape = shape, spotColor = Color.Black.copy(alpha = 0.05f))
|
||||||
|
.clip(shape)
|
||||||
|
.background(MaterialTheme.colorScheme.surface.copy(alpha = alpha))
|
||||||
|
.border(
|
||||||
|
width = 1.dp,
|
||||||
|
color = MaterialTheme.colorScheme.onSurface.copy(alpha = borderAlpha),
|
||||||
|
shape = shape
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AppCard(
|
fun AppCard(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
title: String? = null,
|
title: String? = null,
|
||||||
icon: ImageVector? = null, // New optional icon parameter
|
icon: ImageVector? = null,
|
||||||
text: String? = null,
|
text: String? = null,
|
||||||
expandable: Boolean = false,
|
expandable: Boolean = false,
|
||||||
initiallyExpanded: Boolean = false,
|
initiallyExpanded: Boolean = false,
|
||||||
@@ -110,25 +115,17 @@ fun AppCard(
|
|||||||
label = "Chevron Rotation"
|
label = "Chevron Rotation"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Check if we need to render the header row
|
|
||||||
// Updated to include icon in the check
|
|
||||||
val hasHeader = title != null || text != null || expandable || icon != null
|
val hasHeader = title != null || text != null || expandable || icon != null
|
||||||
|
|
||||||
Surface(
|
Surface(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.shadow(
|
.glassmorphic(shape = ComponentDefaults.CardShape, alpha = 0.25f)
|
||||||
DefaultElevation,
|
|
||||||
shape = ComponentDefaults.CardShape
|
|
||||||
)
|
|
||||||
.clip(ComponentDefaults.CardClipShape)
|
|
||||||
// Animate height changes when expanding/collapsing
|
|
||||||
.animateContentSize(),
|
.animateContentSize(),
|
||||||
shape = ComponentDefaults.CardShape,
|
shape = ComponentDefaults.CardShape,
|
||||||
color = MaterialTheme.colorScheme.surfaceContainer
|
color = Color.Transparent // Let glassmorphic handle the background
|
||||||
) {
|
) {
|
||||||
Column {
|
Column {
|
||||||
// --- Header Row ---
|
|
||||||
if (hasHeader) {
|
if (hasHeader) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -137,7 +134,6 @@ fun AppCard(
|
|||||||
.padding(ComponentDefaults.CardPadding),
|
.padding(ComponentDefaults.CardPadding),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
// 1. Optional Icon on the left
|
|
||||||
if (icon != null) {
|
if (icon != null) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = icon,
|
imageVector = icon,
|
||||||
@@ -148,7 +144,6 @@ fun AppCard(
|
|||||||
Spacer(modifier = Modifier.width(16.dp))
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Title and Text Column
|
|
||||||
Column(modifier = Modifier.weight(1f)) {
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
if (!title.isNullOrBlank()) {
|
if (!title.isNullOrBlank()) {
|
||||||
Text(
|
Text(
|
||||||
@@ -157,12 +152,9 @@ fun AppCard(
|
|||||||
color = MaterialTheme.colorScheme.onSurface
|
color = MaterialTheme.colorScheme.onSurface
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only show spacer if both title and text exist
|
|
||||||
if (!title.isNullOrBlank() && !text.isNullOrBlank()) {
|
if (!title.isNullOrBlank() && !text.isNullOrBlank()) {
|
||||||
Spacer(Modifier.size(4.dp))
|
Spacer(Modifier.size(4.dp))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!text.isNullOrBlank()) {
|
if (!text.isNullOrBlank()) {
|
||||||
Text(
|
Text(
|
||||||
text = text,
|
text = text,
|
||||||
@@ -172,7 +164,6 @@ fun AppCard(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Expand Chevron (Far right)
|
|
||||||
if (expandable) {
|
if (expandable) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = AppIcons.ArrowDropDown,
|
imageVector = AppIcons.ArrowDropDown,
|
||||||
@@ -184,15 +175,12 @@ fun AppCard(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Content Area ---
|
|
||||||
if (!expandable || isExpanded) {
|
if (!expandable || isExpanded) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(
|
modifier = Modifier.padding(
|
||||||
start = ComponentDefaults.CardPadding,
|
start = ComponentDefaults.CardPadding,
|
||||||
end = ComponentDefaults.CardPadding,
|
end = ComponentDefaults.CardPadding,
|
||||||
bottom = ComponentDefaults.CardPadding,
|
bottom = ComponentDefaults.CardPadding,
|
||||||
// If we have a header, remove the top padding so content sits closer to the title.
|
|
||||||
// If no header (legacy behavior), keep the top padding.
|
|
||||||
top = if (hasHeader) 0.dp else ComponentDefaults.CardPadding
|
top = if (hasHeader) 0.dp else ComponentDefaults.CardPadding
|
||||||
),
|
),
|
||||||
content = content
|
content = content
|
||||||
@@ -304,31 +292,27 @@ fun AppButton(
|
|||||||
modifier: Modifier? = Modifier,
|
modifier: Modifier? = Modifier,
|
||||||
enabled: Boolean = true,
|
enabled: Boolean = true,
|
||||||
shape: Shape? = null,
|
shape: Shape? = null,
|
||||||
colors: ButtonColors = ButtonDefaults.buttonColors(),
|
colors: ButtonColors = ButtonDefaults.buttonColors(
|
||||||
elevation: ButtonElevation? = ButtonDefaults.buttonElevation(),
|
containerColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.8f) // Glassy primary
|
||||||
|
),
|
||||||
|
elevation: ButtonElevation? = ButtonDefaults.buttonElevation(defaultElevation = 0.dp),
|
||||||
border: BorderStroke? = null,
|
border: BorderStroke? = null,
|
||||||
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
|
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
|
||||||
interactionSource: MutableInteractionSource? = null,
|
interactionSource: MutableInteractionSource? = null,
|
||||||
content: @Composable RowScope.() -> Unit
|
content: @Composable RowScope.() -> Unit
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val m = modifier ?: Modifier.height(ComponentDefaults.DefaultButtonHeight)
|
val m = modifier ?: Modifier.height(ComponentDefaults.DefaultButtonHeight)
|
||||||
val s = shape ?: ComponentDefaults.DefaultShape
|
val s = shape ?: ComponentDefaults.DefaultShape
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
modifier = m,
|
modifier = m.border(1.dp, MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.2f), s),
|
||||||
enabled = enabled,
|
enabled = enabled,
|
||||||
shape = s,
|
shape = s,
|
||||||
colors = colors,
|
colors = colors,
|
||||||
elevation = elevation,
|
elevation = elevation,
|
||||||
border = border,
|
border = border,
|
||||||
contentPadding = PaddingValues(
|
contentPadding = PaddingValues(start = 8.dp, end = 8.dp, top = 8.dp, bottom = 8.dp),
|
||||||
start = 8.dp, // More horizontal padding
|
|
||||||
end = 8.dp,
|
|
||||||
top = 8.dp, // Default vertical padding
|
|
||||||
bottom = 8.dp
|
|
||||||
),
|
|
||||||
interactionSource = interactionSource
|
interactionSource = interactionSource
|
||||||
) {
|
) {
|
||||||
content()
|
content()
|
||||||
@@ -368,11 +352,7 @@ fun AppOutlinedButton(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview
|
|
||||||
@Composable
|
|
||||||
fun PrimaryButtonWithIconPreview() {
|
|
||||||
PrimaryButton(onClick = { }, text = stringResource(R.string.primary_with_icon), icon = AppIcons.Add)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The secondary button for less prominent actions.
|
* The secondary button for less prominent actions.
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ truth = "1.4.5"
|
|||||||
zstdJni = "1.5.7-7"
|
zstdJni = "1.5.7-7"
|
||||||
composeMarkdown = "0.5.8"
|
composeMarkdown = "0.5.8"
|
||||||
jitpack = "1.0.10"
|
jitpack = "1.0.10"
|
||||||
|
foundationLayoutVersion = "1.10.3"
|
||||||
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
@@ -103,6 +104,7 @@ hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", ve
|
|||||||
hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version = "1.3.0" }
|
hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version = "1.3.0" }
|
||||||
mockk = { module = "io.mockk:mockk", version = "1.14.9" }
|
mockk = { module = "io.mockk:mockk", version = "1.14.9" }
|
||||||
compose-markdown = { module = "com.github.jeziellago:compose-markdown", version.ref = "composeMarkdown" }
|
compose-markdown = { module = "com.github.jeziellago:compose-markdown", version.ref = "composeMarkdown" }
|
||||||
|
androidx-compose-foundation-layout = { group = "androidx.compose.foundation", name = "foundation-layout", version.ref = "foundationLayoutVersion" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
|
|||||||
Reference in New Issue
Block a user