mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-08-04 15:03:00 +10:00
Refactor contact handling and enhance UI with new advert options and localized strings
This commit is contained in:
@@ -1680,12 +1680,6 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
_isLoadingContacts = true;
|
_isLoadingContacts = true;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
break;
|
break;
|
||||||
case pushCodeNewAdvert:
|
|
||||||
debugPrint('Got NEW_ADVERT');
|
|
||||||
_handleContact(frame);
|
|
||||||
notifyListeners();
|
|
||||||
unawaited(_persistContacts());
|
|
||||||
break;
|
|
||||||
case respCodeContact:
|
case respCodeContact:
|
||||||
debugPrint('Got CONTACT');
|
debugPrint('Got CONTACT');
|
||||||
_handleContact(frame);
|
_handleContact(frame);
|
||||||
@@ -1743,7 +1737,6 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
break;
|
break;
|
||||||
case respCodeCustomVars:
|
case respCodeCustomVars:
|
||||||
_handleCustomVars(frame);
|
_handleCustomVars(frame);
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
debugPrint('Unknown frame code: $code');
|
debugPrint('Unknown frame code: $code');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ class BufferReader {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void skipBytes(int count) {
|
||||||
|
_pointer += count;
|
||||||
|
}
|
||||||
|
|
||||||
Uint8List readRemainingBytes() => readBytes(remaining);
|
Uint8List readRemainingBytes() => readBytes(remaining);
|
||||||
|
|
||||||
String readString() =>
|
String readString() =>
|
||||||
@@ -135,6 +139,7 @@ const int cmdSendStatusReq = 27;
|
|||||||
const int cmdGetContactByKey = 30;
|
const int cmdGetContactByKey = 30;
|
||||||
const int cmdGetChannel = 31;
|
const int cmdGetChannel = 31;
|
||||||
const int cmdSetChannel = 32;
|
const int cmdSetChannel = 32;
|
||||||
|
const int cmdSendTracePath = 36;
|
||||||
const int cmdGetRadioSettings = 57;
|
const int cmdGetRadioSettings = 57;
|
||||||
const int cmdGetTelemetryReq = 39;
|
const int cmdGetTelemetryReq = 39;
|
||||||
const int cmdGetCustomVar = 40;
|
const int cmdGetCustomVar = 40;
|
||||||
@@ -185,6 +190,7 @@ const int pushCodeLoginSuccess = 0x85;
|
|||||||
const int pushCodeLoginFail = 0x86;
|
const int pushCodeLoginFail = 0x86;
|
||||||
const int pushCodeStatusResponse = 0x87;
|
const int pushCodeStatusResponse = 0x87;
|
||||||
const int pushCodeLogRxData = 0x88;
|
const int pushCodeLogRxData = 0x88;
|
||||||
|
const int pushCodeTraceData = 0x89;
|
||||||
const int pushCodeNewAdvert = 0x8A;
|
const int pushCodeNewAdvert = 0x8A;
|
||||||
const int pushCodeTelemetryResponse = 0x8B;
|
const int pushCodeTelemetryResponse = 0x8B;
|
||||||
const int pushCodeBinaryResponse = 0x8C;
|
const int pushCodeBinaryResponse = 0x8C;
|
||||||
@@ -718,6 +724,21 @@ Uint8List buildSendBinaryReq(Uint8List repeaterPubKey, {Uint8List? payload}) {
|
|||||||
return writer.toBytes();
|
return writer.toBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Build a trace request frame
|
||||||
|
//[cmd][tag x4][auth x4][flag][payload]
|
||||||
|
Uint8List buildTraceReq(int tag, int auth, int flag, {Uint8List? payload})
|
||||||
|
{
|
||||||
|
final writer = BufferWriter();
|
||||||
|
writer.writeByte(cmdSendTracePath);
|
||||||
|
writer.writeUInt32LE(tag);
|
||||||
|
writer.writeUInt32LE(auth);
|
||||||
|
writer.writeByte(flag);
|
||||||
|
if (payload != null && payload.isNotEmpty) {
|
||||||
|
writer.writeBytes(payload);
|
||||||
|
}
|
||||||
|
return writer.toBytes();
|
||||||
|
}
|
||||||
|
|
||||||
// Build a export contact frame
|
// Build a export contact frame
|
||||||
// [cmd][pub_key x32 / if empty exports your contact info]
|
// [cmd][pub_key x32 / if empty exports your contact info]
|
||||||
Uint8List buildExportContactFrame(Uint8List pubKey) {
|
Uint8List buildExportContactFrame(Uint8List pubKey) {
|
||||||
|
|||||||
+5
-1
@@ -1327,5 +1327,9 @@
|
|||||||
"contacts_clipboardEmpty": "Clipboard Is Empty.",
|
"contacts_clipboardEmpty": "Clipboard Is Empty.",
|
||||||
"contacts_invalidAdvertFormat": "Invalid Contact Data",
|
"contacts_invalidAdvertFormat": "Invalid Contact Data",
|
||||||
"contacts_contactImported": "Contact has been Imported.",
|
"contacts_contactImported": "Contact has been Imported.",
|
||||||
"contacts_contactImportFailed": "Contact Failed to Imported."
|
"contacts_contactImportFailed": "Contact Failed to Imported.",
|
||||||
|
"contacts_zeroHopAdvert":"Zero Hop Advert",
|
||||||
|
"contacts_floodAdvert":"Flood Advert",
|
||||||
|
"contacts_copyAdvertToClipboard":"Copy Advert to Clipboard",
|
||||||
|
"contacts_addContactFromClipboard":"Add Contact from Clipboard"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,6 +102,10 @@ class Contact {
|
|||||||
return parts.join(',');
|
return parts.join(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String get shortPubKeyHex {
|
||||||
|
return "<${publicKeyHex.substring(0, 8)}...${publicKeyHex.substring(publicKeyHex.length - 8)}>";
|
||||||
|
}
|
||||||
|
|
||||||
Uint8List get _pathBytesForDisplay {
|
Uint8List get _pathBytesForDisplay {
|
||||||
if (pathOverride != null) {
|
if (pathOverride != null) {
|
||||||
if (pathOverride! < 0) return Uint8List(0);
|
if (pathOverride! < 0) return Uint8List(0);
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ class _ContactsScreenState extends State<ContactsScreen>
|
|||||||
children: [
|
children: [
|
||||||
const Icon(Icons.connect_without_contact),
|
const Icon(Icons.connect_without_contact),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text("Zero Hop Advert"),
|
Text(context.l10n.contacts_zeroHopAdvert),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
onTap: () => {
|
onTap: () => {
|
||||||
@@ -192,7 +192,7 @@ class _ContactsScreenState extends State<ContactsScreen>
|
|||||||
children: [
|
children: [
|
||||||
const Icon(Icons.cell_tower),
|
const Icon(Icons.cell_tower),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text("Flood Advert"),
|
Text(context.l10n.contacts_floodAdvert),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
onTap: () => {
|
onTap: () => {
|
||||||
@@ -207,7 +207,7 @@ class _ContactsScreenState extends State<ContactsScreen>
|
|||||||
children: [
|
children: [
|
||||||
const Icon(Icons.copy),
|
const Icon(Icons.copy),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text("Copy Advert to Clipboard"),
|
Text(context.l10n.contacts_copyAdvertToClipboard),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
onTap: () => _contactExport(Uint8List.fromList([])),
|
onTap: () => _contactExport(Uint8List.fromList([])),
|
||||||
@@ -217,7 +217,7 @@ class _ContactsScreenState extends State<ContactsScreen>
|
|||||||
children: [
|
children: [
|
||||||
const Icon(Icons.paste),
|
const Icon(Icons.paste),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text("Add Contact from Clipboard"),
|
Text(context.l10n.contacts_addContactFromClipboard),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
onTap: () => _contactImport(),
|
onTap: () => _contactImport(),
|
||||||
@@ -227,12 +227,22 @@ class _ContactsScreenState extends State<ContactsScreen>
|
|||||||
),
|
),
|
||||||
PopupMenuButton(
|
PopupMenuButton(
|
||||||
itemBuilder: (context) => [
|
itemBuilder: (context) => [
|
||||||
|
PopupMenuItem(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.logout, color: Colors.red),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(context.l10n.common_disconnect),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onTap: () => _disconnect(context, connector),
|
||||||
|
),
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.settings),
|
const Icon(Icons.settings),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
const Text('Settings'),
|
Text(context.l10n.settings_title),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
onTap: () => Navigator.push(
|
onTap: () => Navigator.push(
|
||||||
@@ -240,16 +250,6 @@ class _ContactsScreenState extends State<ContactsScreen>
|
|||||||
MaterialPageRoute(builder: (context) => const SettingsScreen()),
|
MaterialPageRoute(builder: (context) => const SettingsScreen()),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PopupMenuItem(
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
const Icon(Icons.logout, color: Colors.red),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
const Text('Disconnect'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
onTap: () => _disconnect(context, connector),
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
icon: const Icon(Icons.more_vert),
|
icon: const Icon(Icons.more_vert),
|
||||||
),
|
),
|
||||||
@@ -930,7 +930,7 @@ class _ContactsScreenState extends State<ContactsScreen>
|
|||||||
_showRoomLogin(context, contact, RoomLoginDestination.management);
|
_showRoomLogin(context, contact, RoomLoginDestination.management);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
] else
|
] else ...[
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.chat),
|
leading: const Icon(Icons.chat),
|
||||||
title: Text(context.l10n.contacts_openChat),
|
title: Text(context.l10n.contacts_openChat),
|
||||||
@@ -1005,17 +1005,16 @@ class _ContactTile extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final shotPublicKey =
|
|
||||||
"<${contact.publicKeyHex.substring(0, 8)}...${contact.publicKeyHex.substring(contact.publicKeyHex.length - 8)}>";
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: CircleAvatar(
|
leading: CircleAvatar(
|
||||||
backgroundColor: _getTypeColor(contact.type),
|
backgroundColor: _getTypeColor(contact.type),
|
||||||
child: _buildContactAvatar(contact),
|
child: _buildContactAvatar(contact),
|
||||||
),
|
),
|
||||||
title: Text(contact.name),
|
title: Text(contact.name),
|
||||||
subtitle: Text(
|
subtitle: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
'${contact.typeLabel}\n${contact.shortPubKeyHex}',
|
Text(contact.pathLabel),
|
||||||
),
|
Text(contact.shortPubKeyHex, style: TextStyle(fontSize: 12))
|
||||||
|
],),
|
||||||
// Clamp text scaling in trailing section to prevent overflow while
|
// Clamp text scaling in trailing section to prevent overflow while
|
||||||
// maintaining accessibility. Primary content (title/subtitle) scales normally.
|
// maintaining accessibility. Primary content (title/subtitle) scales normally.
|
||||||
trailing: MediaQuery(
|
trailing: MediaQuery(
|
||||||
@@ -1039,21 +1038,15 @@ class _ContactTile extends StatelessWidget {
|
|||||||
Row(
|
Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(contact.pathLabel,
|
|
||||||
style: TextStyle(fontSize: 12, color: Colors.grey[600])),
|
|
||||||
if (contact.hasLocation)
|
if (contact.hasLocation)
|
||||||
Icon(Icons.location_on, size: 14, color: Colors.grey[400]),
|
Icon(Icons.location_on, size: 14, color: Colors.grey[400]),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Text(
|
|
||||||
_formatLastSeen(context, lastSeen),
|
|
||||||
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
|
|
||||||
),
|
|
||||||
if (contact.hasLocation)
|
|
||||||
Icon(Icons.location_on, size: 14, color: Colors.grey[400]),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
onTap: onTap,
|
||||||
|
onLongPress: onLongPress,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user