mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-07-12 03:27:06 +10:00
resolved conflict and update doc
This commit is contained in:
@@ -4,6 +4,7 @@ class FeatureToggleRow extends StatefulWidget {
|
||||
final String title;
|
||||
final String subtitle;
|
||||
final bool value;
|
||||
final bool enabled;
|
||||
final bool hasRefreshing;
|
||||
final bool isRefreshing;
|
||||
final ValueChanged<bool>? onChanged;
|
||||
@@ -15,6 +16,7 @@ class FeatureToggleRow extends StatefulWidget {
|
||||
required this.title,
|
||||
required this.subtitle,
|
||||
required this.value,
|
||||
this.enabled = true,
|
||||
this.hasRefreshing = false,
|
||||
this.isRefreshing = false,
|
||||
this.onChanged,
|
||||
@@ -31,6 +33,13 @@ class _FeatureToggleRow extends State<FeatureToggleRow> {
|
||||
Widget build(BuildContext context) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
final textTheme = Theme.of(context).textTheme;
|
||||
final isEnabled = widget.enabled;
|
||||
final titleColor = isEnabled
|
||||
? scheme.onSurface
|
||||
: scheme.onSurfaceVariant.withValues(alpha: 0.7);
|
||||
final subtitleColor = isEnabled
|
||||
? scheme.onSurfaceVariant
|
||||
: scheme.onSurfaceVariant.withValues(alpha: 0.55);
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
|
||||
@@ -44,14 +53,13 @@ class _FeatureToggleRow extends State<FeatureToggleRow> {
|
||||
widget.title,
|
||||
style: textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: titleColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
widget.subtitle,
|
||||
style: textTheme.bodySmall?.copyWith(
|
||||
color: scheme.onSurfaceVariant,
|
||||
),
|
||||
style: textTheme.bodySmall?.copyWith(color: subtitleColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -60,7 +68,18 @@ class _FeatureToggleRow extends State<FeatureToggleRow> {
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Switch(value: widget.value, onChanged: widget.onChanged),
|
||||
Switch(
|
||||
value: widget.value,
|
||||
onChanged: isEnabled ? widget.onChanged : null,
|
||||
thumbColor: !isEnabled
|
||||
? WidgetStatePropertyAll<Color?>(scheme.onSurfaceVariant)
|
||||
: null,
|
||||
trackColor: !isEnabled
|
||||
? WidgetStatePropertyAll<Color?>(
|
||||
scheme.onSurfaceVariant.withValues(alpha: 0.35),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
if (widget.hasRefreshing) ...[
|
||||
const SizedBox(width: 4),
|
||||
widget.isRefreshing
|
||||
@@ -74,7 +93,7 @@ class _FeatureToggleRow extends State<FeatureToggleRow> {
|
||||
)
|
||||
: IconButton(
|
||||
icon: const Icon(Icons.refresh, size: 18),
|
||||
onPressed: widget.onRefresh,
|
||||
onPressed: isEnabled ? widget.onRefresh : null,
|
||||
tooltip: widget.refreshTooltip,
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: EdgeInsets.zero,
|
||||
|
||||
@@ -26,9 +26,16 @@ class QuickSwitchBar extends StatelessWidget {
|
||||
final colorScheme = theme.colorScheme;
|
||||
final labelStyle = theme.textTheme.labelMedium ?? const TextStyle();
|
||||
final background = highContrast ? MapPalette.panelDark : Colors.transparent;
|
||||
final selectedColor = highContrast
|
||||
// The selected icon sits on the primary indicator pill, so it uses
|
||||
// onPrimary. The label sits below on the bar background, so it must use a
|
||||
// foreground color that contrasts with the surface (not onPrimary, which
|
||||
// is white-on-white in the light theme).
|
||||
final selectedIconColor = highContrast
|
||||
? MapPalette.textPrimary
|
||||
: colorScheme.onPrimary;
|
||||
final selectedLabelColor = highContrast
|
||||
? MapPalette.textPrimary
|
||||
: colorScheme.onSurface;
|
||||
final unselectedColor = highContrast
|
||||
? MapPalette.textSecondary
|
||||
: colorScheme.onSurfaceVariant;
|
||||
@@ -59,13 +66,13 @@ class QuickSwitchBar extends StatelessWidget {
|
||||
final isSelected = states.contains(WidgetState.selected);
|
||||
return labelStyle.copyWith(
|
||||
fontWeight: isSelected ? FontWeight.w700 : FontWeight.w500,
|
||||
color: isSelected ? selectedColor : unselectedColor,
|
||||
color: isSelected ? selectedLabelColor : unselectedColor,
|
||||
);
|
||||
}),
|
||||
iconTheme: WidgetStateProperty.resolveWith((states) {
|
||||
final isSelected = states.contains(WidgetState.selected);
|
||||
return IconThemeData(
|
||||
color: isSelected ? selectedColor : unselectedColor,
|
||||
color: isSelected ? selectedIconColor : unselectedColor,
|
||||
);
|
||||
}),
|
||||
),
|
||||
|
||||
@@ -11,7 +11,6 @@ import '../models/app_settings.dart';
|
||||
import '../models/contact.dart';
|
||||
import '../services/app_settings_service.dart';
|
||||
import '../services/map_tile_cache_service.dart';
|
||||
import 'themed_map_tile_layer.dart';
|
||||
|
||||
class TelemetryLocationMap extends StatefulWidget {
|
||||
final double latitude;
|
||||
@@ -115,7 +114,7 @@ class _TelemetryLocationMapState extends State<TelemetryLocationMap> {
|
||||
),
|
||||
),
|
||||
children: [
|
||||
ThemedMapTileLayer(tileCache: tileCache),
|
||||
tileCache.buildTileLayer(context),
|
||||
MarkerLayer(
|
||||
markers: [
|
||||
...contacts.map(_buildContactMarker),
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
|
||||
import '../services/map_tile_cache_service.dart';
|
||||
|
||||
/// Shared cached map tiles with an automatic dark-mode treatment.
|
||||
///
|
||||
/// The dark style transforms the existing OpenStreetMap raster tiles, so light
|
||||
/// and dark maps share the same offline cache and network requests.
|
||||
class ThemedMapTileLayer extends StatelessWidget {
|
||||
final MapTileCacheService tileCache;
|
||||
final double opacity;
|
||||
|
||||
const ThemedMapTileLayer({
|
||||
super.key,
|
||||
required this.tileCache,
|
||||
this.opacity = 1,
|
||||
});
|
||||
|
||||
static const ColorFilter _darkMapFilter = ColorFilter.matrix([
|
||||
-0.0850,
|
||||
-0.2861,
|
||||
-0.0289,
|
||||
0,
|
||||
120,
|
||||
-0.0957,
|
||||
-0.3218,
|
||||
-0.0325,
|
||||
0,
|
||||
140,
|
||||
-0.1169,
|
||||
-0.3934,
|
||||
-0.0397,
|
||||
0,
|
||||
170,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget layer = TileLayer(
|
||||
urlTemplate: kMapTileUrlTemplate,
|
||||
tileProvider: tileCache.tileProvider,
|
||||
userAgentPackageName: MapTileCacheService.userAgentPackageName,
|
||||
maxZoom: 19,
|
||||
);
|
||||
|
||||
if (Theme.of(context).brightness == Brightness.dark) {
|
||||
layer = ColorFiltered(colorFilter: _darkMapFilter, child: layer);
|
||||
}
|
||||
if (opacity < 1) {
|
||||
layer = Opacity(opacity: opacity, child: layer);
|
||||
}
|
||||
return layer;
|
||||
}
|
||||
}
|
||||
@@ -11,18 +11,19 @@ class UnreadBadge extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final display = count > 9999 ? '9999+' : count.toString();
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 2),
|
||||
constraints: const BoxConstraints(minWidth: 20),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: MeshPalette.blue.withValues(alpha: 0.18),
|
||||
color: MeshPalette.alert,
|
||||
borderRadius: BorderRadius.circular(MeshRadii.pill),
|
||||
border: Border.all(color: MeshPalette.blue.withValues(alpha: 0.45)),
|
||||
),
|
||||
child: Text(
|
||||
display,
|
||||
style: MeshTheme.mono(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: MeshPalette.blue,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user