NewMenuComponents.kt (6094B)
1 /** 2 * Metrolist Project (C) 2026 3 * Licensed under GPL-3.0 | See git history for contributors 4 */ 5 6 package net.taler.wallet.compose 7 8 import androidx.compose.animation.animateContentSize 9 import androidx.compose.foundation.clickable 10 import androidx.compose.foundation.layout.Arrangement 11 import androidx.compose.foundation.layout.Column 12 import androidx.compose.foundation.layout.Row 13 import androidx.compose.foundation.layout.Spacer 14 import androidx.compose.foundation.layout.fillMaxWidth 15 import androidx.compose.foundation.layout.height 16 import androidx.compose.foundation.layout.padding 17 import androidx.compose.foundation.layout.width 18 import androidx.compose.foundation.shape.RoundedCornerShape 19 import androidx.compose.material3.Card 20 import androidx.compose.material3.CardColors 21 import androidx.compose.material3.CardDefaults 22 import androidx.compose.material3.HorizontalDivider 23 import androidx.compose.material3.ListItem 24 import androidx.compose.material3.MaterialTheme 25 import androidx.compose.material3.ProvideTextStyle 26 import androidx.compose.material3.Text 27 import androidx.compose.runtime.Composable 28 import androidx.compose.ui.Alignment 29 import androidx.compose.ui.Modifier 30 import androidx.compose.ui.text.font.FontWeight 31 import androidx.compose.ui.unit.dp 32 import androidx.compose.ui.unit.sp 33 34 // Enhanced Menu Item - Material 3 Expressive Design 35 @Composable 36 fun NewMenuItem( 37 modifier: Modifier = Modifier, 38 headlineContent: @Composable () -> Unit, 39 leadingContent: @Composable (() -> Unit)? = null, 40 trailingContent: @Composable (() -> Unit)? = null, 41 supportingContent: @Composable (() -> Unit)? = null, 42 onClick: (() -> Unit)? = null, 43 enabled: Boolean = true, 44 ) { 45 ListItem( 46 headlineContent = headlineContent, 47 leadingContent = leadingContent, 48 trailingContent = trailingContent, 49 supportingContent = supportingContent, 50 modifier = modifier 51 .clickable(enabled = enabled) { onClick?.invoke() } 52 .padding(horizontal = 4.dp), 53 tonalElevation = 0.dp 54 ) 55 } 56 57 // Enhanced Menu Section Header - Material 3 Expressive Design 58 @Composable 59 fun NewMenuSectionHeader( 60 modifier: Modifier = Modifier, 61 text: String, 62 ) { 63 Text( 64 text = text, 65 style = MaterialTheme.typography.titleMedium.copy( 66 fontWeight = FontWeight.SemiBold, 67 fontSize = 16.sp 68 ), 69 color = MaterialTheme.colorScheme.primary, 70 modifier = modifier.padding(horizontal = 20.dp, vertical = 12.dp) 71 ) 72 } 73 74 // Enhanced Menu Content - Material 3 Expressive Design 75 @Composable 76 fun NewMenuContent( 77 modifier: Modifier = Modifier, 78 headerContent: @Composable (() -> Unit)? = null, 79 actionGrid: @Composable (() -> Unit)? = null, 80 menuItems: @Composable (() -> Unit)? = null, 81 ) { 82 Column( 83 modifier = modifier, 84 verticalArrangement = Arrangement.spacedBy(8.dp) 85 ) { 86 // Header 87 headerContent?.invoke() 88 89 // Action Grid 90 actionGrid?.invoke() 91 92 // Divider if both header and actions exist 93 if (headerContent != null && actionGrid != null) { 94 HorizontalDivider( 95 modifier = Modifier.padding(vertical = 16.dp), 96 color = MaterialTheme.colorScheme.outlineVariant 97 ) 98 } 99 100 // Menu Items 101 menuItems?.invoke() 102 } 103 } 104 105 @Composable 106 fun Material3MenuGroup( 107 items: List<Material3MenuItemData>, 108 ) { 109 Column( 110 modifier = Modifier.fillMaxWidth(), 111 verticalArrangement = Arrangement.spacedBy(4.dp) 112 ) { 113 items.forEachIndexed { index, item -> 114 val shape = when { 115 items.size == 1 -> RoundedCornerShape(24.dp) 116 index == 0 -> RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp, bottomStart = 6.dp, bottomEnd = 6.dp) 117 index == items.size - 1 -> RoundedCornerShape(topStart = 6.dp, topEnd = 6.dp, bottomStart = 24.dp, bottomEnd = 24.dp) 118 else -> RoundedCornerShape(6.dp) 119 } 120 121 Card( 122 modifier = Modifier 123 .fillMaxWidth() 124 .animateContentSize(), 125 shape = shape, 126 colors = item.cardColors ?: CardDefaults.cardColors( 127 containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f) 128 ), 129 elevation = CardDefaults.cardElevation(defaultElevation = 0.dp) 130 ) { 131 Material3MenuItemRow(item = item) 132 } 133 } 134 } 135 } 136 137 @Composable 138 private fun Material3MenuItemRow( 139 item: Material3MenuItemData, 140 ) { 141 Row( 142 modifier = Modifier 143 .fillMaxWidth() 144 .clickable( 145 enabled = item.onClick != null, 146 onClick = { item.onClick?.invoke() } 147 ) 148 .padding(horizontal = 20.dp, vertical = 16.dp), 149 verticalAlignment = Alignment.CenterVertically 150 ) { 151 item.icon?.let { icon -> 152 icon() 153 Spacer(modifier = Modifier.width(16.dp)) 154 } 155 156 Column( 157 modifier = Modifier.weight(1f) 158 ) { 159 ProvideTextStyle(MaterialTheme.typography.titleMedium) { 160 item.title() 161 } 162 163 item.description?.let { desc -> 164 Spacer(modifier = Modifier.height(2.dp)) 165 ProvideTextStyle( 166 MaterialTheme.typography.bodyMedium.copy( 167 color = MaterialTheme.colorScheme.onSurfaceVariant 168 ) 169 ) { 170 desc() 171 } 172 } 173 } 174 item.trailingContent?.let { trailing -> 175 Spacer(modifier = Modifier.width(8.dp)) 176 trailing() 177 } 178 } 179 } 180 181 data class Material3MenuItemData( 182 val icon: (@Composable () -> Unit)? = null, 183 val title: @Composable () -> Unit, 184 val description: (@Composable () -> Unit)? = null, 185 val onClick: (() -> Unit)? = null, 186 val cardColors: CardColors? = null, 187 val trailingContent: (@Composable () -> Unit)? = null, 188 )