mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2025-05-02 14:26:12 -04:00
clean up context locators
This commit is contained in:
parent
751022e743
commit
2ccad50f9a
31 changed files with 603 additions and 542 deletions
|
@ -1,3 +1,2 @@
|
|||
export 'home_account_ready_chat.dart';
|
||||
export 'home_account_ready_main.dart';
|
||||
export 'home_account_ready_shell.dart';
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:flutter_zoom_drawer/flutter_zoom_drawer.dart';
|
|||
|
||||
import '../../../account_manager/account_manager.dart';
|
||||
import '../../../chat/chat.dart';
|
||||
import '../../../proto/proto.dart' as proto;
|
||||
import '../../../theme/theme.dart';
|
||||
import '../../../tools/tools.dart';
|
||||
import 'main_pager/main_pager.dart';
|
||||
|
@ -29,7 +30,8 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
|
|||
}
|
||||
|
||||
Widget buildUserPanel() => Builder(builder: (context) {
|
||||
final account = context.watch<AccountRecordCubit>().state;
|
||||
final profile = context.select<AccountRecordCubit, proto.Profile>(
|
||||
(c) => c.state.asData!.value.profile);
|
||||
final theme = Theme.of(context);
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
|
||||
|
@ -50,9 +52,7 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
|
|||
await ctrl.toggle?.call();
|
||||
//await GoRouterHelper(context).push('/settings');
|
||||
}).paddingLTRB(0, 0, 8, 0),
|
||||
asyncValueBuilder(account,
|
||||
(_, account) => ProfileWidget(profile: account.profile))
|
||||
.expanded(),
|
||||
ProfileWidget(profile: profile).expanded(),
|
||||
]).paddingAll(8),
|
||||
const MainPager().expanded()
|
||||
]);
|
||||
|
@ -72,8 +72,8 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
|
|||
return const NoConversationWidget();
|
||||
}
|
||||
return ChatComponentWidget.builder(
|
||||
localConversationRecordKey: activeChatLocalConversationKey,
|
||||
);
|
||||
localConversationRecordKey: activeChatLocalConversationKey,
|
||||
key: ValueKey(activeChatLocalConversationKey));
|
||||
}
|
||||
|
||||
// ignore: prefer_expression_function_bodies
|
||||
|
|
|
@ -1,158 +0,0 @@
|
|||
import 'package:async_tools/async_tools.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../../account_manager/account_manager.dart';
|
||||
import '../../../chat/chat.dart';
|
||||
import '../../../chat_list/chat_list.dart';
|
||||
import '../../../contact_invitation/contact_invitation.dart';
|
||||
import '../../../contacts/contacts.dart';
|
||||
import '../../../conversation/conversation.dart';
|
||||
import '../../../router/router.dart';
|
||||
import '../../../theme/theme.dart';
|
||||
|
||||
class HomeAccountReadyShell extends StatefulWidget {
|
||||
factory HomeAccountReadyShell(
|
||||
{required BuildContext context, required Widget child, Key? key}) {
|
||||
// These must exist in order for the account to
|
||||
// be considered 'ready' for this widget subtree
|
||||
final unlockedAccountInfo = context.watch<UnlockedAccountInfo>();
|
||||
final routerCubit = context.read<RouterCubit>();
|
||||
|
||||
return HomeAccountReadyShell._(
|
||||
unlockedAccountInfo: unlockedAccountInfo,
|
||||
routerCubit: routerCubit,
|
||||
key: key,
|
||||
child: child);
|
||||
}
|
||||
const HomeAccountReadyShell._(
|
||||
{required this.unlockedAccountInfo,
|
||||
required this.routerCubit,
|
||||
required this.child,
|
||||
super.key});
|
||||
|
||||
@override
|
||||
HomeAccountReadyShellState createState() => HomeAccountReadyShellState();
|
||||
|
||||
final Widget child;
|
||||
final UnlockedAccountInfo unlockedAccountInfo;
|
||||
final RouterCubit routerCubit;
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties
|
||||
..add(DiagnosticsProperty<UnlockedAccountInfo>(
|
||||
'unlockedAccountInfo', unlockedAccountInfo))
|
||||
..add(DiagnosticsProperty<RouterCubit>('routerCubit', routerCubit));
|
||||
}
|
||||
}
|
||||
|
||||
class HomeAccountReadyShellState extends State<HomeAccountReadyShell> {
|
||||
final SingleStateProcessor<WaitingInvitationsBlocMapState>
|
||||
_singleInvitationStatusProcessor = SingleStateProcessor();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
// Process all accepted or rejected invitations
|
||||
void _invitationStatusListener(
|
||||
BuildContext context, WaitingInvitationsBlocMapState state) {
|
||||
_singleInvitationStatusProcessor.updateState(state, (newState) async {
|
||||
final contactListCubit = context.read<ContactListCubit>();
|
||||
final contactInvitationListCubit =
|
||||
context.read<ContactInvitationListCubit>();
|
||||
|
||||
for (final entry in newState.entries) {
|
||||
final contactRequestInboxRecordKey = entry.key;
|
||||
final invStatus = entry.value.asData?.value;
|
||||
// Skip invitations that have not yet been accepted or rejected
|
||||
if (invStatus == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Delete invitation and process the accepted or rejected contact
|
||||
final acceptedContact = invStatus.acceptedContact;
|
||||
if (acceptedContact != null) {
|
||||
await contactInvitationListCubit.deleteInvitation(
|
||||
accepted: true,
|
||||
contactRequestInboxRecordKey: contactRequestInboxRecordKey);
|
||||
|
||||
// Accept
|
||||
await contactListCubit.createContact(
|
||||
remoteProfile: acceptedContact.remoteProfile,
|
||||
remoteSuperIdentity: acceptedContact.remoteIdentity,
|
||||
remoteConversationRecordKey:
|
||||
acceptedContact.remoteConversationRecordKey,
|
||||
localConversationRecordKey:
|
||||
acceptedContact.localConversationRecordKey,
|
||||
);
|
||||
} else {
|
||||
// Reject
|
||||
await contactInvitationListCubit.deleteInvitation(
|
||||
accepted: false,
|
||||
contactRequestInboxRecordKey: contactRequestInboxRecordKey);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// XXX: Should probably eliminate this in favor
|
||||
// of streaming changes into other cubits. Too much rebuilding!
|
||||
// should not need to 'watch' all these cubits
|
||||
final account = context.watch<AccountRecordCubit>().state.asData?.value;
|
||||
if (account == null) {
|
||||
return waitingPage();
|
||||
}
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
// Contact Cubits
|
||||
BlocProvider(
|
||||
create: (context) => ContactInvitationListCubit(
|
||||
unlockedAccountInfo: widget.unlockedAccountInfo,
|
||||
account: account)),
|
||||
BlocProvider(
|
||||
create: (context) => ContactListCubit(
|
||||
unlockedAccountInfo: widget.unlockedAccountInfo,
|
||||
account: account)),
|
||||
BlocProvider(
|
||||
create: (context) => WaitingInvitationsBlocMapCubit(
|
||||
unlockedAccountInfo: widget.unlockedAccountInfo,
|
||||
account: account)
|
||||
..follow(context.read<ContactInvitationListCubit>())),
|
||||
// Chat Cubits
|
||||
BlocProvider(
|
||||
create: (context) => ActiveChatCubit(null,
|
||||
routerCubit: context.read<RouterCubit>())),
|
||||
BlocProvider(
|
||||
create: (context) => ChatListCubit(
|
||||
unlockedAccountInfo: widget.unlockedAccountInfo,
|
||||
activeChatCubit: context.read<ActiveChatCubit>(),
|
||||
account: account)),
|
||||
// Conversation Cubits
|
||||
BlocProvider(
|
||||
create: (context) => ActiveConversationsBlocMapCubit(
|
||||
unlockedAccountInfo: widget.unlockedAccountInfo,
|
||||
contactListCubit: context.read<ContactListCubit>(),
|
||||
accountRecordCubit: context.read<AccountRecordCubit>())
|
||||
..follow(context.read<ChatListCubit>())),
|
||||
BlocProvider(
|
||||
create: (context) => ActiveSingleContactChatBlocMapCubit(
|
||||
unlockedAccountInfo: widget.unlockedAccountInfo,
|
||||
contactListCubit: context.read<ContactListCubit>(),
|
||||
chatListCubit: context.read<ChatListCubit>())
|
||||
..follow(context.read<ActiveConversationsBlocMapCubit>())),
|
||||
],
|
||||
child: MultiBlocListener(listeners: [
|
||||
BlocListener<WaitingInvitationsBlocMapCubit,
|
||||
WaitingInvitationsBlocMapState>(
|
||||
listener: _invitationStatusListener,
|
||||
)
|
||||
], child: widget.child));
|
||||
}
|
||||
}
|
|
@ -1,11 +1,20 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:async_tools/async_tools.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_zoom_drawer/flutter_zoom_drawer.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:veilid_support/veilid_support.dart';
|
||||
|
||||
import '../../account_manager/account_manager.dart';
|
||||
import '../../chat/chat.dart';
|
||||
import '../../chat_list/chat_list.dart';
|
||||
import '../../contact_invitation/contact_invitation.dart';
|
||||
import '../../contacts/contacts.dart';
|
||||
import '../../conversation/conversation.dart';
|
||||
import '../../proto/proto.dart' as proto;
|
||||
import '../../router/router.dart';
|
||||
import '../../theme/theme.dart';
|
||||
import 'drawer_menu/drawer_menu.dart';
|
||||
import 'home_account_invalid.dart';
|
||||
|
@ -33,25 +42,133 @@ class HomeShellState extends State<HomeShell> {
|
|||
super.dispose();
|
||||
}
|
||||
|
||||
Widget buildWithLogin(BuildContext context) {
|
||||
final accountInfo = context.watch<ActiveAccountInfoCubit>().state;
|
||||
final accountRecordsCubit = context.watch<AccountRecordsBlocMapCubit>();
|
||||
if (!accountInfo.active) {
|
||||
// Process all accepted or rejected invitations
|
||||
void _invitationStatusListener(
|
||||
BuildContext context, WaitingInvitationsBlocMapState state) {
|
||||
_singleInvitationStatusProcessor.updateState(state, (newState) async {
|
||||
final contactListCubit = context.read<ContactListCubit>();
|
||||
final contactInvitationListCubit =
|
||||
context.read<ContactInvitationListCubit>();
|
||||
|
||||
for (final entry in newState.entries) {
|
||||
final contactRequestInboxRecordKey = entry.key;
|
||||
final invStatus = entry.value.asData?.value;
|
||||
// Skip invitations that have not yet been accepted or rejected
|
||||
if (invStatus == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Delete invitation and process the accepted or rejected contact
|
||||
final acceptedContact = invStatus.acceptedContact;
|
||||
if (acceptedContact != null) {
|
||||
await contactInvitationListCubit.deleteInvitation(
|
||||
accepted: true,
|
||||
contactRequestInboxRecordKey: contactRequestInboxRecordKey);
|
||||
|
||||
// Accept
|
||||
await contactListCubit.createContact(
|
||||
profile: acceptedContact.remoteProfile,
|
||||
remoteSuperIdentity: acceptedContact.remoteIdentity,
|
||||
remoteConversationRecordKey:
|
||||
acceptedContact.remoteConversationRecordKey,
|
||||
localConversationRecordKey:
|
||||
acceptedContact.localConversationRecordKey,
|
||||
);
|
||||
} else {
|
||||
// Reject
|
||||
await contactInvitationListCubit.deleteInvitation(
|
||||
accepted: false,
|
||||
contactRequestInboxRecordKey: contactRequestInboxRecordKey);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildActiveAccount(BuildContext context) {
|
||||
final accountRecordKey = context.select<ActiveAccountInfoCubit, TypedKey>(
|
||||
(c) => c.state.unlockedAccountInfo!.accountRecordKey);
|
||||
final contactListRecordPointer =
|
||||
context.select<AccountRecordCubit, OwnedDHTRecordPointer?>(
|
||||
(c) => c.state.asData?.value.contactList.toVeilid());
|
||||
final contactInvitationListRecordPointer =
|
||||
context.select<AccountRecordCubit, OwnedDHTRecordPointer?>(
|
||||
(c) => c.state.asData?.value.contactInvitationRecords.toVeilid());
|
||||
final chatListRecordPointer =
|
||||
context.select<AccountRecordCubit, OwnedDHTRecordPointer?>(
|
||||
(c) => c.state.asData?.value.chatList.toVeilid());
|
||||
|
||||
if (contactListRecordPointer == null ||
|
||||
contactInvitationListRecordPointer == null ||
|
||||
chatListRecordPointer == null) {
|
||||
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,
|
||||
routerCubit: context.read<RouterCubit>())),
|
||||
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,
|
||||
WaitingInvitationsBlocMapState>(
|
||||
listener: _invitationStatusListener,
|
||||
)
|
||||
], child: widget.child));
|
||||
}
|
||||
|
||||
Widget _buildWithLogin(BuildContext context) {
|
||||
// Get active account info status
|
||||
final (
|
||||
accountInfoStatus,
|
||||
accountInfoActive,
|
||||
superIdentityRecordKey
|
||||
) = context
|
||||
.select<ActiveAccountInfoCubit, (AccountInfoStatus, bool, TypedKey?)>(
|
||||
(c) => (
|
||||
c.state.status,
|
||||
c.state.active,
|
||||
c.state.unlockedAccountInfo?.superIdentityRecordKey
|
||||
));
|
||||
|
||||
if (!accountInfoActive) {
|
||||
// If no logged in user is active, show the loading panel
|
||||
return const HomeNoActive();
|
||||
}
|
||||
|
||||
final superIdentityRecordKey =
|
||||
accountInfo.unlockedAccountInfo?.superIdentityRecordKey;
|
||||
final activeCubit = superIdentityRecordKey == null
|
||||
? null
|
||||
: accountRecordsCubit.tryOperate(superIdentityRecordKey,
|
||||
closure: (c) => c);
|
||||
if (activeCubit == null) {
|
||||
return waitingPage();
|
||||
}
|
||||
|
||||
switch (accountInfo.status) {
|
||||
switch (accountInfoStatus) {
|
||||
case AccountInfoStatus.noAccount:
|
||||
return const HomeAccountMissing();
|
||||
case AccountInfoStatus.accountInvalid:
|
||||
|
@ -59,17 +176,21 @@ class HomeShellState extends State<HomeShell> {
|
|||
case AccountInfoStatus.accountLocked:
|
||||
return const HomeAccountLocked();
|
||||
case AccountInfoStatus.accountReady:
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider<AccountRecordCubit>.value(value: activeCubit),
|
||||
],
|
||||
child: MultiProvider(providers: [
|
||||
Provider<UnlockedAccountInfo>.value(
|
||||
value: accountInfo.unlockedAccountInfo!,
|
||||
),
|
||||
Provider<ZoomDrawerController>.value(
|
||||
value: _zoomDrawerController),
|
||||
], child: widget.child));
|
||||
|
||||
// Get the current active account record cubit
|
||||
final activeAccountRecordCubit =
|
||||
context.select<AccountRecordsBlocMapCubit, AccountRecordCubit?>(
|
||||
(c) => superIdentityRecordKey == null
|
||||
? null
|
||||
: c.tryOperate(superIdentityRecordKey, closure: (x) => x));
|
||||
if (activeAccountRecordCubit == null) {
|
||||
return waitingPage();
|
||||
}
|
||||
|
||||
return MultiBlocProvider(providers: [
|
||||
BlocProvider<AccountRecordCubit>.value(
|
||||
value: activeAccountRecordCubit),
|
||||
], child: Builder(builder: _buildActiveAccount));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +217,9 @@ class HomeShellState extends State<HomeShell> {
|
|||
mainScreen: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: scale.primaryScale.activeElementBackground),
|
||||
child: buildWithLogin(context)),
|
||||
child: Provider<ZoomDrawerController>.value(
|
||||
value: _zoomDrawerController,
|
||||
child: Builder(builder: _buildWithLogin))),
|
||||
borderRadius: 24,
|
||||
showShadow: true,
|
||||
angle: 0,
|
||||
|
@ -112,5 +235,54 @@ class HomeShellState extends State<HomeShell> {
|
|||
)));
|
||||
}
|
||||
|
||||
final ZoomDrawerController _zoomDrawerController = ZoomDrawerController();
|
||||
final _zoomDrawerController = ZoomDrawerController();
|
||||
final _singleInvitationStatusProcessor =
|
||||
SingleStateProcessor<WaitingInvitationsBlocMapState>();
|
||||
}
|
||||
|
||||
// class HomeAccountReadyShell extends StatefulWidget {
|
||||
// factory HomeAccountReadyShell(
|
||||
// {required BuildContext context, required Widget child, Key? key}) {
|
||||
// // These must exist in order for the account to
|
||||
// // be considered 'ready' for this widget subtree
|
||||
// final unlockedAccountInfo = context.watch<UnlockedAccountInfo>();
|
||||
// final routerCubit = context.read<RouterCubit>();
|
||||
|
||||
// return HomeAccountReadyShell._(
|
||||
// unlockedAccountInfo: unlockedAccountInfo,
|
||||
// routerCubit: routerCubit,
|
||||
// key: key,
|
||||
// child: child);
|
||||
// }
|
||||
// const HomeAccountReadyShell._(
|
||||
// {required this.unlockedAccountInfo,
|
||||
// required this.routerCubit,
|
||||
// required this.child,
|
||||
// super.key});
|
||||
|
||||
// @override
|
||||
// HomeAccountReadyShellState createState() => HomeAccountReadyShellState();
|
||||
|
||||
// final Widget child;
|
||||
// final UnlockedAccountInfo unlockedAccountInfo;
|
||||
// final RouterCubit routerCubit;
|
||||
|
||||
// @override
|
||||
// void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
// super.debugFillProperties(properties);
|
||||
// properties
|
||||
// ..add(DiagnosticsProperty<UnlockedAccountInfo>(
|
||||
// 'unlockedAccountInfo', unlockedAccountInfo))
|
||||
// ..add(DiagnosticsProperty<RouterCubit>('routerCubit', routerCubit));
|
||||
// }
|
||||
// }
|
||||
|
||||
// class HomeAccountReadyShellState extends State<HomeAccountReadyShell> {
|
||||
// final SingleStateProcessor<WaitingInvitationsBlocMapState>
|
||||
// _singleInvitationStatusProcessor = SingleStateProcessor();
|
||||
|
||||
// @override
|
||||
// void initState() {
|
||||
// super.initState();
|
||||
// }
|
||||
// }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue