checkpoint

This commit is contained in:
Christien Rioux 2024-06-19 11:35:51 -04:00
parent c40f835ec5
commit aea196deb3
7 changed files with 371 additions and 177 deletions

View file

@ -1,12 +1,11 @@
import 'package:async_tools/async_tools.dart';
import 'package:bloc_advanced_tools/bloc_advanced_tools.dart'; import 'package:bloc_advanced_tools/bloc_advanced_tools.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:veilid_support/veilid_support.dart'; import 'package:veilid_support/veilid_support.dart';
import '../../account_manager/account_manager.dart'; import '../../account_manager/account_manager.dart';
typedef AccountRecordsBlocMapState typedef PerAccountCollectionBlocMapState
= BlocMapState<TypedKey, AsyncValue<AccountRecordState>>; = BlocMapState<TypedKey, PerAccountCollectionState>;
/// Map of the logged in user accounts to their PerAccountCollectionCubit /// Map of the logged in user accounts to their PerAccountCollectionCubit
/// Ensures there is an single account record cubit for each logged in account /// Ensures there is an single account record cubit for each logged in account

View file

@ -55,11 +55,26 @@ class PerAccountCollectionCubit extends Cubit<PerAccountCollectionState> {
PerAccountCollectionState( PerAccountCollectionState(
accountInfo: accountInfoCubit.state, accountInfo: accountInfoCubit.state,
avAccountRecordState: const AsyncValue.loading(), avAccountRecordState: const AsyncValue.loading(),
contactInvitationListCubit: null); contactInvitationListCubit: null,
accountInfoCubit: null,
accountRecordCubit: null,
contactListCubit: null,
waitingInvitationsBlocMapCubit: null,
activeChatCubit: null,
chatListCubit: null,
activeConversationsBlocMapCubit: null,
activeSingleContactChatBlocMapCubit: null);
Future<void> _followAccountInfoState(AccountInfo accountInfo) async { Future<void> _followAccountInfoState(AccountInfo accountInfo) async {
// If state hasn't changed just return
if (state.accountInfo == accountInfo) {
return;
}
// Get the next state
var nextState = state.copyWith(accountInfo: accountInfo); var nextState = state.copyWith(accountInfo: accountInfo);
// Update AccountRecordCubit
if (accountInfo.userLogin == null) { if (accountInfo.userLogin == null) {
/////////////// Not logged in ///////////////// /////////////// Not logged in /////////////////
@ -67,7 +82,7 @@ class PerAccountCollectionCubit extends Cubit<PerAccountCollectionState> {
await _accountRecordSubscription?.cancel(); await _accountRecordSubscription?.cancel();
_accountRecordSubscription = null; _accountRecordSubscription = null;
// Update state // Update state to 'loading'
nextState = nextState =
_updateAccountRecordState(nextState, const AsyncValue.loading()); _updateAccountRecordState(nextState, const AsyncValue.loading());
emit(nextState); emit(nextState);
@ -78,12 +93,12 @@ class PerAccountCollectionCubit extends Cubit<PerAccountCollectionState> {
} else { } else {
///////////////// Logged in /////////////////// ///////////////// Logged in ///////////////////
// AccountRecordCubit // Create AccountRecordCubit
accountRecordCubit ??= AccountRecordCubit( accountRecordCubit ??= AccountRecordCubit(
localAccount: accountInfo.localAccount, localAccount: accountInfo.localAccount,
userLogin: accountInfo.userLogin!); userLogin: accountInfo.userLogin!);
// Update State // Update state to value
nextState = nextState =
_updateAccountRecordState(nextState, accountRecordCubit!.state); _updateAccountRecordState(nextState, accountRecordCubit!.state);
emit(nextState); emit(nextState);
@ -98,17 +113,17 @@ class PerAccountCollectionCubit extends Cubit<PerAccountCollectionState> {
PerAccountCollectionState _updateAccountRecordState( PerAccountCollectionState _updateAccountRecordState(
PerAccountCollectionState prevState, PerAccountCollectionState prevState,
AsyncValue<AccountRecordState> avAccountRecordState) { AsyncValue<AccountRecordState>? avAccountRecordState) {
// Get next state // Get next state
final nextState = final nextState =
state.copyWith(avAccountRecordState: accountRecordCubit!.state); state.copyWith(avAccountRecordState: avAccountRecordState);
// Get bloc parameters // Get bloc parameters
final accountInfo = nextState.accountInfo; final accountInfo = nextState.accountInfo;
// ContactInvitationListCubit // ContactInvitationListCubit
final contactInvitationListRecordPointer = nextState final contactInvitationListRecordPointer = nextState
.avAccountRecordState.asData?.value.contactInvitationRecords .avAccountRecordState?.asData?.value.contactInvitationRecords
.toVeilid(); .toVeilid();
final contactInvitationListCubit = contactInvitationListCubitUpdater.update( final contactInvitationListCubit = contactInvitationListCubitUpdater.update(
@ -118,7 +133,7 @@ class PerAccountCollectionCubit extends Cubit<PerAccountCollectionState> {
// ContactListCubit // ContactListCubit
final contactListRecordPointer = final contactListRecordPointer =
nextState.avAccountRecordState.asData?.value.contactList.toVeilid(); nextState.avAccountRecordState?.asData?.value.contactList.toVeilid();
final contactListCubit = contactListCubitUpdater.update( final contactListCubit = contactListCubitUpdater.update(
contactListRecordPointer == null contactListRecordPointer == null
@ -126,18 +141,18 @@ class PerAccountCollectionCubit extends Cubit<PerAccountCollectionState> {
: (accountInfo, contactListRecordPointer)); : (accountInfo, contactListRecordPointer));
// WaitingInvitationsBlocMapCubit // WaitingInvitationsBlocMapCubit
waitingInvitationsBlocMapCubitUpdater.update( final waitingInvitationsBlocMapCubit = waitingInvitationsBlocMapCubitUpdater
contactInvitationListCubit == null .update(contactInvitationListCubit == null
? null ? null
: (accountInfo, accountRecordCubit!, contactInvitationListCubit)); : (accountInfo, accountRecordCubit!, contactInvitationListCubit));
// ActiveChatCubit // ActiveChatCubit
final activeChatCubit = activeChatCubitUpdater final activeChatCubit = activeChatCubitUpdater.update(
.update(nextState.avAccountRecordState.isData ? true : null); (nextState.avAccountRecordState?.isData ?? false) ? true : null);
// ChatListCubit // ChatListCubit
final chatListRecordPointer = final chatListRecordPointer =
nextState.avAccountRecordState.asData?.value.chatList.toVeilid(); nextState.avAccountRecordState?.asData?.value.chatList.toVeilid();
final chatListCubit = chatListCubitUpdater.update( final chatListCubit = chatListCubitUpdater.update(
chatListRecordPointer == null || activeChatCubit == null chatListRecordPointer == null || activeChatCubit == null
@ -159,19 +174,31 @@ class PerAccountCollectionCubit extends Cubit<PerAccountCollectionState> {
)); ));
// ActiveSingleContactChatBlocMapCubit // ActiveSingleContactChatBlocMapCubit
activeSingleContactChatBlocMapCubitUpdater.update( final activeSingleContactChatBlocMapCubit =
activeConversationsBlocMapCubit == null || activeSingleContactChatBlocMapCubitUpdater.update(
chatListCubit == null || activeConversationsBlocMapCubit == null ||
contactListCubit == null chatListCubit == null ||
? null contactListCubit == null
: ( ? null
accountInfo, : (
activeConversationsBlocMapCubit, accountInfo,
chatListCubit, activeConversationsBlocMapCubit,
contactListCubit chatListCubit,
)); contactListCubit
));
return nextState; // Update available blocs in our state
return nextState.copyWith(
contactInvitationListCubit: contactInvitationListCubit,
accountInfoCubit: accountInfoCubit,
accountRecordCubit: accountRecordCubit,
contactListCubit: contactListCubit,
waitingInvitationsBlocMapCubit: waitingInvitationsBlocMapCubit,
activeChatCubit: activeChatCubit,
chatListCubit: chatListCubit,
activeConversationsBlocMapCubit: activeConversationsBlocMapCubit,
activeSingleContactChatBlocMapCubit:
activeSingleContactChatBlocMapCubit);
} }
T collectionLocator<T>() { T collectionLocator<T>() {

View file

@ -1,7 +1,13 @@
import 'package:async_tools/async_tools.dart'; import 'package:async_tools/async_tools.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import '../../../chat/chat.dart';
import '../../../chat_list/chat_list.dart';
import '../../../contact_invitation/contact_invitation.dart'; import '../../../contact_invitation/contact_invitation.dart';
import '../../../contacts/contacts.dart';
import '../../../conversation/conversation.dart';
import '../../../proto/proto.dart' show Account; import '../../../proto/proto.dart' show Account;
import '../../account_manager.dart'; import '../../account_manager.dart';
@ -9,9 +15,45 @@ part 'per_account_collection_state.freezed.dart';
@freezed @freezed
class PerAccountCollectionState with _$PerAccountCollectionState { class PerAccountCollectionState with _$PerAccountCollectionState {
const factory PerAccountCollectionState( const factory PerAccountCollectionState({
{required AccountInfo accountInfo, required AccountInfo accountInfo,
required AsyncValue<AccountRecordState> avAccountRecordState, required AsyncValue<AccountRecordState>? avAccountRecordState,
required ContactInvitationListCubit? contactInvitationListCubit}) = required AccountInfoCubit? accountInfoCubit,
_PerAccountCollectionState; required AccountRecordCubit? accountRecordCubit,
required ContactInvitationListCubit? contactInvitationListCubit,
required ContactListCubit? contactListCubit,
required WaitingInvitationsBlocMapCubit? waitingInvitationsBlocMapCubit,
required ActiveChatCubit? activeChatCubit,
required ChatListCubit? chatListCubit,
required ActiveConversationsBlocMapCubit? activeConversationsBlocMapCubit,
required ActiveSingleContactChatBlocMapCubit?
activeSingleContactChatBlocMapCubit,
}) = _PerAccountCollectionState;
}
extension PerAccountCollectionStateExt on PerAccountCollectionState {
bool get isReady =>
avAccountRecordState != null &&
avAccountRecordState!.isData &&
accountInfoCubit != null &&
accountRecordCubit != null &&
contactInvitationListCubit != null &&
contactListCubit != null &&
waitingInvitationsBlocMapCubit != null &&
activeChatCubit != null &&
chatListCubit != null &&
activeConversationsBlocMapCubit != null &&
activeSingleContactChatBlocMapCubit != null;
Widget provide({required Widget child}) => MultiBlocProvider(providers: [
BlocProvider.value(value: accountInfoCubit!),
BlocProvider.value(value: accountRecordCubit!),
BlocProvider.value(value: contactInvitationListCubit!),
BlocProvider.value(value: contactListCubit!),
BlocProvider.value(value: waitingInvitationsBlocMapCubit!),
BlocProvider.value(value: activeChatCubit!),
BlocProvider.value(value: chatListCubit!),
BlocProvider.value(value: activeConversationsBlocMapCubit!),
BlocProvider.value(value: activeSingleContactChatBlocMapCubit!),
], child: child);
} }

View file

@ -17,10 +17,23 @@ final _privateConstructorUsedError = UnsupportedError(
/// @nodoc /// @nodoc
mixin _$PerAccountCollectionState { mixin _$PerAccountCollectionState {
AccountInfo get accountInfo => throw _privateConstructorUsedError; AccountInfo get accountInfo => throw _privateConstructorUsedError;
AsyncValue<Account> get avAccountRecordState => AsyncValue<Account>? get avAccountRecordState =>
throw _privateConstructorUsedError;
AccountInfoCubit? get accountInfoCubit => throw _privateConstructorUsedError;
AccountRecordCubit? get accountRecordCubit =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
ContactInvitationListCubit? get contactInvitationListCubit => ContactInvitationListCubit? get contactInvitationListCubit =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
ContactListCubit? get contactListCubit => throw _privateConstructorUsedError;
WaitingInvitationsBlocMapCubit? get waitingInvitationsBlocMapCubit =>
throw _privateConstructorUsedError;
ActiveChatCubit? get activeChatCubit => throw _privateConstructorUsedError;
ChatListCubit? get chatListCubit => throw _privateConstructorUsedError;
ActiveConversationsBlocMapCubit? get activeConversationsBlocMapCubit =>
throw _privateConstructorUsedError;
ActiveSingleContactChatBlocMapCubit?
get activeSingleContactChatBlocMapCubit =>
throw _privateConstructorUsedError;
@JsonKey(ignore: true) @JsonKey(ignore: true)
$PerAccountCollectionStateCopyWith<PerAccountCollectionState> get copyWith => $PerAccountCollectionStateCopyWith<PerAccountCollectionState> get copyWith =>
@ -35,10 +48,19 @@ abstract class $PerAccountCollectionStateCopyWith<$Res> {
@useResult @useResult
$Res call( $Res call(
{AccountInfo accountInfo, {AccountInfo accountInfo,
AsyncValue<Account> avAccountRecordState, AsyncValue<Account>? avAccountRecordState,
ContactInvitationListCubit? contactInvitationListCubit}); AccountInfoCubit? accountInfoCubit,
AccountRecordCubit? accountRecordCubit,
ContactInvitationListCubit? contactInvitationListCubit,
ContactListCubit? contactListCubit,
WaitingInvitationsBlocMapCubit? waitingInvitationsBlocMapCubit,
ActiveChatCubit? activeChatCubit,
ChatListCubit? chatListCubit,
ActiveConversationsBlocMapCubit? activeConversationsBlocMapCubit,
ActiveSingleContactChatBlocMapCubit?
activeSingleContactChatBlocMapCubit});
$AsyncValueCopyWith<Account, $Res> get avAccountRecordState; $AsyncValueCopyWith<Account, $Res>? get avAccountRecordState;
} }
/// @nodoc /// @nodoc
@ -56,29 +78,75 @@ class _$PerAccountCollectionStateCopyWithImpl<$Res,
@override @override
$Res call({ $Res call({
Object? accountInfo = null, Object? accountInfo = null,
Object? avAccountRecordState = null, Object? avAccountRecordState = freezed,
Object? accountInfoCubit = freezed,
Object? accountRecordCubit = freezed,
Object? contactInvitationListCubit = freezed, Object? contactInvitationListCubit = freezed,
Object? contactListCubit = freezed,
Object? waitingInvitationsBlocMapCubit = freezed,
Object? activeChatCubit = freezed,
Object? chatListCubit = freezed,
Object? activeConversationsBlocMapCubit = freezed,
Object? activeSingleContactChatBlocMapCubit = freezed,
}) { }) {
return _then(_value.copyWith( return _then(_value.copyWith(
accountInfo: null == accountInfo accountInfo: null == accountInfo
? _value.accountInfo ? _value.accountInfo
: accountInfo // ignore: cast_nullable_to_non_nullable : accountInfo // ignore: cast_nullable_to_non_nullable
as AccountInfo, as AccountInfo,
avAccountRecordState: null == avAccountRecordState avAccountRecordState: freezed == avAccountRecordState
? _value.avAccountRecordState ? _value.avAccountRecordState
: avAccountRecordState // ignore: cast_nullable_to_non_nullable : avAccountRecordState // ignore: cast_nullable_to_non_nullable
as AsyncValue<Account>, as AsyncValue<Account>?,
accountInfoCubit: freezed == accountInfoCubit
? _value.accountInfoCubit
: accountInfoCubit // ignore: cast_nullable_to_non_nullable
as AccountInfoCubit?,
accountRecordCubit: freezed == accountRecordCubit
? _value.accountRecordCubit
: accountRecordCubit // ignore: cast_nullable_to_non_nullable
as AccountRecordCubit?,
contactInvitationListCubit: freezed == contactInvitationListCubit contactInvitationListCubit: freezed == contactInvitationListCubit
? _value.contactInvitationListCubit ? _value.contactInvitationListCubit
: contactInvitationListCubit // ignore: cast_nullable_to_non_nullable : contactInvitationListCubit // ignore: cast_nullable_to_non_nullable
as ContactInvitationListCubit?, as ContactInvitationListCubit?,
contactListCubit: freezed == contactListCubit
? _value.contactListCubit
: contactListCubit // ignore: cast_nullable_to_non_nullable
as ContactListCubit?,
waitingInvitationsBlocMapCubit: freezed == waitingInvitationsBlocMapCubit
? _value.waitingInvitationsBlocMapCubit
: waitingInvitationsBlocMapCubit // ignore: cast_nullable_to_non_nullable
as WaitingInvitationsBlocMapCubit?,
activeChatCubit: freezed == activeChatCubit
? _value.activeChatCubit
: activeChatCubit // ignore: cast_nullable_to_non_nullable
as ActiveChatCubit?,
chatListCubit: freezed == chatListCubit
? _value.chatListCubit
: chatListCubit // ignore: cast_nullable_to_non_nullable
as ChatListCubit?,
activeConversationsBlocMapCubit: freezed ==
activeConversationsBlocMapCubit
? _value.activeConversationsBlocMapCubit
: activeConversationsBlocMapCubit // ignore: cast_nullable_to_non_nullable
as ActiveConversationsBlocMapCubit?,
activeSingleContactChatBlocMapCubit: freezed ==
activeSingleContactChatBlocMapCubit
? _value.activeSingleContactChatBlocMapCubit
: activeSingleContactChatBlocMapCubit // ignore: cast_nullable_to_non_nullable
as ActiveSingleContactChatBlocMapCubit?,
) as $Val); ) as $Val);
} }
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
$AsyncValueCopyWith<Account, $Res> get avAccountRecordState { $AsyncValueCopyWith<Account, $Res>? get avAccountRecordState {
return $AsyncValueCopyWith<Account, $Res>(_value.avAccountRecordState, if (_value.avAccountRecordState == null) {
return null;
}
return $AsyncValueCopyWith<Account, $Res>(_value.avAccountRecordState!,
(value) { (value) {
return _then(_value.copyWith(avAccountRecordState: value) as $Val); return _then(_value.copyWith(avAccountRecordState: value) as $Val);
}); });
@ -96,11 +164,20 @@ abstract class _$$PerAccountCollectionStateImplCopyWith<$Res>
@useResult @useResult
$Res call( $Res call(
{AccountInfo accountInfo, {AccountInfo accountInfo,
AsyncValue<Account> avAccountRecordState, AsyncValue<Account>? avAccountRecordState,
ContactInvitationListCubit? contactInvitationListCubit}); AccountInfoCubit? accountInfoCubit,
AccountRecordCubit? accountRecordCubit,
ContactInvitationListCubit? contactInvitationListCubit,
ContactListCubit? contactListCubit,
WaitingInvitationsBlocMapCubit? waitingInvitationsBlocMapCubit,
ActiveChatCubit? activeChatCubit,
ChatListCubit? chatListCubit,
ActiveConversationsBlocMapCubit? activeConversationsBlocMapCubit,
ActiveSingleContactChatBlocMapCubit?
activeSingleContactChatBlocMapCubit});
@override @override
$AsyncValueCopyWith<Account, $Res> get avAccountRecordState; $AsyncValueCopyWith<Account, $Res>? get avAccountRecordState;
} }
/// @nodoc /// @nodoc
@ -117,22 +194,64 @@ class __$$PerAccountCollectionStateImplCopyWithImpl<$Res>
@override @override
$Res call({ $Res call({
Object? accountInfo = null, Object? accountInfo = null,
Object? avAccountRecordState = null, Object? avAccountRecordState = freezed,
Object? accountInfoCubit = freezed,
Object? accountRecordCubit = freezed,
Object? contactInvitationListCubit = freezed, Object? contactInvitationListCubit = freezed,
Object? contactListCubit = freezed,
Object? waitingInvitationsBlocMapCubit = freezed,
Object? activeChatCubit = freezed,
Object? chatListCubit = freezed,
Object? activeConversationsBlocMapCubit = freezed,
Object? activeSingleContactChatBlocMapCubit = freezed,
}) { }) {
return _then(_$PerAccountCollectionStateImpl( return _then(_$PerAccountCollectionStateImpl(
accountInfo: null == accountInfo accountInfo: null == accountInfo
? _value.accountInfo ? _value.accountInfo
: accountInfo // ignore: cast_nullable_to_non_nullable : accountInfo // ignore: cast_nullable_to_non_nullable
as AccountInfo, as AccountInfo,
avAccountRecordState: null == avAccountRecordState avAccountRecordState: freezed == avAccountRecordState
? _value.avAccountRecordState ? _value.avAccountRecordState
: avAccountRecordState // ignore: cast_nullable_to_non_nullable : avAccountRecordState // ignore: cast_nullable_to_non_nullable
as AsyncValue<Account>, as AsyncValue<Account>?,
accountInfoCubit: freezed == accountInfoCubit
? _value.accountInfoCubit
: accountInfoCubit // ignore: cast_nullable_to_non_nullable
as AccountInfoCubit?,
accountRecordCubit: freezed == accountRecordCubit
? _value.accountRecordCubit
: accountRecordCubit // ignore: cast_nullable_to_non_nullable
as AccountRecordCubit?,
contactInvitationListCubit: freezed == contactInvitationListCubit contactInvitationListCubit: freezed == contactInvitationListCubit
? _value.contactInvitationListCubit ? _value.contactInvitationListCubit
: contactInvitationListCubit // ignore: cast_nullable_to_non_nullable : contactInvitationListCubit // ignore: cast_nullable_to_non_nullable
as ContactInvitationListCubit?, as ContactInvitationListCubit?,
contactListCubit: freezed == contactListCubit
? _value.contactListCubit
: contactListCubit // ignore: cast_nullable_to_non_nullable
as ContactListCubit?,
waitingInvitationsBlocMapCubit: freezed == waitingInvitationsBlocMapCubit
? _value.waitingInvitationsBlocMapCubit
: waitingInvitationsBlocMapCubit // ignore: cast_nullable_to_non_nullable
as WaitingInvitationsBlocMapCubit?,
activeChatCubit: freezed == activeChatCubit
? _value.activeChatCubit
: activeChatCubit // ignore: cast_nullable_to_non_nullable
as ActiveChatCubit?,
chatListCubit: freezed == chatListCubit
? _value.chatListCubit
: chatListCubit // ignore: cast_nullable_to_non_nullable
as ChatListCubit?,
activeConversationsBlocMapCubit: freezed ==
activeConversationsBlocMapCubit
? _value.activeConversationsBlocMapCubit
: activeConversationsBlocMapCubit // ignore: cast_nullable_to_non_nullable
as ActiveConversationsBlocMapCubit?,
activeSingleContactChatBlocMapCubit: freezed ==
activeSingleContactChatBlocMapCubit
? _value.activeSingleContactChatBlocMapCubit
: activeSingleContactChatBlocMapCubit // ignore: cast_nullable_to_non_nullable
as ActiveSingleContactChatBlocMapCubit?,
)); ));
} }
} }
@ -143,18 +262,43 @@ class _$PerAccountCollectionStateImpl implements _PerAccountCollectionState {
const _$PerAccountCollectionStateImpl( const _$PerAccountCollectionStateImpl(
{required this.accountInfo, {required this.accountInfo,
required this.avAccountRecordState, required this.avAccountRecordState,
required this.contactInvitationListCubit}); required this.accountInfoCubit,
required this.accountRecordCubit,
required this.contactInvitationListCubit,
required this.contactListCubit,
required this.waitingInvitationsBlocMapCubit,
required this.activeChatCubit,
required this.chatListCubit,
required this.activeConversationsBlocMapCubit,
required this.activeSingleContactChatBlocMapCubit});
@override @override
final AccountInfo accountInfo; final AccountInfo accountInfo;
@override @override
final AsyncValue<Account> avAccountRecordState; final AsyncValue<Account>? avAccountRecordState;
@override
final AccountInfoCubit? accountInfoCubit;
@override
final AccountRecordCubit? accountRecordCubit;
@override @override
final ContactInvitationListCubit? contactInvitationListCubit; final ContactInvitationListCubit? contactInvitationListCubit;
@override
final ContactListCubit? contactListCubit;
@override
final WaitingInvitationsBlocMapCubit? waitingInvitationsBlocMapCubit;
@override
final ActiveChatCubit? activeChatCubit;
@override
final ChatListCubit? chatListCubit;
@override
final ActiveConversationsBlocMapCubit? activeConversationsBlocMapCubit;
@override
final ActiveSingleContactChatBlocMapCubit?
activeSingleContactChatBlocMapCubit;
@override @override
String toString() { String toString() {
return 'PerAccountCollectionState(accountInfo: $accountInfo, avAccountRecordState: $avAccountRecordState, contactInvitationListCubit: $contactInvitationListCubit)'; return 'PerAccountCollectionState(accountInfo: $accountInfo, avAccountRecordState: $avAccountRecordState, accountInfoCubit: $accountInfoCubit, accountRecordCubit: $accountRecordCubit, contactInvitationListCubit: $contactInvitationListCubit, contactListCubit: $contactListCubit, waitingInvitationsBlocMapCubit: $waitingInvitationsBlocMapCubit, activeChatCubit: $activeChatCubit, chatListCubit: $chatListCubit, activeConversationsBlocMapCubit: $activeConversationsBlocMapCubit, activeSingleContactChatBlocMapCubit: $activeSingleContactChatBlocMapCubit)';
} }
@override @override
@ -166,15 +310,48 @@ class _$PerAccountCollectionStateImpl implements _PerAccountCollectionState {
other.accountInfo == accountInfo) && other.accountInfo == accountInfo) &&
(identical(other.avAccountRecordState, avAccountRecordState) || (identical(other.avAccountRecordState, avAccountRecordState) ||
other.avAccountRecordState == avAccountRecordState) && other.avAccountRecordState == avAccountRecordState) &&
(identical(other.accountInfoCubit, accountInfoCubit) ||
other.accountInfoCubit == accountInfoCubit) &&
(identical(other.accountRecordCubit, accountRecordCubit) ||
other.accountRecordCubit == accountRecordCubit) &&
(identical(other.contactInvitationListCubit, (identical(other.contactInvitationListCubit,
contactInvitationListCubit) || contactInvitationListCubit) ||
other.contactInvitationListCubit == other.contactInvitationListCubit ==
contactInvitationListCubit)); contactInvitationListCubit) &&
(identical(other.contactListCubit, contactListCubit) ||
other.contactListCubit == contactListCubit) &&
(identical(other.waitingInvitationsBlocMapCubit,
waitingInvitationsBlocMapCubit) ||
other.waitingInvitationsBlocMapCubit ==
waitingInvitationsBlocMapCubit) &&
(identical(other.activeChatCubit, activeChatCubit) ||
other.activeChatCubit == activeChatCubit) &&
(identical(other.chatListCubit, chatListCubit) ||
other.chatListCubit == chatListCubit) &&
(identical(other.activeConversationsBlocMapCubit,
activeConversationsBlocMapCubit) ||
other.activeConversationsBlocMapCubit ==
activeConversationsBlocMapCubit) &&
(identical(other.activeSingleContactChatBlocMapCubit,
activeSingleContactChatBlocMapCubit) ||
other.activeSingleContactChatBlocMapCubit ==
activeSingleContactChatBlocMapCubit));
} }
@override @override
int get hashCode => Object.hash(runtimeType, accountInfo, int get hashCode => Object.hash(
avAccountRecordState, contactInvitationListCubit); runtimeType,
accountInfo,
avAccountRecordState,
accountInfoCubit,
accountRecordCubit,
contactInvitationListCubit,
contactListCubit,
waitingInvitationsBlocMapCubit,
activeChatCubit,
chatListCubit,
activeConversationsBlocMapCubit,
activeSingleContactChatBlocMapCubit);
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@ -186,18 +363,45 @@ class _$PerAccountCollectionStateImpl implements _PerAccountCollectionState {
abstract class _PerAccountCollectionState implements PerAccountCollectionState { abstract class _PerAccountCollectionState implements PerAccountCollectionState {
const factory _PerAccountCollectionState( const factory _PerAccountCollectionState(
{required final AccountInfo accountInfo, {required final AccountInfo accountInfo,
required final AsyncValue<Account> avAccountRecordState, required final AsyncValue<Account>? avAccountRecordState,
required final ContactInvitationListCubit? required final AccountInfoCubit? accountInfoCubit,
contactInvitationListCubit}) = _$PerAccountCollectionStateImpl; required final AccountRecordCubit? accountRecordCubit,
required final ContactInvitationListCubit? contactInvitationListCubit,
required final ContactListCubit? contactListCubit,
required final WaitingInvitationsBlocMapCubit?
waitingInvitationsBlocMapCubit,
required final ActiveChatCubit? activeChatCubit,
required final ChatListCubit? chatListCubit,
required final ActiveConversationsBlocMapCubit?
activeConversationsBlocMapCubit,
required final ActiveSingleContactChatBlocMapCubit?
activeSingleContactChatBlocMapCubit}) =
_$PerAccountCollectionStateImpl;
@override @override
AccountInfo get accountInfo; AccountInfo get accountInfo;
@override @override
AsyncValue<Account> get avAccountRecordState; AsyncValue<Account>? get avAccountRecordState;
@override
AccountInfoCubit? get accountInfoCubit;
@override
AccountRecordCubit? get accountRecordCubit;
@override @override
ContactInvitationListCubit? get contactInvitationListCubit; ContactInvitationListCubit? get contactInvitationListCubit;
@override @override
ContactListCubit? get contactListCubit;
@override
WaitingInvitationsBlocMapCubit? get waitingInvitationsBlocMapCubit;
@override
ActiveChatCubit? get activeChatCubit;
@override
ChatListCubit? get chatListCubit;
@override
ActiveConversationsBlocMapCubit? get activeConversationsBlocMapCubit;
@override
ActiveSingleContactChatBlocMapCubit? get activeSingleContactChatBlocMapCubit;
@override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$PerAccountCollectionStateImplCopyWith<_$PerAccountCollectionStateImpl> _$$PerAccountCollectionStateImplCopyWith<_$PerAccountCollectionStateImpl>
get copyWith => throw _privateConstructorUsedError; get copyWith => throw _privateConstructorUsedError;

View file

@ -116,14 +116,11 @@ class _EditAccountPageState extends State<EditAccountPage> {
}); });
try { try {
// Look up account cubit for this specific account // Look up account cubit for this specific account
final perAccountCollectionCubit = final accountRecordCubit = context.read<AccountRecordCubit>();
context.read<PerAccountCollectionBlocMapCubit>();
await perAccountCollectionCubit.operateAsync( // Update account profile DHT record
widget.superIdentityRecordKey, closure: (c) async { // This triggers ConversationCubits to update
// Update account profile DHT record await accountRecordCubit.updateProfile(newProfile);
// This triggers ConversationCubits to update
await c.accountRecordCubit!.updateProfile(newProfile);
});
// Update local account profile // Update local account profile
await AccountRepository.instance.editAccountProfile( await AccountRepository.instance.editAccountProfile(

View file

@ -105,7 +105,8 @@ class _DrawerMenuState extends State<DrawerMenu> {
Widget _getAccountList( Widget _getAccountList(
{required IList<LocalAccount> localAccounts, {required IList<LocalAccount> localAccounts,
required TypedKey? activeLocalAccount, required TypedKey? activeLocalAccount,
required AccountRecordsBlocMapState accountRecords}) { required PerAccountCollectionBlocMapState
perAccountCollectionBlocMapState}) {
final theme = Theme.of(context); final theme = Theme.of(context);
final scaleScheme = theme.extension<ScaleScheme>()!; final scaleScheme = theme.extension<ScaleScheme>()!;
@ -116,11 +117,13 @@ class _DrawerMenuState extends State<DrawerMenu> {
final superIdentityRecordKey = la.superIdentity.recordKey; final superIdentityRecordKey = la.superIdentity.recordKey;
// See if this account is logged in // See if this account is logged in
final acctRecord = accountRecords.get(superIdentityRecordKey); final avAccountRecordState = perAccountCollectionBlocMapState
if (acctRecord != null) { .get(superIdentityRecordKey)
?.avAccountRecordState;
if (avAccountRecordState != null) {
// Account is logged in // Account is logged in
final scale = theme.extension<ScaleScheme>()!.tertiaryScale; final scale = theme.extension<ScaleScheme>()!.tertiaryScale;
final loggedInAccount = acctRecord.when( final loggedInAccount = avAccountRecordState.when(
data: (value) => _makeAccountWidget( data: (value) => _makeAccountWidget(
name: value.profile.name, name: value.profile.name,
scale: scale, scale: scale,
@ -233,7 +236,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
//final textTheme = theme.textTheme; //final textTheme = theme.textTheme;
final localAccounts = context.watch<LocalAccountsCubit>().state; final localAccounts = context.watch<LocalAccountsCubit>().state;
final accountRecords = final perAccountCollectionBlocMapState =
context.watch<PerAccountCollectionBlocMapCubit>().state; context.watch<PerAccountCollectionBlocMapCubit>().state;
final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state; final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state;
final gradient = LinearGradient( final gradient = LinearGradient(
@ -278,7 +281,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
_getAccountList( _getAccountList(
localAccounts: localAccounts, localAccounts: localAccounts,
activeLocalAccount: activeLocalAccount, activeLocalAccount: activeLocalAccount,
accountRecords: accountRecords), perAccountCollectionBlocMapState: perAccountCollectionBlocMapState),
_getBottomButtons(), _getBottomButtons(),
const Spacer(), const Spacer(),
Row(children: [ Row(children: [

View file

@ -9,11 +9,8 @@ import 'package:veilid_support/veilid_support.dart';
import '../../account_manager/account_manager.dart'; import '../../account_manager/account_manager.dart';
import '../../chat/chat.dart'; import '../../chat/chat.dart';
import '../../chat_list/chat_list.dart';
import '../../contact_invitation/contact_invitation.dart'; import '../../contact_invitation/contact_invitation.dart';
import '../../contacts/contacts.dart'; import '../../contacts/contacts.dart';
import '../../conversation/conversation.dart';
import '../../proto/proto.dart' as proto;
import '../../theme/theme.dart'; import '../../theme/theme.dart';
import '../../tools/tools.dart'; import '../../tools/tools.dart';
import 'active_account_page_controller_wrapper.dart'; import 'active_account_page_controller_wrapper.dart';
@ -98,113 +95,39 @@ class HomeScreenState extends State<HomeScreen> {
return const HomeAccountReadyMain(); return const HomeAccountReadyMain();
} }
Widget _buildUnlockedAccount(BuildContext context) { Widget _buildAccount(BuildContext context, TypedKey superIdentityRecordKey,
final accountRecordKey = context.select<AccountInfoCubit, TypedKey>( PerAccountCollectionState perAccountCollectionState) {
(c) => c.state.unlockedAccountInfo!.accountRecordKey); switch (perAccountCollectionState.accountInfo.status) {
final contactListRecordPointer = case AccountInfoStatus.accountInvalid:
context.select<AccountRecordCubit, OwnedDHTRecordPointer?>( return const HomeAccountInvalid();
(c) => c.state.asData?.value.contactList.toVeilid()); case AccountInfoStatus.accountLocked:
final contactInvitationListRecordPointer = return const HomeAccountLocked();
context.select<AccountRecordCubit, OwnedDHTRecordPointer?>( case AccountInfoStatus.accountUnlocked:
(c) => c.state.asData?.value.contactInvitationRecords.toVeilid()); // Are we ready to render?
final chatListRecordPointer = if (!perAccountCollectionState.isReady) {
context.select<AccountRecordCubit, OwnedDHTRecordPointer?>( return waitingPage();
(c) => c.state.asData?.value.chatList.toVeilid()); }
if (contactListRecordPointer == null || // Re-export all ready blocs to the account display subtree
contactInvitationListRecordPointer == null || return perAccountCollectionState.provide(
chatListRecordPointer == null) { child: MultiBlocListener(listeners: [
return waitingPage();
}
return MultiBlocProvider(
providers: [
// Contact Cubits
BlocProvider(
create: (context) => ContactInvitationListCubit(
locator: context.read,
accountRecordKey: accountRecordKey,
contactInvitationListRecordPointer:
contactInvitationListRecordPointer,
)),
BlocProvider(
create: (context) => ContactListCubit(
locator: context.read,
accountRecordKey: accountRecordKey,
contactListRecordPointer: contactListRecordPointer)),
BlocProvider(
create: (context) => WaitingInvitationsBlocMapCubit(
locator: context.read,
)),
// Chat Cubits
BlocProvider(
create: (context) => ActiveChatCubit(
null,
)),
BlocProvider(
create: (context) => ChatListCubit(
locator: context.read,
accountRecordKey: accountRecordKey,
chatListRecordPointer: chatListRecordPointer)),
// Conversation Cubits
BlocProvider(
create: (context) => ActiveConversationsBlocMapCubit(
locator: context.read,
)),
BlocProvider(
create: (context) => ActiveSingleContactChatBlocMapCubit(
locator: context.read,
)),
],
child: MultiBlocListener(listeners: [
BlocListener<WaitingInvitationsBlocMapCubit, BlocListener<WaitingInvitationsBlocMapCubit,
WaitingInvitationsBlocMapState>( WaitingInvitationsBlocMapState>(
listener: _invitationStatusListener, listener: _invitationStatusListener,
) )
], child: Builder(builder: _buildAccountReadyDeviceSpecific))); ], child: Builder(builder: _buildAccountReadyDeviceSpecific)));
}
} }
Widget _buildAccount(BuildContext context, TypedKey superIdentityRecordKey,
PerAccountCollectionCubit perAccountCollectionCubit) =>
BlocBuilder<PerAccountCollectionCubit, PerAccountCollectionState>(
key: ValueKey(superIdentityRecordKey),
bloc: perAccountCollectionCubit,
builder: (context, state) {
switch (state.accountInfo.status) {
case AccountInfoStatus.accountInvalid:
return const HomeAccountInvalid();
case AccountInfoStatus.accountLocked:
return const HomeAccountLocked();
case AccountInfoStatus.accountUnlocked:
// Get the current active account record cubit
final activeAccountRecordCubit = context.select<
PerAccountCollectionBlocMapCubit,
AccountRecordCubit?>(
(c) => c.tryOperate(superIdentityRecordKey,
closure: (x) => x));
if (activeAccountRecordCubit == null) {
return waitingPage();
}
return MultiBlocProvider(providers: [
BlocProvider<AccountRecordCubit>.value(
value: activeAccountRecordCubit),
], child: Builder(builder: _buildUnlockedAccount));
}
});
};
Widget _buildAccountPageView(BuildContext context) { Widget _buildAccountPageView(BuildContext context) {
final localAccounts = context.watch<LocalAccountsCubit>().state; final localAccounts = context.watch<LocalAccountsCubit>().state;
final activeLocalAccountCubit = context.watch<ActiveLocalAccountCubit>(); final activeLocalAccountCubit =
final perAccountCollectionBlocMapCubit = context.watch<ActiveLocalAccountCubit>().state;
context.watch<PerAccountCollectionBlocMapCubit>(); final perAccountCollectionBlocMapState =
context.watch<PerAccountCollectionBlocMapCubit>().state;
final activeIndex = localAccounts.indexWhere( final activeIndex = localAccounts.indexWhere(
(x) => x.superIdentity.recordKey == activeLocalAccountCubit.state); (x) => x.superIdentity.recordKey == activeLocalAccountCubit);
if (activeIndex == -1) { if (activeIndex == -1) {
return const HomeNoActive(); return const HomeNoActive();
} }
@ -231,16 +154,15 @@ class HomeScreenState extends State<HomeScreen> {
itemBuilder: (context, index) { itemBuilder: (context, index) {
final superIdentityRecordKey = final superIdentityRecordKey =
localAccounts[index].superIdentity.recordKey; localAccounts[index].superIdentity.recordKey;
final perAccountCollectionCubit = final perAccountCollectionState =
perAccountCollectionBlocMapCubit.tryOperate( perAccountCollectionBlocMapState
superIdentityRecordKey, .get(superIdentityRecordKey);
closure: (c) => c); if (perAccountCollectionState == null) {
if (perAccountCollectionCubit == null) {
return HomeAccountMissing( return HomeAccountMissing(
key: ValueKey(superIdentityRecordKey)); key: ValueKey(superIdentityRecordKey));
} }
return _buildAccount(context, superIdentityRecordKey, return _buildAccount(context, superIdentityRecordKey,
perAccountCollectionCubit); perAccountCollectionState);
}))); })));
} }