feat: Add new contact and message tracking features, including unread status and removal functionality

This commit is contained in:
Janez T
2025-10-15 21:49:33 +02:00
parent 2849ab92aa
commit 6be182e20a
13 changed files with 463 additions and 48 deletions

View File

@@ -1098,6 +1098,26 @@ class ConnectionProvider with ChangeNotifier {
}
}
/// Remove a contact from the companion radio
///
/// Deletes the contact from the device's internal contact table.
/// The contact will no longer appear in the contact list and all
/// routing information will be cleared.
Future<void> removeContact(Uint8List contactPublicKey) async {
if (!_bleService.isConnected) {
_error = 'Not connected to device';
notifyListeners();
return;
}
try {
await _bleService.removeContact(contactPublicKey);
} catch (e) {
_error = 'Failed to remove contact: $e';
notifyListeners();
}
}
/// Clear error message
void clearError() {
_error = null;

View File

@@ -125,7 +125,18 @@ class ContactsProvider with ChangeNotifier {
return;
}
_contacts[contact.publicKeyHex] = contact;
// Check if this is a new contact
final isNewContact = !_contacts.containsKey(contact.publicKeyHex);
// If it's a new contact, mark it as new
if (isNewContact) {
_contacts[contact.publicKeyHex] = contact.copyWith(isNew: true);
} else {
// Keep existing isNew status when updating
final existingContact = _contacts[contact.publicKeyHex]!;
_contacts[contact.publicKeyHex] = contact.copyWith(isNew: existingContact.isNew);
}
_persistContacts();
notifyListeners();
}
@@ -242,6 +253,35 @@ class ContactsProvider with ChangeNotifier {
return contacts.where((c) => c.isRecentlySeen).toList();
}
/// Get count of new contacts (not yet viewed)
int get newContactsCount =>
contacts.where((c) => c.isNew && !c.isChannel).length;
/// Mark all contacts as viewed (not new)
void markAllAsViewed() {
bool hasChanges = false;
_contacts.forEach((key, contact) {
if (contact.isNew && !contact.isChannel) {
_contacts[key] = contact.copyWith(isNew: false);
hasChanges = true;
}
});
if (hasChanges) {
_persistContacts();
notifyListeners();
}
}
/// Mark a specific contact as viewed (not new)
void markAsViewed(String publicKeyHex) {
final contact = _contacts[publicKeyHex];
if (contact != null && contact.isNew) {
_contacts[publicKeyHex] = contact.copyWith(isNew: false);
_persistContacts();
notifyListeners();
}
}
/// Clear all contacts
void clearContacts() {
_contacts.clear();
@@ -250,7 +290,21 @@ class ContactsProvider with ChangeNotifier {
}
/// Remove a contact
void removeContact(String publicKeyHex) {
/// [onRemoveFromDevice] - Optional callback to remove contact from BLE device
Future<void> removeContact(
String publicKeyHex, {
Future<void> Function(Uint8List)? onRemoveFromDevice,
}) async {
// Get the contact before removing
final contact = _contacts[publicKeyHex];
if (contact == null) return;
// Remove from device first if callback provided
if (onRemoveFromDevice != null) {
await onRemoveFromDevice(contact.publicKey);
}
// Then remove from local storage
_contacts.remove(publicKeyHex);
_persistContacts();
notifyListeners();

View File

@@ -49,6 +49,14 @@ class MessagesProvider with ChangeNotifier {
bool get isInitialized => _isInitialized;
/// Get count of unread messages (excluding sent messages and system messages)
int get unreadCount => _messages
.where((m) =>
!m.isRead &&
!m.isSentMessage &&
!m.isSystemMessage)
.length;
/// Initialize and load persisted messages
Future<void> initialize() async {
if (_isInitialized) return;
@@ -287,6 +295,31 @@ class MessagesProvider with ChangeNotifier {
notifyListeners();
}
/// Mark all messages as read
void markAllAsRead() {
bool hasChanges = false;
for (int i = 0; i < _messages.length; i++) {
if (!_messages[i].isRead && !_messages[i].isSentMessage && !_messages[i].isSystemMessage) {
_messages[i] = _messages[i].copyWith(isRead: true);
hasChanges = true;
}
}
if (hasChanges) {
_persistMessages();
notifyListeners();
}
}
/// Mark a specific message as read
void markAsRead(String messageId) {
final index = _messages.indexWhere((m) => m.id == messageId);
if (index != -1 && !_messages[index].isRead) {
_messages[index] = _messages[index].copyWith(isRead: true);
_persistMessages();
notifyListeners();
}
}
/// Delete a specific message by ID
void deleteMessage(String messageId) {
final index = _messages.indexWhere((m) => m.id == messageId);
@@ -412,9 +445,10 @@ class MessagesProvider with ChangeNotifier {
return;
}
// Add message with sending status
// Add message with sending status and mark as read (sent messages are always read)
final sendingMessage = enhancedMessage.copyWith(
deliveryStatus: MessageDeliveryStatus.sending,
isRead: true, // Sent messages are always marked as read
);
_messages.add(sendingMessage);
print(' ✅ Message added to list at index ${_messages.length - 1}');