mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
refactor: adopt M3 Expressive components from material3 1.11.0-alpha06 (#5063)
This commit is contained in:
parent
a6423d0a0f
commit
3794c79dae
25 changed files with 128 additions and 69 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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].
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.app.map.component
|
||||
package org.meshtastic.feature.map.component
|
||||
|
||||
import androidx.compose.material3.FilledIconButton
|
||||
import androidx.compose.material3.Icon
|
||||
|
|
@ -14,13 +14,15 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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)
|
||||
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 <T> BaseMetricScreen(
|
|||
)
|
||||
}
|
||||
}
|
||||
IconButton(onClick = { isChartExpanded = !isChartExpanded }) {
|
||||
IconToggleButton(checked = isChartExpanded, onCheckedChange = { isChartExpanded = it }) {
|
||||
Icon(
|
||||
imageVector =
|
||||
if (isChartExpanded) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
@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
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
@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
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
@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
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
@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
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
@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
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
@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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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() })
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue