feat: Add GPS toggle and node sorting

This commit is contained in:
Janez T
2026-03-17 09:30:36 +01:00
parent 59f6df4260
commit cd165d2372
3 changed files with 126 additions and 17 deletions

View File

@@ -0,0 +1,48 @@
import 'package:geolocator/geolocator.dart';
import 'package:latlong2/latlong.dart';
import '../models/contact.dart';
class RelayCandidateSorter {
const RelayCandidateSorter();
List<Contact> sortByDistanceFromSelf(
List<Contact> contacts, {
required LatLng? selfPoint,
}) {
final sorted = List<Contact>.from(contacts);
sorted.sort((a, b) {
if (selfPoint != null) {
final distanceCompare = _distanceFrom(
selfPoint,
a,
).compareTo(_distanceFrom(selfPoint, b));
if (distanceCompare != 0) {
return distanceCompare;
}
}
final nameCompare = a.displayName.compareTo(b.displayName);
if (nameCompare != 0) {
return nameCompare;
}
return a.publicKeyHex.compareTo(b.publicKeyHex);
});
return sorted;
}
double _distanceFrom(LatLng selfPoint, Contact contact) {
final location = contact.displayLocation;
if (location == null) {
return double.infinity;
}
return Geolocator.distanceBetween(
selfPoint.latitude,
selfPoint.longitude,
location.latitude,
location.longitude,
);
}
}

View File

@@ -11,6 +11,7 @@ import '../../providers/app_provider.dart';
import '../../providers/connection_provider.dart';
import '../../services/contact_route_resolver.dart';
import '../../services/path_history_service.dart';
import '../../services/relay_candidate_sorter.dart';
import '../../services/route_hash_preferences.dart';
class ContactRouteDialogResult {
@@ -72,6 +73,8 @@ class _ContactRouteDialogState extends State<ContactRouteDialog> {
late final TextEditingController _controller;
late final TextEditingController _relaySearchController;
final PathHistoryService _pathHistoryService = PathHistoryService();
final RelayCandidateSorter _relayCandidateSorter =
const RelayCandidateSorter();
int _selectedHashSize = RouteHashPreferences.defaultHashSize;
ParsedContactRoute? _parsedRoute;
String? _errorText;
@@ -133,13 +136,16 @@ class _ContactRouteDialogState extends State<ContactRouteDialog> {
}
}
List<Contact> get _routeCandidates =>
widget.availableContacts
.where(
(contact) => contact.isRepeater && contact.displayLocation != null,
)
.toList()
..sort((a, b) => a.displayName.compareTo(b.displayName));
List<Contact> _routeCandidates({required LatLng? selfPoint}) =>
_relayCandidateSorter.sortByDistanceFromSelf(
widget.availableContacts
.where(
(contact) =>
contact.isRepeater && contact.displayLocation != null,
)
.toList(),
selfPoint: selfPoint,
);
List<Contact> _mapSelectionForText(String text) {
final tokens = text
@@ -169,7 +175,8 @@ class _ContactRouteDialogState extends State<ContactRouteDialog> {
final contactHashSize = widget.contact.hasPath
? widget.contact.pathHashSize
: null;
final hashSize = contactHashSize ?? await RouteHashPreferences.getHashSize();
final hashSize =
contactHashSize ?? await RouteHashPreferences.getHashSize();
if (!mounted) return;
setState(() {
_selectedHashSize = hashSize;
@@ -697,18 +704,12 @@ class _ContactRouteDialogState extends State<ContactRouteDialog> {
children: [
Row(
children: [
Text(
'Path Size',
style: Theme.of(context).textTheme.labelLarge,
),
Text('Path Size', style: Theme.of(context).textTheme.labelLarge),
const Spacer(),
SegmentedButton<int>(
segments: [
for (final size in RouteHashPreferences.supportedSizes)
ButtonSegment<int>(
value: size,
label: Text('${size}B'),
),
ButtonSegment<int>(value: size, label: Text('${size}B')),
],
selected: {_selectedHashSize},
onSelectionChanged: (selection) {
@@ -822,7 +823,6 @@ class _ContactRouteDialogState extends State<ContactRouteDialog> {
@override
Widget build(BuildContext context) {
final appProvider = context.watch<AppProvider>();
final routeCandidates = _routeCandidates;
final connectionProvider = context.watch<ConnectionProvider>();
final selfPoint =
connectionProvider.deviceInfo.advLat != null &&
@@ -834,6 +834,7 @@ class _ContactRouteDialogState extends State<ContactRouteDialog> {
connectionProvider.deviceInfo.advLon! / 1e6,
)
: null;
final routeCandidates = _routeCandidates(selfPoint: selfPoint);
final recipientLocation = widget.contact.displayLocation;
final recipientPoint = recipientLocation == null
? null