import 'dart:async'; import 'dart:convert'; import 'package:veilid_support/veilid_support.dart'; import '../../account_manager/account_manager.dart'; import '../../proto/proto.dart' as proto; import '../../tools/tools.dart'; import 'conversation_cubit.dart'; ////////////////////////////////////////////////// // Mutable state for per-account contacts class ContactListCubit extends DHTShortArrayCubit { ContactListCubit({ required ActiveAccountInfo activeAccountInfo, required proto.Account account, }) : _activeAccountInfo = activeAccountInfo, super( open: () => _open(activeAccountInfo, account), decodeElement: proto.Contact.fromBuffer); static Future _open( ActiveAccountInfo activeAccountInfo, proto.Account account) async { final accountRecordKey = activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey; final contactListRecordKey = account.contactList.toVeilid(); final dhtRecord = await DHTShortArray.openOwned(contactListRecordKey, debugName: 'ContactListCubit::_open::ContactList', parent: accountRecordKey); return dhtRecord; } Future createContact({ required proto.Profile remoteProfile, required IdentityMaster remoteIdentity, required TypedKey remoteConversationRecordKey, required TypedKey localConversationRecordKey, }) async { // Create Contact final contact = proto.Contact() ..editedProfile = remoteProfile ..remoteProfile = remoteProfile ..identityMasterJson = jsonEncode(remoteIdentity.toJson()) ..identityPublicKey = TypedKey( kind: remoteIdentity.identityRecordKey.kind, value: remoteIdentity.identityPublicKey) .toProto() ..remoteConversationRecordKey = remoteConversationRecordKey.toProto() ..localConversationRecordKey = localConversationRecordKey.toProto() ..showAvailability = false; // Add Contact to account's list // if this fails, don't keep retrying, user can try again later await operateWrite((writer) async { if (!await writer.tryAdd(contact.writeToBuffer())) { throw Exception('Failed to add contact record'); } }); } Future deleteContact({required proto.Contact contact}) async { final remoteIdentityPublicKey = contact.identityPublicKey.toVeilid(); final localConversationRecordKey = contact.localConversationRecordKey.toVeilid(); final remoteConversationRecordKey = contact.remoteConversationRecordKey.toVeilid(); // Remove Contact from account's list final deletedItem = await operateWrite((writer) async { for (var i = 0; i < writer.length; i++) { final item = await writer.getProtobuf(proto.Contact.fromBuffer, i); if (item == null) { throw Exception('Failed to get contact'); } if (item.localConversationRecordKey == contact.localConversationRecordKey) { await writer.remove(i); return item; } } return null; }); if (deletedItem != null) { try { // Make a conversation cubit to manipulate the conversation final conversationCubit = ConversationCubit( activeAccountInfo: _activeAccountInfo, remoteIdentityPublicKey: remoteIdentityPublicKey, localConversationRecordKey: localConversationRecordKey, remoteConversationRecordKey: remoteConversationRecordKey, ); // Delete the local and remote conversation records await conversationCubit.delete(); } on Exception catch (e) { log.debug('error deleting conversation records: $e', e); } } } final ActiveAccountInfo _activeAccountInfo; }