checkpoint

This commit is contained in:
Christien Rioux 2024-06-18 21:20:06 -04:00
parent 3edf2ebb46
commit c40f835ec5
25 changed files with 378 additions and 312 deletions

View file

@ -8,7 +8,6 @@ import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
import 'package:flutter_chat_ui/flutter_chat_ui.dart';
import 'package:provider/provider.dart';
import 'package:scroll_to_index/scroll_to_index.dart';
import 'package:veilid_support/veilid_support.dart';
@ -27,10 +26,12 @@ const metadataKeyAttachments = 'attachments';
class ChatComponentCubit extends Cubit<ChatComponentState> {
ChatComponentCubit._({
required Locator locator,
required AccountInfo accountInfo,
required AccountRecordCubit accountRecordCubit,
required List<ActiveConversationCubit> conversationCubits,
required SingleContactMessagesCubit messagesCubit,
}) : _locator = locator,
}) : _accountInfo = accountInfo,
_accountRecordCubit = accountRecordCubit,
_conversationCubits = conversationCubits,
_messagesCubit = messagesCubit,
super(ChatComponentState(
@ -48,26 +49,25 @@ class ChatComponentCubit extends Cubit<ChatComponentState> {
}
factory ChatComponentCubit.singleContact(
{required Locator locator,
{required AccountInfo accountInfo,
required AccountRecordCubit accountRecordCubit,
required ActiveConversationCubit activeConversationCubit,
required SingleContactMessagesCubit messagesCubit}) =>
ChatComponentCubit._(
locator: locator,
accountInfo: accountInfo,
accountRecordCubit: accountRecordCubit,
conversationCubits: [activeConversationCubit],
messagesCubit: messagesCubit,
);
Future<void> _init() async {
// Get local user info and account record cubit
final unlockedAccountInfo =
_locator<AccountInfoCubit>().state.unlockedAccountInfo!;
_localUserIdentityKey = unlockedAccountInfo.identityTypedPublicKey;
_localUserAccountRecordCubit = _locator<AccountRecordCubit>();
_localUserIdentityKey = _accountInfo.identityTypedPublicKey;
// Subscribe to local user info
_localUserAccountRecordSubscription = _localUserAccountRecordCubit.stream
.listen(_onChangedLocalUserAccountRecord);
_onChangedLocalUserAccountRecord(_localUserAccountRecordCubit.state);
_accountRecordSubscription =
_accountRecordCubit.stream.listen(_onChangedAccountRecord);
_onChangedAccountRecord(_accountRecordCubit.state);
// Subscribe to remote user info
await _updateConversationSubscriptions();
@ -80,7 +80,7 @@ class ChatComponentCubit extends Cubit<ChatComponentState> {
@override
Future<void> close() async {
await _initWait();
await _localUserAccountRecordSubscription.cancel();
await _accountRecordSubscription.cancel();
await _messagesSubscription.cancel();
await super.close();
}
@ -145,7 +145,7 @@ class ChatComponentCubit extends Cubit<ChatComponentState> {
////////////////////////////////////////////////////////////////////////////
// Private Implementation
void _onChangedLocalUserAccountRecord(AsyncValue<proto.Account> avAccount) {
void _onChangedAccountRecord(AsyncValue<proto.Account> avAccount) {
final account = avAccount.asData?.value;
if (account == null) {
emit(state.copyWith(localUser: null));
@ -374,15 +374,14 @@ class ChatComponentCubit extends Cubit<ChatComponentState> {
////////////////////////////////////////////////////////////////////////////
final _initWait = WaitSet<void>();
final Locator _locator;
final AccountInfo _accountInfo;
final AccountRecordCubit _accountRecordCubit;
final List<ActiveConversationCubit> _conversationCubits;
final SingleContactMessagesCubit _messagesCubit;
late final TypedKey _localUserIdentityKey;
late final AccountRecordCubit _localUserAccountRecordCubit;
late final StreamSubscription<AsyncValue<proto.Account>>
_localUserAccountRecordSubscription;
_accountRecordSubscription;
final Map<TypedKey, StreamSubscription<AsyncValue<ActiveConversationState>>>
_conversationSubscriptions = {};
late StreamSubscription<SingleContactMessagesState> _messagesSubscription;

View file

@ -4,7 +4,6 @@ import 'package:async_tools/async_tools.dart';
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';
import 'package:veilid_support/veilid_support.dart';
import '../../account_manager/account_manager.dart';
@ -51,13 +50,13 @@ typedef SingleContactMessagesState = AsyncValue<WindowState<MessageState>>;
// Builds the reconciled chat record from the local and remote conversation keys
class SingleContactMessagesCubit extends Cubit<SingleContactMessagesState> {
SingleContactMessagesCubit({
required Locator locator,
required AccountInfo accountInfo,
required TypedKey remoteIdentityPublicKey,
required TypedKey localConversationRecordKey,
required TypedKey localMessagesRecordKey,
required TypedKey remoteConversationRecordKey,
required TypedKey remoteMessagesRecordKey,
}) : _locator = locator,
}) : _accountInfo = accountInfo,
_remoteIdentityPublicKey = remoteIdentityPublicKey,
_localConversationRecordKey = localConversationRecordKey,
_localMessagesRecordKey = localMessagesRecordKey,
@ -87,9 +86,6 @@ class SingleContactMessagesCubit extends Cubit<SingleContactMessagesState> {
// Initialize everything
Future<void> _init() async {
_unlockedAccountInfo =
_locator<AccountInfoCubit>().state.unlockedAccountInfo!;
_unsentMessagesQueue = PersistentQueue<proto.Message>(
table: 'SingleContactUnsentMessages',
key: _remoteConversationRecordKey.toString(),
@ -115,15 +111,15 @@ class SingleContactMessagesCubit extends Cubit<SingleContactMessagesState> {
// Make crypto
Future<void> _initCrypto() async {
_conversationCrypto = await _unlockedAccountInfo
.makeConversationCrypto(_remoteIdentityPublicKey);
_conversationCrypto =
await _accountInfo.makeConversationCrypto(_remoteIdentityPublicKey);
_senderMessageIntegrity = await MessageIntegrity.create(
author: _unlockedAccountInfo.identityTypedPublicKey);
author: _accountInfo.identityTypedPublicKey);
}
// Open local messages key
Future<void> _initSentMessagesCubit() async {
final writer = _unlockedAccountInfo.identityWriter;
final writer = _accountInfo.identityWriter;
_sentMessagesCubit = DHTLogCubit(
open: () async => DHTLog.openWrite(_localMessagesRecordKey, writer,
@ -153,7 +149,7 @@ class SingleContactMessagesCubit extends Cubit<SingleContactMessagesState> {
Future<VeilidCrypto> _makeLocalMessagesCrypto() async =>
VeilidCryptoPrivate.fromTypedKey(
_unlockedAccountInfo.userLogin.identitySecret, 'tabledb');
_accountInfo.userLogin!.identitySecret, 'tabledb');
// Open reconciled chat record key
Future<void> _initReconciledMessagesCubit() async {
@ -245,9 +241,7 @@ class SingleContactMessagesCubit extends Cubit<SingleContactMessagesState> {
}
_reconciliation.reconcileMessages(
_unlockedAccountInfo.identityTypedPublicKey,
sentMessages,
_sentMessagesCubit!);
_accountInfo.identityTypedPublicKey, sentMessages, _sentMessagesCubit!);
// Update the view
_renderState();
@ -284,7 +278,7 @@ class SingleContactMessagesCubit extends Cubit<SingleContactMessagesState> {
// Now sign it
await _senderMessageIntegrity.signMessage(
message, _unlockedAccountInfo.identitySecretKey);
message, _accountInfo.identitySecretKey);
}
// Async process to send messages in the background
@ -336,8 +330,8 @@ class SingleContactMessagesCubit extends Cubit<SingleContactMessagesState> {
final renderedElements = <RenderStateElement>[];
for (final m in reconciledMessages.windowElements) {
final isLocal = m.content.author.toVeilid() ==
_unlockedAccountInfo.identityTypedPublicKey;
final isLocal =
m.content.author.toVeilid() == _accountInfo.identityTypedPublicKey;
final reconciledTimestamp = Timestamp.fromInt64(m.reconciledTime);
final sm =
isLocal ? sentMessagesMap[m.content.authorUniqueIdString] : null;
@ -375,7 +369,7 @@ class SingleContactMessagesCubit extends Cubit<SingleContactMessagesState> {
// Add common fields
// id and signature will get set by _processMessageToSend
message
..author = _unlockedAccountInfo.identityTypedPublicKey.toProto()
..author = _accountInfo.identityTypedPublicKey.toProto()
..timestamp = Veilid.instance.now().toInt64();
// Put in the queue
@ -408,8 +402,7 @@ class SingleContactMessagesCubit extends Cubit<SingleContactMessagesState> {
/////////////////////////////////////////////////////////////////////////
final WaitSet<void> _initWait = WaitSet();
final Locator _locator;
late final UnlockedAccountInfo _unlockedAccountInfo;
late final AccountInfo _accountInfo;
final TypedKey _remoteIdentityPublicKey;
final TypedKey _localConversationRecordKey;
final TypedKey _localMessagesRecordKey;

View file

@ -8,6 +8,7 @@ import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
import 'package:flutter_chat_ui/flutter_chat_ui.dart';
import 'package:veilid_support/veilid_support.dart';
import '../../account_manager/account_manager.dart';
import '../../conversation/conversation.dart';
import '../../theme/theme.dart';
import '../chat.dart';
@ -21,6 +22,12 @@ class ChatComponentWidget extends StatelessWidget {
static Widget builder(
{required TypedKey localConversationRecordKey, Key? key}) =>
Builder(builder: (context) {
// Get the account info
final accountInfo = context.watch<AccountInfoCubit>().state;
// Get the account record cubit
final accountRecordCubit = context.read<AccountRecordCubit>();
// Get the active conversation cubit
final activeConversationCubit = context
.select<ActiveConversationsBlocMapCubit, ActiveConversationCubit?>(
@ -43,7 +50,8 @@ class ChatComponentWidget extends StatelessWidget {
// Make chat component state
return BlocProvider(
create: (context) => ChatComponentCubit.singleContact(
locator: context.read,
accountInfo: accountInfo,
accountRecordCubit: accountRecordCubit,
activeConversationCubit: activeConversationCubit,
messagesCubit: messagesCubit,
),