|
|
|
@ -480,12 +480,14 @@ class _MapScreenState extends State<MapScreen> {
|
|
|
|
point: highlightPosition,
|
|
|
|
point: highlightPosition,
|
|
|
|
width: 40,
|
|
|
|
width: 40,
|
|
|
|
height: 40,
|
|
|
|
height: 40,
|
|
|
|
|
|
|
|
child: IgnorePointer(
|
|
|
|
child: Icon(
|
|
|
|
child: Icon(
|
|
|
|
Icons.location_on_outlined,
|
|
|
|
Icons.location_on_outlined,
|
|
|
|
color: Colors.red[600],
|
|
|
|
color: Colors.red[600],
|
|
|
|
size: 34,
|
|
|
|
size: 34,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
if (!_isBuildingPathTrace)
|
|
|
|
if (!_isBuildingPathTrace)
|
|
|
|
..._buildGuessedMarker(
|
|
|
|
..._buildGuessedMarker(
|
|
|
|
guessedLocations,
|
|
|
|
guessedLocations,
|
|
|
|
@ -506,6 +508,8 @@ class _MapScreenState extends State<MapScreen> {
|
|
|
|
),
|
|
|
|
),
|
|
|
|
width: 40,
|
|
|
|
width: 40,
|
|
|
|
height: 40,
|
|
|
|
height: 40,
|
|
|
|
|
|
|
|
child: IgnorePointer(
|
|
|
|
|
|
|
|
ignoring: true,
|
|
|
|
child: Container(
|
|
|
|
child: Container(
|
|
|
|
padding: const EdgeInsets.all(4),
|
|
|
|
padding: const EdgeInsets.all(4),
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
@ -517,7 +521,9 @@ class _MapScreenState extends State<MapScreen> {
|
|
|
|
),
|
|
|
|
),
|
|
|
|
boxShadow: [
|
|
|
|
boxShadow: [
|
|
|
|
BoxShadow(
|
|
|
|
BoxShadow(
|
|
|
|
color: Colors.black.withValues(alpha: 0.3),
|
|
|
|
color: Colors.black.withValues(
|
|
|
|
|
|
|
|
alpha: 0.3,
|
|
|
|
|
|
|
|
),
|
|
|
|
blurRadius: 4,
|
|
|
|
blurRadius: 4,
|
|
|
|
offset: const Offset(0, 2),
|
|
|
|
offset: const Offset(0, 2),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
@ -531,6 +537,7 @@ class _MapScreenState extends State<MapScreen> {
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
if (_showNodeLabels &&
|
|
|
|
if (_showNodeLabels &&
|
|
|
|
connector.selfLatitude != null &&
|
|
|
|
connector.selfLatitude != null &&
|
|
|
|
connector.selfLongitude != null)
|
|
|
|
connector.selfLongitude != null)
|
|
|
|
@ -547,6 +554,7 @@ class _MapScreenState extends State<MapScreen> {
|
|
|
|
),
|
|
|
|
),
|
|
|
|
if (!_isBuildingPathTrace)
|
|
|
|
if (!_isBuildingPathTrace)
|
|
|
|
_buildLegend(
|
|
|
|
_buildLegend(
|
|
|
|
|
|
|
|
contacts,
|
|
|
|
contactsWithLocation,
|
|
|
|
contactsWithLocation,
|
|
|
|
settings,
|
|
|
|
settings,
|
|
|
|
sharedMarkers.length,
|
|
|
|
sharedMarkers.length,
|
|
|
|
@ -832,13 +840,16 @@ class _MapScreenState extends State<MapScreen> {
|
|
|
|
|
|
|
|
|
|
|
|
List<Contact> _filterContactsBySettings(
|
|
|
|
List<Contact> _filterContactsBySettings(
|
|
|
|
List<Contact> contacts,
|
|
|
|
List<Contact> contacts,
|
|
|
|
dynamic settings,
|
|
|
|
dynamic settings, {
|
|
|
|
) {
|
|
|
|
bool noLocations = false,
|
|
|
|
|
|
|
|
}) {
|
|
|
|
List<Contact> filtered = [];
|
|
|
|
List<Contact> filtered = [];
|
|
|
|
bool addContact = false;
|
|
|
|
bool addContact = false;
|
|
|
|
for (final contact in contacts) {
|
|
|
|
for (final contact in contacts) {
|
|
|
|
addContact = false;
|
|
|
|
addContact = false;
|
|
|
|
if (!contact.hasLocation) continue;
|
|
|
|
if (!contact.hasLocation && !noLocations) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Apply node type filters
|
|
|
|
// Apply node type filters
|
|
|
|
if (contact.type == advTypeRepeater &&
|
|
|
|
if (contact.type == advTypeRepeater &&
|
|
|
|
@ -1012,17 +1023,25 @@ class _MapScreenState extends State<MapScreen> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Widget _buildLegend(
|
|
|
|
Widget _buildLegend(
|
|
|
|
|
|
|
|
List<Contact> contacts,
|
|
|
|
List<Contact> contactsWithLocation,
|
|
|
|
List<Contact> contactsWithLocation,
|
|
|
|
settings,
|
|
|
|
settings,
|
|
|
|
int markerCount,
|
|
|
|
int markerCount,
|
|
|
|
int guessedCount,
|
|
|
|
int guessedCount,
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
final filteredContacts = _filterContactsBySettings(
|
|
|
|
final filteredContacts = _filterContactsBySettings(
|
|
|
|
contactsWithLocation,
|
|
|
|
contacts,
|
|
|
|
settings,
|
|
|
|
settings,
|
|
|
|
|
|
|
|
noLocations: false,
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
final filteredContactsAll = _filterContactsBySettings(
|
|
|
|
|
|
|
|
contacts,
|
|
|
|
|
|
|
|
settings,
|
|
|
|
|
|
|
|
noLocations: true,
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
final nodeCount = filteredContacts.length;
|
|
|
|
final nodeCount = filteredContacts.length;
|
|
|
|
|
|
|
|
final nodeCountAll = filteredContactsAll.length;
|
|
|
|
|
|
|
|
|
|
|
|
return Positioned(
|
|
|
|
return Positioned(
|
|
|
|
top: 16,
|
|
|
|
top: 16,
|
|
|
|
@ -1058,6 +1077,54 @@ class _MapScreenState extends State<MapScreen> {
|
|
|
|
fontSize: 14,
|
|
|
|
fontSize: 14,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
|
|
|
|
Row(
|
|
|
|
|
|
|
|
children: [
|
|
|
|
|
|
|
|
Icon(
|
|
|
|
|
|
|
|
Icons.location_on,
|
|
|
|
|
|
|
|
size: 16,
|
|
|
|
|
|
|
|
color: Colors.grey,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
Text(
|
|
|
|
|
|
|
|
": $nodeCount",
|
|
|
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
Row(
|
|
|
|
|
|
|
|
children: [
|
|
|
|
|
|
|
|
const Icon(
|
|
|
|
|
|
|
|
Icons.wrong_location,
|
|
|
|
|
|
|
|
size: 16,
|
|
|
|
|
|
|
|
color: Colors.grey,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
Text(
|
|
|
|
|
|
|
|
": ${nodeCountAll - nodeCount}",
|
|
|
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
Row(
|
|
|
|
|
|
|
|
children: [
|
|
|
|
|
|
|
|
const Icon(
|
|
|
|
|
|
|
|
Icons.add_outlined,
|
|
|
|
|
|
|
|
size: 16,
|
|
|
|
|
|
|
|
color: Colors.grey,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
Text(
|
|
|
|
|
|
|
|
": $nodeCountAll",
|
|
|
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
),
|
|
|
|
Text(
|
|
|
|
Text(
|
|
|
|
context.l10n.map_pinsCount(markerCount),
|
|
|
|
context.l10n.map_pinsCount(markerCount),
|
|
|
|
style: const TextStyle(
|
|
|
|
style: const TextStyle(
|
|
|
|
@ -2137,7 +2204,7 @@ class _MapScreenState extends State<MapScreen> {
|
|
|
|
_isBuildingPathTrace = false;
|
|
|
|
_isBuildingPathTrace = false;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
},
|
|
|
|
tooltip: "Path Trace",
|
|
|
|
tooltip: l10n.map_runTrace,
|
|
|
|
icon: const Icon(Icons.arrow_forward_outlined),
|
|
|
|
icon: const Icon(Icons.arrow_forward_outlined),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
if (_pathTrace.isNotEmpty)
|
|
|
|
if (_pathTrace.isNotEmpty)
|
|
|
|
@ -2157,14 +2224,14 @@ class _MapScreenState extends State<MapScreen> {
|
|
|
|
_isBuildingPathTrace = false;
|
|
|
|
_isBuildingPathTrace = false;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
},
|
|
|
|
tooltip: "Build Return Path",
|
|
|
|
tooltip: l10n.map_runTraceWithReturnPath,
|
|
|
|
icon: const Icon(Icons.replay),
|
|
|
|
icon: const Icon(Icons.replay),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
if (_pathTrace.isNotEmpty)
|
|
|
|
if (_pathTrace.isNotEmpty)
|
|
|
|
IconButton(
|
|
|
|
IconButton(
|
|
|
|
onPressed: _removePath,
|
|
|
|
onPressed: _removePath,
|
|
|
|
tooltip: "Remove Last Point",
|
|
|
|
tooltip: l10n.map_removeLast,
|
|
|
|
icon: const Icon(Icons.delete),
|
|
|
|
icon: const Icon(Icons.undo),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
if (_pathTrace.isEmpty)
|
|
|
|
if (_pathTrace.isEmpty)
|
|
|
|
IconButton(
|
|
|
|
IconButton(
|
|
|
|
@ -2179,6 +2246,7 @@ class _MapScreenState extends State<MapScreen> {
|
|
|
|
SnackBar(content: Text(l10n.map_pathTraceCancelled)),
|
|
|
|
SnackBar(content: Text(l10n.map_pathTraceCancelled)),
|
|
|
|
);
|
|
|
|
);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
tooltip: l10n.common_cancel,
|
|
|
|
icon: const Icon(Icons.close),
|
|
|
|
icon: const Icon(Icons.close),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
|