diff --git a/app/src/fdroid/kotlin/org/meshtastic/app/map/MapView.kt b/app/src/fdroid/kotlin/org/meshtastic/app/map/MapView.kt index 54935b422..657f7ab74 100644 --- a/app/src/fdroid/kotlin/org/meshtastic/app/map/MapView.kt +++ b/app/src/fdroid/kotlin/org/meshtastic/app/map/MapView.kt @@ -77,8 +77,6 @@ import org.meshtastic.app.map.cluster.RadiusMarkerClusterer import org.meshtastic.app.map.component.CacheLayout import org.meshtastic.app.map.component.DownloadButton import org.meshtastic.app.map.component.EditWaypointDialog -import org.meshtastic.app.map.component.MapButton -import org.meshtastic.app.map.component.MapControlsOverlay import org.meshtastic.app.map.model.CustomTileSource import org.meshtastic.app.map.model.MarkerWithLabel import org.meshtastic.core.common.gpsDisabled @@ -130,6 +128,8 @@ import org.meshtastic.core.ui.util.formatAgo import org.meshtastic.core.ui.util.showToast import org.meshtastic.feature.map.BaseMapViewModel.MapFilterState import org.meshtastic.feature.map.LastHeardFilter +import org.meshtastic.feature.map.component.MapButton +import org.meshtastic.feature.map.component.MapControlsOverlay import org.meshtastic.proto.Config.DisplayConfig.DisplayUnits import org.meshtastic.proto.Waypoint import org.osmdroid.bonuspack.utils.BonusPackHelper.getBitmapFromVectorDrawable diff --git a/app/src/fdroid/kotlin/org/meshtastic/app/map/node/NodeTrackOsmMap.kt b/app/src/fdroid/kotlin/org/meshtastic/app/map/node/NodeTrackOsmMap.kt index b24e57b63..a6aec4c2d 100644 --- a/app/src/fdroid/kotlin/org/meshtastic/app/map/node/NodeTrackOsmMap.kt +++ b/app/src/fdroid/kotlin/org/meshtastic/app/map/node/NodeTrackOsmMap.kt @@ -42,7 +42,6 @@ import org.meshtastic.app.map.addCopyright import org.meshtastic.app.map.addPolyline import org.meshtastic.app.map.addPositionMarkers import org.meshtastic.app.map.addScaleBarOverlay -import org.meshtastic.app.map.component.MapControlsOverlay import org.meshtastic.app.map.model.CustomTileSource import org.meshtastic.app.map.rememberMapViewWithLifecycle import org.meshtastic.core.common.util.nowSeconds @@ -50,6 +49,7 @@ import org.meshtastic.core.model.util.GeoConstants.DEG_D import org.meshtastic.core.resources.Res import org.meshtastic.core.resources.last_heard_filter_label import org.meshtastic.feature.map.LastHeardFilter +import org.meshtastic.feature.map.component.MapControlsOverlay import org.meshtastic.proto.Position import org.osmdroid.util.BoundingBox import org.osmdroid.util.GeoPoint @@ -61,8 +61,8 @@ import kotlin.math.roundToInt * * Applies the [lastHeardTrackFilter][org.meshtastic.feature.map.BaseMapViewModel.MapFilterState.lastHeardTrackFilter] * from [MapViewModel] to filter positions by time, matching the behavior of the Google Maps implementation. Includes a - * minimal [MapControlsOverlay][org.meshtastic.app.map.component.MapControlsOverlay] with a track time filter slider so - * users can adjust the time range directly from the map. + * minimal [MapControlsOverlay][org.meshtastic.feature.map.component.MapControlsOverlay] with a track time filter slider + * so users can adjust the time range directly from the map. * * Supports optional synchronized selection via [selectedPositionTime] and [onPositionSelected]. * diff --git a/app/src/google/kotlin/org/meshtastic/app/map/MapView.kt b/app/src/google/kotlin/org/meshtastic/app/map/MapView.kt index 125f861cc..c8f2f3fee 100644 --- a/app/src/google/kotlin/org/meshtastic/app/map/MapView.kt +++ b/app/src/google/kotlin/org/meshtastic/app/map/MapView.kt @@ -97,8 +97,6 @@ import org.meshtastic.app.map.component.ClusterItemsListDialog import org.meshtastic.app.map.component.CustomMapLayersSheet import org.meshtastic.app.map.component.CustomTileProviderManagerSheet import org.meshtastic.app.map.component.EditWaypointDialog -import org.meshtastic.app.map.component.MapButton -import org.meshtastic.app.map.component.MapControlsOverlay import org.meshtastic.app.map.component.MapFilterDropdown import org.meshtastic.app.map.component.MapTypeDropdown import org.meshtastic.app.map.component.NodeClusterMarkers @@ -137,6 +135,8 @@ import org.meshtastic.core.ui.util.formatAgo import org.meshtastic.core.ui.util.formatPositionTime import org.meshtastic.feature.map.BaseMapViewModel.MapFilterState import org.meshtastic.feature.map.LastHeardFilter +import org.meshtastic.feature.map.component.MapButton +import org.meshtastic.feature.map.component.MapControlsOverlay import org.meshtastic.feature.map.tracerouteNodeSelection import org.meshtastic.proto.Config.DisplayConfig.DisplayUnits import org.meshtastic.proto.Position diff --git a/app/src/google/kotlin/org/meshtastic/app/map/component/CustomMapLayersSheet.kt b/app/src/google/kotlin/org/meshtastic/app/map/component/CustomMapLayersSheet.kt index fb5f682ed..fd9272579 100644 --- a/app/src/google/kotlin/org/meshtastic/app/map/component/CustomMapLayersSheet.kt +++ b/app/src/google/kotlin/org/meshtastic/app/map/component/CustomMapLayersSheet.kt @@ -31,6 +31,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.IconToggleButton import androidx.compose.material3.ListItem import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField @@ -125,7 +126,10 @@ fun CustomMapLayersSheet( } } } - IconButton(onClick = { onToggleVisibility(layer.id) }) { + IconToggleButton( + checked = layer.isVisible, + onCheckedChange = { onToggleVisibility(layer.id) }, + ) { Icon( imageVector = if (layer.isVisible) { diff --git a/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/EditPasswordPreference.kt b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/EditPasswordPreference.kt index 681952e61..2dce97aa5 100644 --- a/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/EditPasswordPreference.kt +++ b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/EditPasswordPreference.kt @@ -19,7 +19,7 @@ package org.meshtastic.core.ui.component import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton +import androidx.compose.material3.IconToggleButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -36,6 +36,7 @@ import org.meshtastic.core.resources.Res import org.meshtastic.core.resources.hide_password import org.meshtastic.core.resources.show_password import org.meshtastic.core.ui.icon.MeshtasticIcons +import org.meshtastic.core.ui.icon.Visibility import org.meshtastic.core.ui.icon.VisibilityOff @Composable @@ -63,10 +64,9 @@ fun EditPasswordPreference( onFocusChanged = {}, visualTransformation = if (isPasswordVisible) VisualTransformation.None else PasswordVisualTransformation(), trailingIcon = { - IconButton(onClick = { isPasswordVisible = !isPasswordVisible }) { + IconToggleButton(checked = isPasswordVisible, onCheckedChange = { isPasswordVisible = it }) { Icon( - imageVector = - if (isPasswordVisible) MeshtasticIcons.VisibilityOff else MeshtasticIcons.VisibilityOff, + imageVector = if (isPasswordVisible) MeshtasticIcons.VisibilityOff else MeshtasticIcons.Visibility, contentDescription = if (isPasswordVisible) { stringResource(Res.string.hide_password) diff --git a/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/PreferenceFooter.kt b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/PreferenceFooter.kt index 37e354d32..6bf0065bf 100644 --- a/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/PreferenceFooter.kt +++ b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/PreferenceFooter.kt @@ -23,6 +23,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ElevatedButton +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -43,22 +44,28 @@ fun PreferenceFooter( horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically, ) { + @OptIn(ExperimentalMaterial3ExpressiveApi::class) + val mediumHeight = ButtonDefaults.MediumContainerHeight if (negativeText != null) { + @OptIn(ExperimentalMaterial3ExpressiveApi::class) ElevatedButton( - modifier = Modifier.height(48.dp).weight(1f), + shapes = ButtonDefaults.shapesFor(mediumHeight), + modifier = Modifier.height(mediumHeight).weight(1f), colors = ButtonDefaults.filledTonalButtonColors(), onClick = onNegativeClicked, ) { - Text(text = negativeText) + Text(text = negativeText, style = ButtonDefaults.textStyleFor(mediumHeight)) } } if (positiveText != null) { + @OptIn(ExperimentalMaterial3ExpressiveApi::class) ElevatedButton( - modifier = Modifier.height(48.dp).weight(1f), + shapes = ButtonDefaults.shapesFor(mediumHeight), + modifier = Modifier.height(mediumHeight).weight(1f), colors = ButtonDefaults.buttonColors(), onClick = { if (enabled) onPositiveClicked() }, ) { - Text(text = positiveText) + Text(text = positiveText, style = ButtonDefaults.textStyleFor(mediumHeight)) } } } diff --git a/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/qr/ScannedQrCodeDialog.kt b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/qr/ScannedQrCodeDialog.kt index 632c8abb4..d5f4e31ec 100644 --- a/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/qr/ScannedQrCodeDialog.kt +++ b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/qr/ScannedQrCodeDialog.kt @@ -29,6 +29,7 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Surface @@ -240,21 +241,33 @@ fun ScannedQrCodeDialog( val unselectedColors = ButtonDefaults.outlinedButtonColors(contentColor = MaterialTheme.colorScheme.onSurface) + @OptIn(ExperimentalMaterial3ExpressiveApi::class) + val mediumHeight = ButtonDefaults.MediumContainerHeight + @OptIn(ExperimentalMaterial3ExpressiveApi::class) OutlinedButton( onClick = { shouldReplace = false }, - modifier = Modifier.height(48.dp).weight(1f), + shapes = ButtonDefaults.shapesFor(mediumHeight), + modifier = Modifier.height(mediumHeight).weight(1f), colors = if (!shouldReplace) selectedColors else unselectedColors, ) { - Text(text = stringResource(Res.string.add)) + Text( + text = stringResource(Res.string.add), + style = ButtonDefaults.textStyleFor(mediumHeight), + ) } + @OptIn(ExperimentalMaterial3ExpressiveApi::class) OutlinedButton( onClick = { shouldReplace = true }, - modifier = Modifier.height(48.dp).weight(1f), + shapes = ButtonDefaults.shapesFor(mediumHeight), + modifier = Modifier.height(mediumHeight).weight(1f), enabled = incoming.lora_config != null, colors = if (shouldReplace) selectedColors else unselectedColors, ) { - Text(text = stringResource(Res.string.replace)) + Text( + text = stringResource(Res.string.replace), + style = ButtonDefaults.textStyleFor(mediumHeight), + ) } } } diff --git a/feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/ui/components/ConnectingDeviceInfo.kt b/feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/ui/components/ConnectingDeviceInfo.kt index 9907e01c0..9c86a17bf 100644 --- a/feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/ui/components/ConnectingDeviceInfo.kt +++ b/feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/ui/components/ConnectingDeviceInfo.kt @@ -26,6 +26,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -74,17 +75,20 @@ fun ConnectingDeviceInfo( } } + @OptIn(ExperimentalMaterial3ExpressiveApi::class) + val largeHeight = ButtonDefaults.LargeContainerHeight + @OptIn(ExperimentalMaterial3ExpressiveApi::class) Button( - modifier = Modifier.fillMaxWidth().height(56.dp), - shape = MaterialTheme.shapes.medium, + onClick = onClickDisconnect, + shapes = ButtonDefaults.shapesFor(largeHeight), + modifier = Modifier.fillMaxWidth().height(largeHeight), colors = ButtonDefaults.buttonColors( containerColor = MaterialTheme.colorScheme.StatusRed, contentColor = Color.White, ), - onClick = onClickDisconnect, ) { - Text(stringResource(Res.string.disconnect), style = MaterialTheme.typography.titleMedium) + Text(stringResource(Res.string.disconnect), style = ButtonDefaults.textStyleFor(largeHeight)) } } } diff --git a/feature/firmware/src/commonMain/kotlin/org/meshtastic/feature/firmware/FirmwareUpdateScreen.kt b/feature/firmware/src/commonMain/kotlin/org/meshtastic/feature/firmware/FirmwareUpdateScreen.kt index 0a051fa9c..eee6637af 100644 --- a/feature/firmware/src/commonMain/kotlin/org/meshtastic/feature/firmware/FirmwareUpdateScreen.kt +++ b/feature/firmware/src/commonMain/kotlin/org/meshtastic/feature/firmware/FirmwareUpdateScreen.kt @@ -35,15 +35,18 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.CircularWavyProgressIndicator import androidx.compose.material3.ElevatedCard import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.material3.LinearProgressIndicator +import androidx.compose.material3.LinearWavyProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Scaffold @@ -381,24 +384,35 @@ private fun ReadyState( Spacer(Modifier.height(16.dp)) if (selectedReleaseType == FirmwareReleaseType.LOCAL) { + @OptIn(ExperimentalMaterial3ExpressiveApi::class) + val largeHeight = ButtonDefaults.LargeContainerHeight + @OptIn(ExperimentalMaterial3ExpressiveApi::class) Button( onClick = { haptic.performHapticFeedback(HapticFeedbackType.LongPress) showDisclaimer = true }, - modifier = Modifier.fillMaxWidth().height(56.dp), + shapes = ButtonDefaults.shapesFor(largeHeight), + modifier = Modifier.fillMaxWidth().height(largeHeight), ) { Icon(MeshtasticIcons.Folder, contentDescription = null) Spacer(Modifier.width(8.dp)) - Text(stringResource(Res.string.firmware_update_select_file)) + Text( + stringResource(Res.string.firmware_update_select_file), + style = ButtonDefaults.textStyleFor(largeHeight), + ) } } else if (state.release != null) { + @OptIn(ExperimentalMaterial3ExpressiveApi::class) + val largeHeight = ButtonDefaults.LargeContainerHeight + @OptIn(ExperimentalMaterial3ExpressiveApi::class) Button( onClick = { haptic.performHapticFeedback(HapticFeedbackType.LongPress) showDisclaimer = true }, - modifier = Modifier.fillMaxWidth().height(56.dp), + shapes = ButtonDefaults.shapesFor(largeHeight), + modifier = Modifier.fillMaxWidth().height(largeHeight), ) { Icon( imageVector = @@ -416,6 +430,7 @@ private fun ReadyState( resource = Res.string.firmware_update_method_detail, stringResource(state.updateMethod.description), ), + style = ButtonDefaults.textStyleFor(largeHeight), ) } Spacer(Modifier.height(24.dp)) @@ -680,7 +695,8 @@ private fun ProgressContent( tint = MaterialTheme.colorScheme.primary, ) } else { - CircularProgressIndicator( + @OptIn(ExperimentalMaterial3ExpressiveApi::class) + CircularWavyProgressIndicator( progress = { if (isUpdating) progressState.progress else 1f }, modifier = Modifier.size(64.dp), ) @@ -708,7 +724,8 @@ private fun ProgressContent( Spacer(Modifier.height(12.dp)) if (isDownloading || isUpdating) { - LinearProgressIndicator( + @OptIn(ExperimentalMaterial3ExpressiveApi::class) + LinearWavyProgressIndicator( progress = { progressState.progress }, modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp), ) @@ -850,8 +867,15 @@ private fun SuccessState(onDone: () -> Unit) { textAlign = TextAlign.Center, ) Spacer(Modifier.height(32.dp)) - Button(onClick = onDone, modifier = Modifier.fillMaxWidth().height(56.dp)) { - Text(stringResource(Res.string.firmware_update_done)) + @OptIn(ExperimentalMaterial3ExpressiveApi::class) + val largeHeight = ButtonDefaults.LargeContainerHeight + @OptIn(ExperimentalMaterial3ExpressiveApi::class) + Button( + onClick = onDone, + shapes = ButtonDefaults.shapesFor(largeHeight), + modifier = Modifier.fillMaxWidth().height(largeHeight), + ) { + Text(stringResource(Res.string.firmware_update_done), style = ButtonDefaults.textStyleFor(largeHeight)) } } } diff --git a/app/src/main/kotlin/org/meshtastic/app/map/component/MapButton.kt b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MapButton.kt similarity index 97% rename from app/src/main/kotlin/org/meshtastic/app/map/component/MapButton.kt rename to feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MapButton.kt index 997d7d08b..a8bce5529 100644 --- a/app/src/main/kotlin/org/meshtastic/app/map/component/MapButton.kt +++ b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MapButton.kt @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.meshtastic.app.map.component +package org.meshtastic.feature.map.component import androidx.compose.material3.FilledIconButton import androidx.compose.material3.Icon diff --git a/app/src/main/kotlin/org/meshtastic/app/map/component/MapControlsOverlay.kt b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MapControlsOverlay.kt similarity index 87% rename from app/src/main/kotlin/org/meshtastic/app/map/component/MapControlsOverlay.kt rename to feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MapControlsOverlay.kt index 74f08e07f..431354e6d 100644 --- a/app/src/main/kotlin/org/meshtastic/app/map/component/MapControlsOverlay.kt +++ b/feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/MapControlsOverlay.kt @@ -14,13 +14,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.meshtastic.app.map.component +package org.meshtastic.feature.map.component import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.FloatingToolbarDefaults +import androidx.compose.material3.HorizontalFloatingToolbar import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -41,8 +43,9 @@ import org.meshtastic.core.ui.icon.Tune import org.meshtastic.core.ui.theme.StatusColors.StatusRed /** - * Shared map controls overlay used by both Google and F-Droid map views. Provides compass, filter button, location - * tracking button, and optional slots for flavor-specific content (map type selector, layers, refresh). + * Shared map controls overlay using [HorizontalFloatingToolbar] for Material 3 Expressive styling. Provides compass, + * filter button, location tracking button, and optional slots for flavor-specific content (map type selector, layers, + * refresh). * * @param onToggleFilterMenu Callback to open/close the filter dropdown. * @param filterDropdownContent Composable rendered inside a [Box] alongside the filter button — typically a @@ -54,6 +57,7 @@ import org.meshtastic.core.ui.theme.StatusColors.StatusRed * @param isRefreshing Whether a refresh is currently in progress. * @param onRefresh Callback when the refresh button is clicked. */ +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Suppress("LongParameterList") @Composable fun MapControlsOverlay( @@ -71,7 +75,11 @@ fun MapControlsOverlay( isRefreshing: Boolean = false, onRefresh: () -> Unit = {}, ) { - Row(modifier = modifier) { + HorizontalFloatingToolbar( + expanded = true, + modifier = modifier, + colors = FloatingToolbarDefaults.standardFloatingToolbarColors(), + ) { // Compass CompassButton(onClick = onCompassClick, bearing = bearing, isFollowing = followPhoneBearing) diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/component/NodeItem.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/component/NodeItem.kt index cbf99e9ca..514be15e7 100644 --- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/component/NodeItem.kt +++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/component/NodeItem.kt @@ -31,7 +31,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults -import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -96,7 +95,6 @@ private const val ACTIVE_ALPHA = 0.5f private const val INACTIVE_ALPHA = 0.2f private const val GRID_COLUMNS = 3 -@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable @Suppress("LongMethod") fun NodeItem( @@ -391,7 +389,6 @@ private fun MetricsGrid(items: List<@Composable () -> Unit>) { } } -@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable private fun NodeItemHeader( thatNode: Node, diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/BaseMetricChart.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/BaseMetricChart.kt index b8e6f0aae..8f65bf6d8 100644 --- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/BaseMetricChart.kt +++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/BaseMetricChart.kt @@ -31,6 +31,7 @@ import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.IconToggleButton import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -273,7 +274,7 @@ fun BaseMetricScreen( ) } } - IconButton(onClick = { isChartExpanded = !isChartExpanded }) { + IconToggleButton(checked = isChartExpanded, onCheckedChange = { isChartExpanded = it }) { Icon( imageVector = if (isChartExpanded) { diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/DeviceMetrics.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/DeviceMetrics.kt index f3e02818d..5725da604 100644 --- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/DeviceMetrics.kt +++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/DeviceMetrics.kt @@ -15,7 +15,6 @@ * along with this program. If not, see . */ @file:Suppress("MagicNumber") -@file:OptIn(ExperimentalMaterial3ExpressiveApi::class) package org.meshtastic.feature.node.metrics @@ -31,7 +30,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/EnvironmentMetrics.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/EnvironmentMetrics.kt index 12c604a46..4f9e88d47 100644 --- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/EnvironmentMetrics.kt +++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/EnvironmentMetrics.kt @@ -15,7 +15,6 @@ * along with this program. If not, see . */ @file:Suppress("TooManyFunctions") -@file:OptIn(ExperimentalMaterial3ExpressiveApi::class) package org.meshtastic.feature.node.metrics @@ -30,7 +29,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/HostMetricsLog.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/HostMetricsLog.kt index f22710ef5..2cbf008e1 100644 --- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/HostMetricsLog.kt +++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/HostMetricsLog.kt @@ -36,7 +36,6 @@ import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ProgressIndicatorDefaults @@ -155,7 +154,6 @@ private fun HostMetricsCard(telemetry: Telemetry, isSelected: Boolean, onClick: } /** Card body showing timestamp, load averages with progress bars, memory, disk, and uptime. */ -@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable private fun HostMetricsCardContent(time: String, hostMetrics: org.meshtastic.proto.HostMetrics?) { Column(modifier = Modifier.padding(12.dp)) { diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/MetricLogComponents.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/MetricLogComponents.kt index 653293835..92e929056 100644 --- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/MetricLogComponents.kt +++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/MetricLogComponents.kt @@ -14,8 +14,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -@file:OptIn(ExperimentalMaterial3ExpressiveApi::class) - package org.meshtastic.feature.node.metrics import androidx.compose.foundation.BorderStroke @@ -35,7 +33,6 @@ import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PaxMetrics.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PaxMetrics.kt index cad2b63b1..598cd5ca9 100644 --- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PaxMetrics.kt +++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PaxMetrics.kt @@ -14,8 +14,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -@file:OptIn(ExperimentalMaterial3ExpressiveApi::class) - package org.meshtastic.feature.node.metrics import androidx.compose.foundation.layout.Column @@ -28,7 +26,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PowerMetrics.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PowerMetrics.kt index e2064fd5f..c815f6622 100644 --- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PowerMetrics.kt +++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PowerMetrics.kt @@ -15,7 +15,6 @@ * along with this program. If not, see . */ @file:Suppress("MagicNumber") -@file:OptIn(ExperimentalMaterial3ExpressiveApi::class) package org.meshtastic.feature.node.metrics @@ -31,7 +30,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.rememberScrollState -import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.FilterChip import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/SignalMetrics.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/SignalMetrics.kt index ca6fd2d61..e8b184427 100644 --- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/SignalMetrics.kt +++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/SignalMetrics.kt @@ -14,8 +14,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -@file:OptIn(ExperimentalMaterial3ExpressiveApi::class) - package org.meshtastic.feature.node.metrics import androidx.compose.foundation.layout.Arrangement @@ -31,7 +29,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/TracerouteLog.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/TracerouteLog.kt index bf5846e9f..caf3e1938 100644 --- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/TracerouteLog.kt +++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/TracerouteLog.kt @@ -36,7 +36,6 @@ import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -242,7 +241,6 @@ private fun TracerouteCard( /** Card body showing timestamp, route summary text/icon, and metric indicators. */ @Composable -@OptIn(ExperimentalMaterial3ExpressiveApi::class) private fun TracerouteCardContent(time: String, summaryText: String, icon: ImageVector, point: TraceroutePoint) { Column(modifier = Modifier.padding(12.dp)) { Row( diff --git a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/debugging/Debug.kt b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/debugging/Debug.kt index 3fab5b624..dba15e1a4 100644 --- a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/debugging/Debug.kt +++ b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/debugging/Debug.kt @@ -35,6 +35,7 @@ import androidx.compose.material3.CardDefaults import androidx.compose.material3.ColorScheme import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.IconToggleButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text @@ -138,7 +139,7 @@ fun DebugScreen(onNavigateUp: () -> Unit, viewModel: DebugViewModel) { canNavigateUp = true, onNavigateUp = onNavigateUp, actions = { - IconButton(onClick = { showSettings = !showSettings }) { + IconToggleButton(checked = showSettings, onCheckedChange = { showSettings = it }) { Icon(imageVector = MeshtasticIcons.Settings, contentDescription = null) } DebugMenuActions(deleteLogs = { viewModel.requestDeleteAllLogs() }) diff --git a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/NetworkConfigItemList.kt b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/NetworkConfigItemList.kt index b9796aba5..584f8eedc 100644 --- a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/NetworkConfigItemList.kt +++ b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/NetworkConfigItemList.kt @@ -22,6 +22,8 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -220,12 +222,19 @@ fun NetworkConfigScreen(viewModel: RadioConfigViewModel, onBack: () -> Unit, onO onValueChanged = { formState.value = formState.value.copy(wifi_psk = it) }, ) HorizontalDivider() + @OptIn(ExperimentalMaterial3ExpressiveApi::class) + val mediumHeight = ButtonDefaults.MediumContainerHeight + @OptIn(ExperimentalMaterial3ExpressiveApi::class) Button( onClick = { barcodeScanner.startScan() }, - modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp).height(48.dp), + shapes = ButtonDefaults.shapesFor(mediumHeight), + modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp).height(mediumHeight), enabled = state.connected, ) { - Text(text = stringResource(Res.string.wifi_qr_code_scan)) + Text( + text = stringResource(Res.string.wifi_qr_code_scan), + style = ButtonDefaults.textStyleFor(mediumHeight), + ) } } } diff --git a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/NodeActionButton.kt b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/NodeActionButton.kt index fe9675e6d..fa6d9a8fb 100644 --- a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/NodeActionButton.kt +++ b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/NodeActionButton.kt @@ -24,9 +24,10 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.LocalContentColor -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -37,14 +38,22 @@ import androidx.compose.ui.unit.dp @Composable fun NodeActionButton( - modifier: Modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp).height(48.dp), + modifier: Modifier = Modifier, title: String, enabled: Boolean, icon: ImageVector? = null, iconTint: Color? = null, onClick: () -> Unit, ) { - Button(onClick = { onClick() }, enabled = enabled, modifier = modifier) { + @OptIn(ExperimentalMaterial3ExpressiveApi::class) + val mediumHeight = ButtonDefaults.MediumContainerHeight + @OptIn(ExperimentalMaterial3ExpressiveApi::class) + Button( + onClick = { onClick() }, + shapes = ButtonDefaults.shapesFor(mediumHeight), + enabled = enabled, + modifier = modifier.then(Modifier.fillMaxWidth().padding(vertical = 4.dp).height(mediumHeight)), + ) { Row(verticalAlignment = Alignment.CenterVertically) { if (icon != null) { Icon( @@ -55,7 +64,7 @@ fun NodeActionButton( ) Spacer(modifier = Modifier.width(8.dp)) } - Text(text = title, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.weight(1f)) + Text(text = title, style = ButtonDefaults.textStyleFor(mediumHeight), modifier = Modifier.weight(1f)) } } } diff --git a/feature/wifi-provision/src/commonMain/kotlin/org/meshtastic/feature/wifiprovision/ui/WifiProvisionScreen.kt b/feature/wifi-provision/src/commonMain/kotlin/org/meshtastic/feature/wifiprovision/ui/WifiProvisionScreen.kt index 20b54825e..785654c71 100644 --- a/feature/wifi-provision/src/commonMain/kotlin/org/meshtastic/feature/wifiprovision/ui/WifiProvisionScreen.kt +++ b/feature/wifi-provision/src/commonMain/kotlin/org/meshtastic/feature/wifiprovision/ui/WifiProvisionScreen.kt @@ -52,6 +52,7 @@ import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.IconToggleButton import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.ListItem import androidx.compose.material3.ListItemDefaults @@ -414,7 +415,7 @@ internal fun ConnectedContent( singleLine = true, visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), trailingIcon = { - IconButton(onClick = { passwordVisible = !passwordVisible }) { + IconToggleButton(checked = passwordVisible, onCheckedChange = { passwordVisible = it }) { Icon( imageVector = if (passwordVisible) MeshtasticIcons.VisibilityOff else MeshtasticIcons.Visibility,