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) {
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* 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
|
||||
|
||||
import androidx.compose.material3.FilledIconButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButtonDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
|
||||
/**
|
||||
* A compact icon button used in map control overlays. Uses [FilledIconButton] for a consistent, compact appearance
|
||||
* across both Google and F-Droid flavors.
|
||||
*/
|
||||
@Composable
|
||||
fun MapButton(
|
||||
icon: ImageVector,
|
||||
contentDescription: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
iconTint: Color? = null,
|
||||
) {
|
||||
FilledIconButton(onClick = onClick, modifier = modifier) {
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = contentDescription,
|
||||
tint = iconTint ?: IconButtonDefaults.filledIconButtonColors().contentColor,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* 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
|
||||
|
||||
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.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.map_filter
|
||||
import org.meshtastic.core.resources.orient_north
|
||||
import org.meshtastic.core.resources.refresh
|
||||
import org.meshtastic.core.resources.toggle_my_position
|
||||
import org.meshtastic.core.ui.icon.LocationDisabled
|
||||
import org.meshtastic.core.ui.icon.MapCompass
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.icon.MyLocation
|
||||
import org.meshtastic.core.ui.icon.Refresh
|
||||
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).
|
||||
*
|
||||
* @param onToggleFilterMenu Callback to open/close the filter dropdown.
|
||||
* @param filterDropdownContent Composable rendered inside a [Box] alongside the filter button — typically a
|
||||
* `DropdownMenu` with filter options.
|
||||
* @param mapTypeContent Optional composable for a map type selector button + dropdown. Google flavor provides map type
|
||||
* and custom tile options; F-Droid provides a tile source selector.
|
||||
* @param layersContent Optional composable for a layers management button.
|
||||
* @param showRefresh Whether to show a refresh button (e.g., for network map layers).
|
||||
* @param isRefreshing Whether a refresh is currently in progress.
|
||||
* @param onRefresh Callback when the refresh button is clicked.
|
||||
*/
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
fun MapControlsOverlay(
|
||||
onToggleFilterMenu: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
bearing: Float = 0f,
|
||||
onCompassClick: () -> Unit = {},
|
||||
followPhoneBearing: Boolean = false,
|
||||
filterDropdownContent: @Composable () -> Unit = {},
|
||||
mapTypeContent: @Composable () -> Unit = {},
|
||||
layersContent: @Composable () -> Unit = {},
|
||||
isLocationTrackingEnabled: Boolean = false,
|
||||
onToggleLocationTracking: () -> Unit = {},
|
||||
showRefresh: Boolean = false,
|
||||
isRefreshing: Boolean = false,
|
||||
onRefresh: () -> Unit = {},
|
||||
) {
|
||||
Row(modifier = modifier) {
|
||||
// Compass
|
||||
CompassButton(onClick = onCompassClick, bearing = bearing, isFollowing = followPhoneBearing)
|
||||
|
||||
// Filter button + dropdown
|
||||
Box {
|
||||
MapButton(
|
||||
icon = MeshtasticIcons.Tune,
|
||||
contentDescription = stringResource(Res.string.map_filter),
|
||||
onClick = onToggleFilterMenu,
|
||||
)
|
||||
filterDropdownContent()
|
||||
}
|
||||
|
||||
// Map type selector (flavor-specific)
|
||||
mapTypeContent()
|
||||
|
||||
// Layers button (flavor-specific)
|
||||
layersContent()
|
||||
|
||||
// Refresh button (optional)
|
||||
if (showRefresh) {
|
||||
if (isRefreshing) {
|
||||
Box(modifier = Modifier.padding(8.dp)) {
|
||||
CircularProgressIndicator(modifier = Modifier.size(24.dp), strokeWidth = 2.dp)
|
||||
}
|
||||
} else {
|
||||
MapButton(
|
||||
icon = MeshtasticIcons.Refresh,
|
||||
contentDescription = stringResource(Res.string.refresh),
|
||||
onClick = onRefresh,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Location tracking button
|
||||
MapButton(
|
||||
icon = if (isLocationTrackingEnabled) MeshtasticIcons.LocationDisabled else MeshtasticIcons.MyLocation,
|
||||
contentDescription = stringResource(Res.string.toggle_my_position),
|
||||
onClick = onToggleLocationTracking,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CompassButton(onClick: () -> Unit, bearing: Float, isFollowing: Boolean) {
|
||||
val iconTint =
|
||||
when {
|
||||
isFollowing -> MaterialTheme.colorScheme.primary
|
||||
bearing == 0f -> MaterialTheme.colorScheme.StatusRed
|
||||
else -> null
|
||||
}
|
||||
MapButton(
|
||||
modifier = Modifier.rotate(-bearing),
|
||||
icon = MeshtasticIcons.MapCompass,
|
||||
iconTint = iconTint,
|
||||
contentDescription = stringResource(Res.string.orient_north),
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue