mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-07-10 02:32:47 +10:00
Ran flutter format on the file
This commit is contained in:
+201
-120
@@ -100,10 +100,12 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
final highlightPosition = widget.highlightPosition;
|
final highlightPosition = widget.highlightPosition;
|
||||||
final sharedMarkers = settings.mapShowMarkers
|
final sharedMarkers = settings.mapShowMarkers
|
||||||
? _collectSharedMarkers(connector)
|
? _collectSharedMarkers(connector)
|
||||||
.where((marker) =>
|
.where(
|
||||||
!_hiddenMarkerIds.contains(marker.id) &&
|
(marker) =>
|
||||||
!_removedMarkerIds.contains(marker.id))
|
!_hiddenMarkerIds.contains(marker.id) &&
|
||||||
.toList()
|
!_removedMarkerIds.contains(marker.id),
|
||||||
|
)
|
||||||
|
.toList()
|
||||||
: <_SharedMarker>[];
|
: <_SharedMarker>[];
|
||||||
|
|
||||||
// Filter by time
|
// Filter by time
|
||||||
@@ -111,16 +113,18 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
final filteredByTime = settings.mapTimeFilterHours == 0
|
final filteredByTime = settings.mapTimeFilterHours == 0
|
||||||
? contacts
|
? contacts
|
||||||
: contacts.where((c) {
|
: contacts.where((c) {
|
||||||
final hoursSinceLastSeen =
|
final hoursSinceLastSeen = now.difference(c.lastSeen).inHours;
|
||||||
now.difference(c.lastSeen).inHours;
|
|
||||||
return hoursSinceLastSeen <= settings.mapTimeFilterHours;
|
return hoursSinceLastSeen <= settings.mapTimeFilterHours;
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
// Filter by key prefix
|
// Filter by key prefix
|
||||||
final keyPrefix = settings.mapKeyPrefix.trim();
|
final keyPrefix = settings.mapKeyPrefix.trim();
|
||||||
final filteredByKeyPrefix = (settings.mapKeyPrefixEnabled && keyPrefix.isNotEmpty)
|
final filteredByKeyPrefix =
|
||||||
|
(settings.mapKeyPrefixEnabled && keyPrefix.isNotEmpty)
|
||||||
? filteredByTime.where((c) {
|
? filteredByTime.where((c) {
|
||||||
return c.publicKeyHex.toLowerCase().startsWith(keyPrefix.toLowerCase());
|
return c.publicKeyHex.toLowerCase().startsWith(
|
||||||
|
keyPrefix.toLowerCase(),
|
||||||
|
);
|
||||||
}).toList()
|
}).toList()
|
||||||
: filteredByTime;
|
: filteredByTime;
|
||||||
|
|
||||||
@@ -131,7 +135,8 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
|
|
||||||
// Calculate center of all nodes, or default to (0, 0)
|
// Calculate center of all nodes, or default to (0, 0)
|
||||||
LatLng center = const LatLng(0, 0);
|
LatLng center = const LatLng(0, 0);
|
||||||
final hasMapContent = contactsWithLocation.isNotEmpty ||
|
final hasMapContent =
|
||||||
|
contactsWithLocation.isNotEmpty ||
|
||||||
sharedMarkers.isNotEmpty ||
|
sharedMarkers.isNotEmpty ||
|
||||||
_isSelectingPoi ||
|
_isSelectingPoi ||
|
||||||
highlightPosition != null;
|
highlightPosition != null;
|
||||||
@@ -139,7 +144,9 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
double avgLat = 0.0;
|
double avgLat = 0.0;
|
||||||
double avgLon = 0.0;
|
double avgLon = 0.0;
|
||||||
final allPoints = [
|
final allPoints = [
|
||||||
...contactsWithLocation.map((c) => LatLng(c.latitude!, c.longitude!)),
|
...contactsWithLocation.map(
|
||||||
|
(c) => LatLng(c.latitude!, c.longitude!),
|
||||||
|
),
|
||||||
...sharedMarkers.map((m) => m.position),
|
...sharedMarkers.map((m) => m.position),
|
||||||
];
|
];
|
||||||
if (allPoints.length >= 3) {
|
if (allPoints.length >= 3) {
|
||||||
@@ -149,14 +156,30 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
final latStdDev = _standardDeviation(latValues);
|
final latStdDev = _standardDeviation(latValues);
|
||||||
final lonStdDev = _standardDeviation(lonValues);
|
final lonStdDev = _standardDeviation(lonValues);
|
||||||
final filteredLatValues = latValues
|
final filteredLatValues = latValues
|
||||||
.where((lat) => (lat - (latValues.reduce((a, b) => a + b) / latValues.length)).abs() <= latStdDev * 2)
|
.where(
|
||||||
|
(lat) =>
|
||||||
|
(lat -
|
||||||
|
(latValues.reduce((a, b) => a + b) /
|
||||||
|
latValues.length))
|
||||||
|
.abs() <=
|
||||||
|
latStdDev * 2,
|
||||||
|
)
|
||||||
.toList();
|
.toList();
|
||||||
final filteredLonValues = lonValues
|
final filteredLonValues = lonValues
|
||||||
.where((lon) => (lon - (lonValues.reduce((a, b) => a + b) / lonValues.length)).abs() <= lonStdDev * 2)
|
.where(
|
||||||
|
(lon) =>
|
||||||
|
(lon -
|
||||||
|
(lonValues.reduce((a, b) => a + b) /
|
||||||
|
lonValues.length))
|
||||||
|
.abs() <=
|
||||||
|
lonStdDev * 2,
|
||||||
|
)
|
||||||
.toList();
|
.toList();
|
||||||
center = LatLng(
|
center = LatLng(
|
||||||
filteredLatValues.reduce((a, b) => a + b) / filteredLatValues.length,
|
filteredLatValues.reduce((a, b) => a + b) /
|
||||||
filteredLonValues.reduce((a, b) => a + b) / filteredLonValues.length,
|
filteredLatValues.length,
|
||||||
|
filteredLonValues.reduce((a, b) => a + b) /
|
||||||
|
filteredLonValues.length,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
for (final point in allPoints) {
|
for (final point in allPoints) {
|
||||||
@@ -194,7 +217,9 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
tooltip: context.l10n.common_settings,
|
tooltip: context.l10n.common_settings,
|
||||||
onPressed: () => Navigator.push(
|
onPressed: () => Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(builder: (context) => const SettingsScreen()),
|
MaterialPageRoute(
|
||||||
|
builder: (context) => const SettingsScreen(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -272,14 +297,18 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
_buildLegend(contactsWithLocation.length, sharedMarkers.length),
|
_buildLegend(
|
||||||
|
contactsWithLocation.length,
|
||||||
|
sharedMarkers.length,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
bottomNavigationBar: SafeArea(
|
bottomNavigationBar: SafeArea(
|
||||||
top: false,
|
top: false,
|
||||||
child: QuickSwitchBar(
|
child: QuickSwitchBar(
|
||||||
selectedIndex: 2,
|
selectedIndex: 2,
|
||||||
onDestinationSelected: (index) => _handleQuickSwitch(index, context),
|
onDestinationSelected: (index) =>
|
||||||
|
_handleQuickSwitch(index, context),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
@@ -297,27 +326,17 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(Icons.location_off, size: 64, color: Colors.grey[400]),
|
||||||
Icons.location_off,
|
|
||||||
size: 64,
|
|
||||||
color: Colors.grey[400],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
context.l10n.map_noNodesWithLocation,
|
context.l10n.map_noNodesWithLocation,
|
||||||
style: TextStyle(
|
style: TextStyle(fontSize: 18, color: Colors.grey[600]),
|
||||||
fontSize: 18,
|
|
||||||
color: Colors.grey[600],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
context.l10n.map_nodesNeedGps,
|
context.l10n.map_nodesNeedGps,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(fontSize: 14, color: Colors.grey[500]),
|
||||||
fontSize: 14,
|
|
||||||
color: Colors.grey[500],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -331,7 +350,8 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
if (!contact.hasLocation) continue;
|
if (!contact.hasLocation) continue;
|
||||||
|
|
||||||
// Apply node type filters
|
// Apply node type filters
|
||||||
if (contact.type == advTypeRepeater && !settings.mapShowRepeaters) continue;
|
if (contact.type == advTypeRepeater && !settings.mapShowRepeaters)
|
||||||
|
continue;
|
||||||
if (contact.type == advTypeChat && !settings.mapShowChatNodes) continue;
|
if (contact.type == advTypeChat && !settings.mapShowChatNodes) continue;
|
||||||
if (contact.type != advTypeChat &&
|
if (contact.type != advTypeChat &&
|
||||||
contact.type != advTypeRepeater &&
|
contact.type != advTypeRepeater &&
|
||||||
@@ -434,13 +454,37 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_buildLegendItem(Icons.person, context.l10n.map_chat, Colors.blue),
|
_buildLegendItem(
|
||||||
_buildLegendItem(Icons.router, context.l10n.map_repeater, Colors.green),
|
Icons.person,
|
||||||
_buildLegendItem(Icons.meeting_room, context.l10n.map_room, Colors.purple),
|
context.l10n.map_chat,
|
||||||
_buildLegendItem(Icons.sensors, context.l10n.map_sensor, Colors.orange),
|
Colors.blue,
|
||||||
|
),
|
||||||
|
_buildLegendItem(
|
||||||
|
Icons.router,
|
||||||
|
context.l10n.map_repeater,
|
||||||
|
Colors.green,
|
||||||
|
),
|
||||||
|
_buildLegendItem(
|
||||||
|
Icons.meeting_room,
|
||||||
|
context.l10n.map_room,
|
||||||
|
Colors.purple,
|
||||||
|
),
|
||||||
|
_buildLegendItem(
|
||||||
|
Icons.sensors,
|
||||||
|
context.l10n.map_sensor,
|
||||||
|
Colors.orange,
|
||||||
|
),
|
||||||
_buildLegendItem(Icons.flag, context.l10n.map_pinDm, Colors.blue),
|
_buildLegendItem(Icons.flag, context.l10n.map_pinDm, Colors.blue),
|
||||||
_buildLegendItem(Icons.flag, context.l10n.map_pinPrivate, Colors.purple),
|
_buildLegendItem(
|
||||||
_buildLegendItem(Icons.flag, context.l10n.map_pinPublic, Colors.orange),
|
Icons.flag,
|
||||||
|
context.l10n.map_pinPrivate,
|
||||||
|
Colors.purple,
|
||||||
|
),
|
||||||
|
_buildLegendItem(
|
||||||
|
Icons.flag,
|
||||||
|
context.l10n.map_pinPublic,
|
||||||
|
Colors.orange,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -456,10 +500,7 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
children: [
|
children: [
|
||||||
Icon(icon, size: 16, color: color),
|
Icon(icon, size: 16, color: color),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(label, style: const TextStyle(fontSize: 12)),
|
||||||
label,
|
|
||||||
style: const TextStyle(fontSize: 12),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -513,7 +554,9 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
label: payload.label,
|
label: payload.label,
|
||||||
flags: payload.flags,
|
flags: payload.flags,
|
||||||
fromName: message.senderName,
|
fromName: message.senderName,
|
||||||
sourceLabel: channel.name.isEmpty ? 'Channel ${channel.index}' : channel.name,
|
sourceLabel: channel.name.isEmpty
|
||||||
|
? 'Channel ${channel.index}'
|
||||||
|
: channel.name,
|
||||||
isChannel: true,
|
isChannel: true,
|
||||||
isPublicChannel: isPublic,
|
isPublicChannel: isPublic,
|
||||||
),
|
),
|
||||||
@@ -579,11 +622,7 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: const Icon(
|
child: const Icon(Icons.flag, color: Colors.white, size: 20),
|
||||||
Icons.flag,
|
|
||||||
color: Colors.white,
|
|
||||||
size: 20,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -601,10 +640,8 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => RepeaterHubScreen(
|
builder: (context) =>
|
||||||
repeater: repeater,
|
RepeaterHubScreen(repeater: repeater, password: password),
|
||||||
password: password,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -622,9 +659,7 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
context.read<MeshCoreConnector>().markContactRead(room.publicKeyHex);
|
context.read<MeshCoreConnector>().markContactRead(room.publicKeyHex);
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(builder: (context) => ChatScreen(contact: room)),
|
||||||
builder: (context) => ChatScreen(contact: room),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -651,9 +686,14 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
children: [
|
children: [
|
||||||
_buildInfoRow('Type', contact.typeLabel),
|
_buildInfoRow('Type', contact.typeLabel),
|
||||||
_buildInfoRow('Path', contact.pathLabel),
|
_buildInfoRow('Path', contact.pathLabel),
|
||||||
_buildInfoRow('Location',
|
_buildInfoRow(
|
||||||
'${contact.latitude!.toStringAsFixed(6)}, ${contact.longitude!.toStringAsFixed(6)}'),
|
'Location',
|
||||||
_buildInfoRow(context.l10n.map_lastSeen, _formatLastSeen(contact.lastSeen)),
|
'${contact.latitude!.toStringAsFixed(6)}, ${contact.longitude!.toStringAsFixed(6)}',
|
||||||
|
),
|
||||||
|
_buildInfoRow(
|
||||||
|
context.l10n.map_lastSeen,
|
||||||
|
_formatLastSeen(contact.lastSeen),
|
||||||
|
),
|
||||||
_buildInfoRow('Public Key', contact.publicKeyHex),
|
_buildInfoRow('Public Key', contact.publicKeyHex),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -662,7 +702,8 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
onPressed: () => Navigator.pop(dialogContext),
|
onPressed: () => Navigator.pop(dialogContext),
|
||||||
child: Text(context.l10n.common_close),
|
child: Text(context.l10n.common_close),
|
||||||
),
|
),
|
||||||
if (contact.type == advTypeChat) // Only show chat button for chat nodes
|
if (contact.type ==
|
||||||
|
advTypeChat) // Only show chat button for chat nodes
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(dialogContext);
|
Navigator.pop(dialogContext);
|
||||||
@@ -675,22 +716,22 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
},
|
},
|
||||||
child: Text(context.l10n.contacts_openChat),
|
child: Text(context.l10n.contacts_openChat),
|
||||||
),
|
),
|
||||||
if (contact.type == advTypeRepeater)
|
if (contact.type == advTypeRepeater)
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(dialogContext);
|
Navigator.pop(dialogContext);
|
||||||
_showRepeaterLogin(context, contact);
|
_showRepeaterLogin(context, contact);
|
||||||
},
|
},
|
||||||
child: Text(context.l10n.map_manageRepeater),
|
child: Text(context.l10n.map_manageRepeater),
|
||||||
),
|
),
|
||||||
if (contact.type == advTypeRoom)
|
if (contact.type == advTypeRoom)
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(dialogContext);
|
Navigator.pop(dialogContext);
|
||||||
_showRoomLogin(context, contact);
|
_showRoomLogin(context, contact);
|
||||||
},
|
},
|
||||||
child: Text(context.l10n.map_joinRoom),
|
child: Text(context.l10n.map_joinRoom),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -702,17 +743,13 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
case 0:
|
case 0:
|
||||||
Navigator.pushReplacement(
|
Navigator.pushReplacement(
|
||||||
context,
|
context,
|
||||||
buildQuickSwitchRoute(
|
buildQuickSwitchRoute(const ContactsScreen(hideBackButton: true)),
|
||||||
const ContactsScreen(hideBackButton: true),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
Navigator.pushReplacement(
|
Navigator.pushReplacement(
|
||||||
context,
|
context,
|
||||||
buildQuickSwitchRoute(
|
buildQuickSwitchRoute(const ChannelsScreen(hideBackButton: true)),
|
||||||
const ChannelsScreen(hideBackButton: true),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -760,7 +797,8 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
'Location',
|
'Location',
|
||||||
'${marker.position.latitude.toStringAsFixed(6)}, ${marker.position.longitude.toStringAsFixed(6)}',
|
'${marker.position.latitude.toStringAsFixed(6)}, ${marker.position.longitude.toStringAsFixed(6)}',
|
||||||
),
|
),
|
||||||
if (marker.flags.isNotEmpty) _buildInfoRow(context.l10n.map_flags, marker.flags),
|
if (marker.flags.isNotEmpty)
|
||||||
|
_buildInfoRow(context.l10n.map_flags, marker.flags),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
@@ -810,10 +848,7 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
Text(
|
Text(value, style: const TextStyle(fontSize: 14)),
|
||||||
value,
|
|
||||||
style: const TextStyle(fontSize: 14),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -898,7 +933,10 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String?> _promptForLabel(BuildContext context, String defaultLabel) async {
|
Future<String?> _promptForLabel(
|
||||||
|
BuildContext context,
|
||||||
|
String defaultLabel,
|
||||||
|
) async {
|
||||||
final controller = TextEditingController(text: defaultLabel);
|
final controller = TextEditingController(text: defaultLabel);
|
||||||
return showDialog<String>(
|
return showDialog<String>(
|
||||||
context: context,
|
context: context,
|
||||||
@@ -919,7 +957,10 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
final label = controller.text.trim().replaceAll('|', '/');
|
final label = controller.text.trim().replaceAll('|', '/');
|
||||||
Navigator.pop(dialogContext, label.isEmpty ? defaultLabel : label);
|
Navigator.pop(
|
||||||
|
dialogContext,
|
||||||
|
label.isEmpty ? defaultLabel : label,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
child: Text(context.l10n.common_continue),
|
child: Text(context.l10n.common_continue),
|
||||||
),
|
),
|
||||||
@@ -951,8 +992,11 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
return Consumer<MeshCoreConnector>(
|
return Consumer<MeshCoreConnector>(
|
||||||
builder: (consumerContext, liveConnector, child) {
|
builder: (consumerContext, liveConnector, child) {
|
||||||
final allContacts = liveConnector.contacts
|
final allContacts = liveConnector.contacts
|
||||||
.where((contact) =>
|
.where(
|
||||||
contact.type != advTypeRepeater && contact.type != advTypeRoom)
|
(contact) =>
|
||||||
|
contact.type != advTypeRepeater &&
|
||||||
|
contact.type != advTypeRoom,
|
||||||
|
)
|
||||||
.toList();
|
.toList();
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
@@ -962,7 +1006,10 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 4),
|
padding: const EdgeInsets.fromLTRB(16, 12, 16, 4),
|
||||||
child: Text(context.l10n.map_sendToContact, style: const TextStyle(fontWeight: FontWeight.bold)),
|
child: Text(
|
||||||
|
context.l10n.map_sendToContact,
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(16, 4, 16, 8),
|
padding: const EdgeInsets.fromLTRB(16, 4, 16, 8),
|
||||||
@@ -973,7 +1020,10 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 16,
|
||||||
|
vertical: 12,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setSheetState(() {
|
setSheetState(() {
|
||||||
@@ -983,50 +1033,73 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
...allContacts
|
...allContacts
|
||||||
.where((contact) =>
|
.where(
|
||||||
query.isEmpty || matchesContactQuery(contact, query))
|
(contact) =>
|
||||||
|
query.isEmpty ||
|
||||||
|
matchesContactQuery(contact, query),
|
||||||
|
)
|
||||||
.map((contact) {
|
.map((contact) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: const Icon(Icons.person),
|
leading: const Icon(Icons.person),
|
||||||
title: Text(contact.name),
|
title: Text(contact.name),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.pop(sheetContext);
|
Navigator.pop(sheetContext);
|
||||||
liveConnector.sendMessage(contact, markerText);
|
liveConnector.sendMessage(contact, markerText);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 4),
|
padding: const EdgeInsets.fromLTRB(16, 12, 16, 4),
|
||||||
child: Text(context.l10n.map_sendToChannel, style: const TextStyle(fontWeight: FontWeight.bold)),
|
child: Text(
|
||||||
|
context.l10n.map_sendToChannel,
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
if (liveConnector.isLoadingChannels)
|
if (liveConnector.isLoadingChannels)
|
||||||
const Padding(
|
const Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 16,
|
||||||
|
vertical: 8,
|
||||||
|
),
|
||||||
child: LinearProgressIndicator(),
|
child: LinearProgressIndicator(),
|
||||||
)
|
)
|
||||||
else if (liveConnector.channels.where((c) => !c.isEmpty).isEmpty)
|
else if (liveConnector.channels
|
||||||
|
.where((c) => !c.isEmpty)
|
||||||
|
.isEmpty)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 16,
|
||||||
|
vertical: 8,
|
||||||
|
),
|
||||||
child: Text(context.l10n.map_noChannelsAvailable),
|
child: Text(context.l10n.map_noChannelsAvailable),
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
...liveConnector.channels.where((c) => !c.isEmpty).map((channel) {
|
...liveConnector.channels.where((c) => !c.isEmpty).map((
|
||||||
|
channel,
|
||||||
|
) {
|
||||||
final isPublic = _isPublicChannel(channel);
|
final isPublic = _isPublicChannel(channel);
|
||||||
final label = channel.name.isEmpty ? 'Channel ${channel.index}' : channel.name;
|
final label = channel.name.isEmpty
|
||||||
|
? 'Channel ${channel.index}'
|
||||||
|
: channel.name;
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: Icon(
|
leading: Icon(
|
||||||
isPublic ? Icons.public : Icons.tag,
|
isPublic ? Icons.public : Icons.tag,
|
||||||
color: isPublic ? Colors.orange : Colors.blue,
|
color: isPublic ? Colors.orange : Colors.blue,
|
||||||
),
|
),
|
||||||
title: Text(label),
|
title: Text(label),
|
||||||
subtitle: isPublic ? Text(context.l10n.channels_publicChannel) : null,
|
subtitle: isPublic
|
||||||
|
? Text(context.l10n.channels_publicChannel)
|
||||||
|
: null,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
Navigator.pop(sheetContext);
|
Navigator.pop(sheetContext);
|
||||||
final canSend = isPublic
|
final canSend = isPublic
|
||||||
? await _confirmPublicShare(context, label)
|
? await _confirmPublicShare(context, label)
|
||||||
: true;
|
: true;
|
||||||
if (canSend) {
|
if (canSend) {
|
||||||
liveConnector.sendChannelMessage(channel, markerText);
|
liveConnector.sendChannelMessage(
|
||||||
|
channel,
|
||||||
|
markerText,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -1046,12 +1119,17 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
return channel.isPublicChannel;
|
return channel.isPublicChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> _confirmPublicShare(BuildContext context, String channelLabel) async {
|
Future<bool> _confirmPublicShare(
|
||||||
|
BuildContext context,
|
||||||
|
String channelLabel,
|
||||||
|
) async {
|
||||||
final result = await showDialog<bool>(
|
final result = await showDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (dialogContext) => AlertDialog(
|
builder: (dialogContext) => AlertDialog(
|
||||||
title: Text(context.l10n.map_publicLocationShare),
|
title: Text(context.l10n.map_publicLocationShare),
|
||||||
content: Text(context.l10n.map_publicLocationShareConfirm(channelLabel)),
|
content: Text(
|
||||||
|
context.l10n.map_publicLocationShareConfirm(channelLabel),
|
||||||
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(dialogContext, false),
|
onPressed: () => Navigator.pop(dialogContext, false),
|
||||||
@@ -1067,7 +1145,10 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
return result ?? false;
|
return result ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showFilterDialog(BuildContext context, AppSettingsService settingsService) {
|
void _showFilterDialog(
|
||||||
|
BuildContext context,
|
||||||
|
AppSettingsService settingsService,
|
||||||
|
) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (dialogContext) => AlertDialog(
|
builder: (dialogContext) => AlertDialog(
|
||||||
@@ -1171,10 +1252,7 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
_getTimeFilterLabel(settings.mapTimeFilterHours),
|
_getTimeFilterLabel(settings.mapTimeFilterHours),
|
||||||
style: TextStyle(
|
style: TextStyle(fontSize: 14, color: Colors.grey[700]),
|
||||||
fontSize: 14,
|
|
||||||
color: Colors.grey[700],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Slider(
|
Slider(
|
||||||
value: _hoursToSliderValue(settings.mapTimeFilterHours),
|
value: _hoursToSliderValue(settings.mapTimeFilterHours),
|
||||||
@@ -1214,11 +1292,14 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
|
|
||||||
if (hours <= 24) {
|
if (hours <= 24) {
|
||||||
return (hours / 24) * 40;
|
return (hours / 24) * 40;
|
||||||
} else if (hours <= 168) { // 7 days
|
} else if (hours <= 168) {
|
||||||
|
// 7 days
|
||||||
return 40 + ((hours - 24) / (168 - 24)) * 20;
|
return 40 + ((hours - 24) / (168 - 24)) * 20;
|
||||||
} else if (hours <= 720) { // 30 days
|
} else if (hours <= 720) {
|
||||||
|
// 30 days
|
||||||
return 60 + ((hours - 168) / (720 - 168)) * 20;
|
return 60 + ((hours - 168) / (720 - 168)) * 20;
|
||||||
} else if (hours <= 4380) { // 6 months
|
} else if (hours <= 4380) {
|
||||||
|
// 6 months
|
||||||
return 80 + ((hours - 720) / (4380 - 720)) * 19;
|
return 80 + ((hours - 720) / (4380 - 720)) * 19;
|
||||||
} else {
|
} else {
|
||||||
return 100;
|
return 100;
|
||||||
|
|||||||
Reference in New Issue
Block a user