mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-07-11 02:57:04 +10:00
Updated to last dev
This commit is contained in:
@@ -3208,10 +3208,7 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
|
|
||||||
if (pathLen != null &&
|
if (pathLen != null &&
|
||||||
pathLen >= 0 &&
|
pathLen >= 0 &&
|
||||||
!_isPathLenValidForCurrentMode(
|
!_isPathLenValidForCurrentMode(pathLen, pathBytes ?? Uint8List(0))) {
|
||||||
pathLen,
|
|
||||||
pathBytes ?? Uint8List(0),
|
|
||||||
)) {
|
|
||||||
appLogger.warn(
|
appLogger.warn(
|
||||||
'setPathOverride: invalid path for ${contact.name}: '
|
'setPathOverride: invalid path for ${contact.name}: '
|
||||||
'pathLen=$pathLen, bytesLen=${pathBytes?.length ?? 0}, '
|
'pathLen=$pathLen, bytesLen=${pathBytes?.length ?? 0}, '
|
||||||
@@ -6694,13 +6691,12 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final pathStartIndex = path.isNotEmpty ? path.length - hashWidth : 0;
|
final pathStartIndex = path.isNotEmpty ? path.length - hashWidth : 0;
|
||||||
final publicKeyPrefixEnd = math.min(hashWidth, contact.publicKey.length).toInt();
|
final publicKeyPrefixEnd = math
|
||||||
|
.min(hashWidth, contact.publicKey.length)
|
||||||
|
.toInt();
|
||||||
final pubkeyPrefix = path.isNotEmpty
|
final pubkeyPrefix = path.isNotEmpty
|
||||||
? path.sublist(pathStartIndex)
|
? path.sublist(pathStartIndex)
|
||||||
: contact.publicKey.sublist(
|
: contact.publicKey.sublist(0, publicKeyPrefixEnd);
|
||||||
0,
|
|
||||||
publicKeyPrefixEnd,
|
|
||||||
);
|
|
||||||
final contactKeyHex = _resolveDirectRepeaterContactKeyHex(
|
final contactKeyHex = _resolveDirectRepeaterContactKeyHex(
|
||||||
contact,
|
contact,
|
||||||
pubkeyPrefix,
|
pubkeyPrefix,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import '../connector/meshcore_protocol.dart';
|
import '../connector/meshcore_protocol.dart';
|
||||||
|
import '../helpers/path_helper.dart';
|
||||||
import '../models/contact.dart';
|
import '../models/contact.dart';
|
||||||
import 'app_localizations.dart';
|
import 'app_localizations.dart';
|
||||||
|
|
||||||
@@ -23,14 +24,30 @@ extension ContactLocalization on Contact {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String pathLabel(AppLocalizations l10n) {
|
String pathLabel(
|
||||||
|
AppLocalizations l10n, {
|
||||||
|
int pathHashByteWidth = pathHashSize,
|
||||||
|
}) {
|
||||||
if (pathOverride != null) {
|
if (pathOverride != null) {
|
||||||
if (pathOverride! < 0) return l10n.chat_floodForced;
|
if (pathOverride! < 0) return l10n.chat_floodForced;
|
||||||
if (pathOverride == 0) return l10n.chat_directForced;
|
if (pathOverride == 0) return l10n.chat_directForced;
|
||||||
return l10n.chat_hopsForced(pathOverride!);
|
return l10n.chat_hopsForced(
|
||||||
|
_displayHopCount(pathOverrideBytes, pathOverride!, pathHashByteWidth),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (pathLength < 0) return l10n.channelPath_floodPath;
|
if (pathLength < 0) return l10n.channelPath_floodPath;
|
||||||
if (pathLength == 0) return l10n.chat_direct;
|
if (pathLength == 0) return l10n.chat_direct;
|
||||||
return l10n.chat_hopsCount(pathLength);
|
return l10n.chat_hopsCount(
|
||||||
|
_displayHopCount(path, pathLength, pathHashByteWidth),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _displayHopCount(
|
||||||
|
List<int>? pathBytes,
|
||||||
|
int storedHopCount,
|
||||||
|
int hashWidth,
|
||||||
|
) {
|
||||||
|
if (pathBytes == null || pathBytes.isEmpty) return storedHopCount;
|
||||||
|
return PathHelper.splitPathBytes(pathBytes, hashWidth).length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ class _ChannelsScreenState extends State<ChannelsScreen>
|
|||||||
),
|
),
|
||||||
buildDefaultDragHandles: false,
|
buildDefaultDragHandles: false,
|
||||||
itemCount: filteredChannels.length,
|
itemCount: filteredChannels.length,
|
||||||
onReorder: (oldIndex, newIndex) {
|
onReorderItem: (oldIndex, newIndex) {
|
||||||
final reordered = List<Channel>.from(
|
final reordered = List<Channel>.from(
|
||||||
filteredChannels,
|
filteredChannels,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import '../utils/platform_info.dart';
|
|||||||
import '../connector/meshcore_connector.dart';
|
import '../connector/meshcore_connector.dart';
|
||||||
import '../connector/meshcore_protocol.dart';
|
import '../connector/meshcore_protocol.dart';
|
||||||
import '../helpers/cyr2lat.dart';
|
import '../helpers/cyr2lat.dart';
|
||||||
|
import '../helpers/path_helper.dart';
|
||||||
import '../helpers/reaction_helper.dart';
|
import '../helpers/reaction_helper.dart';
|
||||||
import '../widgets/message_status_icon.dart';
|
import '../widgets/message_status_icon.dart';
|
||||||
import '../widgets/empty_state.dart';
|
import '../widgets/empty_state.dart';
|
||||||
@@ -727,17 +728,35 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _currentPathLabel(Contact contact) {
|
String _currentPathLabel(Contact contact) {
|
||||||
|
final connector = context.read<MeshCoreConnector>();
|
||||||
|
|
||||||
// Check if user has set a path override
|
// Check if user has set a path override
|
||||||
if (contact.pathOverride != null) {
|
if (contact.pathOverride != null) {
|
||||||
if (contact.pathOverride! < 0) return context.l10n.chat_floodForced;
|
if (contact.pathOverride! < 0) return context.l10n.chat_floodForced;
|
||||||
if (contact.pathOverride == 0) return context.l10n.chat_directForced;
|
if (contact.pathOverride == 0) return context.l10n.chat_directForced;
|
||||||
return context.l10n.chat_hopsForced(contact.pathOverride!);
|
final bytes = contact.pathOverrideBytes ?? Uint8List(0);
|
||||||
|
final hopCount = _displayHopCount(
|
||||||
|
bytes,
|
||||||
|
contact.pathOverride!,
|
||||||
|
connector.pathHashByteWidth,
|
||||||
|
);
|
||||||
|
return context.l10n.chat_hopsForced(hopCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use device's path
|
// Use device's path
|
||||||
if (contact.pathLength < 0) return context.l10n.chat_floodAuto;
|
if (contact.pathLength < 0) return context.l10n.chat_floodAuto;
|
||||||
if (contact.pathLength == 0) return context.l10n.chat_direct;
|
if (contact.pathLength == 0) return context.l10n.chat_direct;
|
||||||
return context.l10n.chat_hopsCount(contact.pathLength);
|
final hopCount = _displayHopCount(
|
||||||
|
contact.path,
|
||||||
|
contact.pathLength,
|
||||||
|
connector.pathHashByteWidth,
|
||||||
|
);
|
||||||
|
return context.l10n.chat_hopsCount(hopCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _displayHopCount(List<int> pathBytes, int storedHopCount, int hashWidth) {
|
||||||
|
if (pathBytes.isEmpty) return storedHopCount;
|
||||||
|
return PathHelper.splitPathBytes(pathBytes, hashWidth).length;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showContactInfo(BuildContext context) {
|
void _showContactInfo(BuildContext context) {
|
||||||
@@ -758,7 +777,10 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
),
|
),
|
||||||
_buildInfoRow(
|
_buildInfoRow(
|
||||||
context.l10n.chat_path,
|
context.l10n.chat_path,
|
||||||
contact.pathLabel(context.l10n),
|
contact.pathLabel(
|
||||||
|
context.l10n,
|
||||||
|
pathHashByteWidth: connector.pathHashByteWidth,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
_buildInfoRow(
|
_buildInfoRow(
|
||||||
context.l10n.contact_lastSeen,
|
context.l10n.contact_lastSeen,
|
||||||
|
|||||||
@@ -911,6 +911,7 @@ class _ContactsScreenState extends State<ContactsScreen>
|
|||||||
);
|
);
|
||||||
return _ContactTile(
|
return _ContactTile(
|
||||||
contact: contact,
|
contact: contact,
|
||||||
|
pathHashByteWidth: connector.pathHashByteWidth,
|
||||||
lastSeen: _resolveLastSeen(contact),
|
lastSeen: _resolveLastSeen(contact),
|
||||||
unreadCount: unreadCount,
|
unreadCount: unreadCount,
|
||||||
isFavorite: contact.isFavorite,
|
isFavorite: contact.isFavorite,
|
||||||
@@ -1553,6 +1554,7 @@ class _ContactsScreenState extends State<ContactsScreen>
|
|||||||
|
|
||||||
class _ContactTile extends StatelessWidget {
|
class _ContactTile extends StatelessWidget {
|
||||||
final Contact contact;
|
final Contact contact;
|
||||||
|
final int pathHashByteWidth;
|
||||||
final DateTime lastSeen;
|
final DateTime lastSeen;
|
||||||
final int unreadCount;
|
final int unreadCount;
|
||||||
final bool isFavorite;
|
final bool isFavorite;
|
||||||
@@ -1561,6 +1563,7 @@ class _ContactTile extends StatelessWidget {
|
|||||||
|
|
||||||
const _ContactTile({
|
const _ContactTile({
|
||||||
required this.contact,
|
required this.contact,
|
||||||
|
required this.pathHashByteWidth,
|
||||||
required this.lastSeen,
|
required this.lastSeen,
|
||||||
required this.unreadCount,
|
required this.unreadCount,
|
||||||
required this.isFavorite,
|
required this.isFavorite,
|
||||||
@@ -1579,7 +1582,7 @@ class _ContactTile extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
title: Text(contact.name, maxLines: 1, overflow: TextOverflow.ellipsis),
|
title: Text(contact.name, maxLines: 1, overflow: TextOverflow.ellipsis),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
contact.pathLabel(context.l10n),
|
contact.pathLabel(context.l10n, pathHashByteWidth: pathHashByteWidth),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -2468,10 +2468,7 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
builder: (context) => PathTraceMapScreen(
|
builder: (context) => PathTraceMapScreen(
|
||||||
title: l10n.contacts_pathTrace,
|
title: l10n.contacts_pathTrace,
|
||||||
path: Uint8List.fromList(_pathTrace),
|
path: Uint8List.fromList(_pathTrace),
|
||||||
flipPathAround: true,
|
flipPathAround: false,
|
||||||
targetContact: _pathTraceContacts.isNotEmpty
|
|
||||||
? _pathTraceContacts.last
|
|
||||||
: null,
|
|
||||||
pathHashByteWidth: hashW,
|
pathHashByteWidth: hashW,
|
||||||
pathContacts: _pathTraceContacts,
|
pathContacts: _pathTraceContacts,
|
||||||
),
|
),
|
||||||
@@ -2494,9 +2491,6 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
title: l10n.contacts_pathTrace,
|
title: l10n.contacts_pathTrace,
|
||||||
path: Uint8List.fromList(_pathTrace),
|
path: Uint8List.fromList(_pathTrace),
|
||||||
flipPathAround: true,
|
flipPathAround: true,
|
||||||
targetContact: _pathTraceContacts.isNotEmpty
|
|
||||||
? _pathTraceContacts.last
|
|
||||||
: null,
|
|
||||||
pathHashByteWidth: context
|
pathHashByteWidth: context
|
||||||
.read<MeshCoreConnector>()
|
.read<MeshCoreConnector>()
|
||||||
.pathHashByteWidth,
|
.pathHashByteWidth,
|
||||||
|
|||||||
@@ -97,7 +97,9 @@ class _PathEditorSheetState extends State<PathEditorSheet> {
|
|||||||
|
|
||||||
void _syncHexFromHops() {
|
void _syncHexFromHops() {
|
||||||
_syncingHex = true;
|
_syncingHex = true;
|
||||||
_hexController.text = _hops.map((h) => PathHelper.formatHopHex(h.bytes)).join(',');
|
_hexController.text = _hops
|
||||||
|
.map((h) => PathHelper.formatHopHex(h.bytes))
|
||||||
|
.join(',');
|
||||||
_syncingHex = false;
|
_syncingHex = false;
|
||||||
_hexError = null;
|
_hexError = null;
|
||||||
}
|
}
|
||||||
@@ -114,8 +116,7 @@ class _PathEditorSheetState extends State<PathEditorSheet> {
|
|||||||
final invalid = tokens
|
final invalid = tokens
|
||||||
.where(
|
.where(
|
||||||
(t) =>
|
(t) =>
|
||||||
t.length != expectedChars ||
|
t.length != expectedChars || int.tryParse(t, radix: 16) == null,
|
||||||
int.tryParse(t, radix: 16) == null,
|
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
setState(() {
|
setState(() {
|
||||||
@@ -144,10 +145,15 @@ class _PathEditorSheetState extends State<PathEditorSheet> {
|
|||||||
|
|
||||||
void _addHop(Contact contact) {
|
void _addHop(Contact contact) {
|
||||||
if (_hops.length >= _maxHops) return;
|
if (_hops.length >= _maxHops) return;
|
||||||
final width = widget.pathHashByteWidth.clamp(1, contact.publicKey.length).toInt();
|
final width = widget.pathHashByteWidth
|
||||||
|
.clamp(1, contact.publicKey.length)
|
||||||
|
.toInt();
|
||||||
setState(() {
|
setState(() {
|
||||||
_hops.add(
|
_hops.add(
|
||||||
_Hop(_nextHopId++, Uint8List.fromList(contact.publicKey.sublist(0, width))),
|
_Hop(
|
||||||
|
_nextHopId++,
|
||||||
|
Uint8List.fromList(contact.publicKey.sublist(0, width)),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
_syncHexFromHops();
|
_syncHexFromHops();
|
||||||
});
|
});
|
||||||
@@ -173,10 +179,7 @@ class _PathEditorSheetState extends State<PathEditorSheet> {
|
|||||||
for (final hop in _hops) {
|
for (final hop in _hops) {
|
||||||
bytes.addAll(hop.bytes);
|
bytes.addAll(hop.bytes);
|
||||||
}
|
}
|
||||||
Navigator.pop(
|
Navigator.pop(context, Uint8List.fromList(bytes));
|
||||||
context,
|
|
||||||
Uint8List.fromList(bytes),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _hopTile(BuildContext context, int index) {
|
Widget _hopTile(BuildContext context, int index) {
|
||||||
|
|||||||
@@ -547,9 +547,15 @@ class _RoutingSheetBodyState extends State<_RoutingSheetBody> {
|
|||||||
connector.pathHashByteWidth,
|
connector.pathHashByteWidth,
|
||||||
)
|
)
|
||||||
: l10n.chat_hopsCount(record.hopCount);
|
: l10n.chat_hopsCount(record.hopCount);
|
||||||
|
final displayHopCount = hasBytes
|
||||||
|
? PathHelper.splitPathBytes(
|
||||||
|
record.pathBytes,
|
||||||
|
connector.pathHashByteWidth,
|
||||||
|
).length
|
||||||
|
: record.hopCount;
|
||||||
|
|
||||||
final line1 =
|
final line1 =
|
||||||
'${l10n.chat_hopsCount(record.hopCount)} • ${_qualityLabel(context, quality)}';
|
'${l10n.chat_hopsCount(displayHopCount)} • ${_qualityLabel(context, quality)}';
|
||||||
final line2Parts = <String>[
|
final line2Parts = <String>[
|
||||||
record.timestamp != null
|
record.timestamp != null
|
||||||
? l10n.routing_lastWorked(_relativeTime(context, record.timestamp!))
|
? l10n.routing_lastWorked(_relativeTime(context, record.timestamp!))
|
||||||
|
|||||||
Reference in New Issue
Block a user