refactor and cleanup in prep for profile changing

This commit is contained in:
Christien Rioux 2024-06-13 14:52:34 -04:00
parent 87bb1657c7
commit 56d65442f4
49 changed files with 967 additions and 655 deletions

View file

@ -1,3 +1,4 @@
import 'package:async_tools/async_tools.dart';
import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -9,6 +10,7 @@ import 'package:veilid_support/veilid_support.dart';
import '../../../account_manager/account_manager.dart';
import '../../../theme/theme.dart';
import '../../../tools/tools.dart';
import '../../../veilid_processor/veilid_processor.dart';
import 'menu_item_widget.dart';
class DrawerMenu extends StatefulWidget {
@ -29,8 +31,10 @@ class _DrawerMenuState extends State<DrawerMenu> {
super.dispose();
}
void _doLoginClick(TypedKey superIdentityRecordKey) {
//
void _doSwitchClick(TypedKey superIdentityRecordKey) {
singleFuture(this, () async {
await AccountRepository.instance.switchToAccount(superIdentityRecordKey);
});
}
void _doEditClick(TypedKey superIdentityRecordKey) {
@ -47,10 +51,12 @@ class _DrawerMenuState extends State<DrawerMenu> {
Widget _makeAccountWidget(
{required String name,
required bool selected,
required ScaleColor scale,
required bool loggedIn,
required void Function() clickHandler}) {
required void Function()? callback,
required void Function()? footerCallback}) {
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!.tertiaryScale;
final abbrev = name.split(' ').map((s) => s.isEmpty ? '' : s[0]).join();
late final String shortname;
if (abbrev.length >= 3) {
@ -65,30 +71,36 @@ class _DrawerMenuState extends State<DrawerMenu> {
foregroundColor: loggedIn ? scale.primaryText : scale.subtleText,
child: Text(shortname, style: theme.textTheme.titleLarge));
return MenuItemWidget(
title: name,
headerWidget: avatar,
titleStyle: theme.textTheme.titleLarge!,
foregroundColor: scale.primary,
backgroundColor: scale.elementBackground,
backgroundHoverColor: scale.hoverElementBackground,
backgroundFocusColor: scale.activeElementBackground,
borderColor: scale.border,
borderHoverColor: scale.hoverBorder,
borderFocusColor: scale.primary,
footerButtonIcon: loggedIn ? Icons.edit_outlined : Icons.login_outlined,
footerCallback: clickHandler,
footerButtonIconColor: scale.border,
footerButtonIconHoverColor: scale.hoverElementBackground,
footerButtonIconFocusColor: scale.activeElementBackground,
);
return AnimatedPadding(
padding: EdgeInsets.fromLTRB(selected ? 0 : 0, 0, selected ? 0 : 8, 0),
duration: const Duration(milliseconds: 50),
child: MenuItemWidget(
title: name,
headerWidget: avatar,
titleStyle: theme.textTheme.titleLarge!,
foregroundColor: scale.primary,
backgroundColor: selected
? scale.activeElementBackground
: scale.elementBackground,
backgroundHoverColor: scale.hoverElementBackground,
backgroundFocusColor: scale.activeElementBackground,
borderColor: scale.border,
borderHoverColor: scale.hoverBorder,
borderFocusColor: scale.primary,
callback: callback,
footerButtonIcon: loggedIn ? Icons.edit_outlined : null,
footerCallback: footerCallback,
footerButtonIconColor: scale.border,
footerButtonIconHoverColor: scale.hoverElementBackground,
footerButtonIconFocusColor: scale.activeElementBackground,
));
}
Widget _getAccountList(
{required TypedKey? activeLocalAccount,
required AccountRecordsBlocMapState accountRecords}) {
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
final scaleScheme = theme.extension<ScaleScheme>()!;
final accountRepo = AccountRepository.instance;
final localAccounts = accountRepo.getLocalAccounts();
@ -104,28 +116,38 @@ class _DrawerMenuState extends State<DrawerMenu> {
final acctRecord = accountRecords.get(superIdentityRecordKey);
if (acctRecord != null) {
// Account is logged in
final scale = theme.extension<ScaleScheme>()!.tertiaryScale;
final loggedInAccount = acctRecord.when(
data: (value) => _makeAccountWidget(
name: value.profile.name,
scale: scale,
selected: superIdentityRecordKey == activeLocalAccount,
loggedIn: true,
clickHandler: () {
callback: () {
_doSwitchClick(superIdentityRecordKey);
},
footerCallback: () {
_doEditClick(superIdentityRecordKey);
}),
loading: () => _wrapInBox(
child: buildProgressIndicator(),
color: scale.grayScale.subtleBorder),
color: scaleScheme.grayScale.subtleBorder),
error: (err, st) => _wrapInBox(
child: errorPage(err, st), color: scale.errorScale.subtleBorder),
child: errorPage(err, st),
color: scaleScheme.errorScale.subtleBorder),
);
loggedInAccounts.add(loggedInAccount);
loggedInAccounts.add(loggedInAccount.paddingLTRB(0, 0, 0, 8));
} else {
// Account is not logged in
final scale = theme.extension<ScaleScheme>()!.grayScale;
final loggedOutAccount = _makeAccountWidget(
name: la.name,
loggedIn: false,
clickHandler: () {
_doLoginClick(superIdentityRecordKey);
});
name: la.name,
scale: scale,
selected: superIdentityRecordKey == activeLocalAccount,
loggedIn: false,
callback: () => {_doSwitchClick(superIdentityRecordKey)},
footerCallback: null,
);
loggedOutAccounts.add(loggedOutAccount);
}
}
@ -208,7 +230,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
final scale = theme.extension<ScaleScheme>()!;
//final textTheme = theme.textTheme;
final accountRecords = context.watch<AccountRecordsBlocMapCubit>().state;
final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state;
final activeLocalAccount = context.watch<ActiveAccountInfoCubit>().state;
final gradient = LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
@ -249,13 +271,21 @@ class _DrawerMenuState extends State<DrawerMenu> {
])),
const Spacer(),
_getAccountList(
activeLocalAccount: activeLocalAccount,
activeLocalAccount:
activeLocalAccount.unlockedAccountInfo?.superIdentityRecordKey,
accountRecords: accountRecords),
_getBottomButtons(),
const Spacer(),
Text('Version $packageInfoVersion',
style: theme.textTheme.labelMedium!
.copyWith(color: scale.tertiaryScale.hoverBorder))
Row(children: [
Text('Version $packageInfoVersion',
style: theme.textTheme.labelMedium!
.copyWith(color: scale.tertiaryScale.hoverBorder)),
const Spacer(),
SignalStrengthMeterWidget(
color: scale.tertiaryScale.hoverBorder,
inactiveColor: scale.tertiaryScale.border,
),
])
]).paddingAll(16),
);
}

View file

@ -27,7 +27,7 @@ class MenuItemWidget extends StatelessWidget {
@override
Widget build(BuildContext context) => TextButton(
onPressed: () => callback,
onPressed: callback,
style: TextButton.styleFrom(foregroundColor: foregroundColor).copyWith(
backgroundColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.hovered)) {

View file

@ -44,7 +44,7 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
WidgetStateProperty.all(scale.primaryScale.hoverBorder),
shape: WidgetStateProperty.all(const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(16))))),
tooltip: translate('app_bar.settings_tooltip'),
tooltip: translate('menu.settings_tooltip'),
onPressed: () async {
final ctrl = context.read<ZoomDrawerController>();
await ctrl.toggle?.call();

View file

@ -1,15 +1,14 @@
import 'package:async_tools/async_tools.dart';
import 'package:bloc_advanced_tools/bloc_advanced_tools.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.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 '../../../router/router.dart';
import '../../../theme/theme.dart';
@ -18,20 +17,17 @@ class HomeAccountReadyShell extends StatefulWidget {
{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 activeLocalAccount = context.read<ActiveLocalAccountCubit>().state!;
final activeAccountInfo = context.read<ActiveAccountInfo>();
final unlockedAccountInfo = context.watch<UnlockedAccountInfo>();
final routerCubit = context.read<RouterCubit>();
return HomeAccountReadyShell._(
activeLocalAccount: activeLocalAccount,
activeAccountInfo: activeAccountInfo,
unlockedAccountInfo: unlockedAccountInfo,
routerCubit: routerCubit,
key: key,
child: child);
}
const HomeAccountReadyShell._(
{required this.activeLocalAccount,
required this.activeAccountInfo,
{required this.unlockedAccountInfo,
required this.routerCubit,
required this.child,
super.key});
@ -40,18 +36,15 @@ class HomeAccountReadyShell extends StatefulWidget {
HomeAccountReadyShellState createState() => HomeAccountReadyShellState();
final Widget child;
final TypedKey activeLocalAccount;
final ActiveAccountInfo activeAccountInfo;
final UnlockedAccountInfo unlockedAccountInfo;
final RouterCubit routerCubit;
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(DiagnosticsProperty<TypedKey>(
'activeLocalAccount', activeLocalAccount))
..add(DiagnosticsProperty<ActiveAccountInfo>(
'activeAccountInfo', activeAccountInfo))
..add(DiagnosticsProperty<UnlockedAccountInfo>(
'unlockedAccountInfo', unlockedAccountInfo))
..add(DiagnosticsProperty<RouterCubit>('routerCubit', routerCubit));
}
}
@ -115,39 +108,41 @@ class HomeAccountReadyShellState extends State<HomeAccountReadyShell> {
}
return MultiBlocProvider(
providers: [
// Contact Cubits
BlocProvider(
create: (context) => ContactInvitationListCubit(
activeAccountInfo: widget.activeAccountInfo,
unlockedAccountInfo: widget.unlockedAccountInfo,
account: account)),
BlocProvider(
create: (context) => ContactListCubit(
activeAccountInfo: widget.activeAccountInfo,
unlockedAccountInfo: widget.unlockedAccountInfo,
account: account)),
BlocProvider(
create: (context) => ActiveChatCubit(null)
..withStateListen((event) {
widget.routerCubit.setHasActiveChat(event != null);
})),
BlocProvider(
create: (context) => ChatListCubit(
activeAccountInfo: widget.activeAccountInfo,
activeChatCubit: context.read<ActiveChatCubit>(),
account: account)),
BlocProvider(
create: (context) => ActiveConversationsBlocMapCubit(
activeAccountInfo: widget.activeAccountInfo,
contactListCubit: context.read<ContactListCubit>())
..follow(context.read<ChatListCubit>())),
BlocProvider(
create: (context) => ActiveSingleContactChatBlocMapCubit(
activeAccountInfo: widget.activeAccountInfo,
contactListCubit: context.read<ContactListCubit>(),
chatListCubit: context.read<ChatListCubit>())
..follow(context.read<ActiveConversationsBlocMapCubit>())),
BlocProvider(
create: (context) => WaitingInvitationsBlocMapCubit(
activeAccountInfo: widget.activeAccountInfo, account: account)
..follow(context.read<ContactInvitationListCubit>()))
unlockedAccountInfo: widget.unlockedAccountInfo,
account: account)
..follow(context.watch<ContactInvitationListCubit>())),
// Chat Cubits
BlocProvider(
create: (context) => ActiveChatCubit(null,
routerCubit: context.watch<RouterCubit>())),
BlocProvider(
create: (context) => ChatListCubit(
unlockedAccountInfo: widget.unlockedAccountInfo,
activeChatCubit: context.watch<ActiveChatCubit>(),
account: account)),
// Conversation Cubits
BlocProvider(
create: (context) => ActiveConversationsBlocMapCubit(
unlockedAccountInfo: widget.unlockedAccountInfo,
contactListCubit: context.watch<ContactListCubit>())
..follow(context.watch<ChatListCubit>())),
BlocProvider(
create: (context) => ActiveSingleContactChatBlocMapCubit(
unlockedAccountInfo: widget.unlockedAccountInfo,
contactListCubit: context.watch<ContactListCubit>(),
chatListCubit: context.watch<ChatListCubit>())
..follow(context.watch<ActiveConversationsBlocMapCubit>())),
],
child: MultiBlocListener(listeners: [
BlocListener<WaitingInvitationsBlocMapCubit,

View file

@ -1,8 +1,6 @@
import 'dart:math';
import 'package:awesome_extensions/awesome_extensions.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';
@ -35,17 +33,19 @@ class HomeShellState extends State<HomeShell> {
}
Widget buildWithLogin(BuildContext context) {
final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state;
final accountInfo = context.watch<ActiveAccountInfoCubit>().state;
final accountRecordsCubit = context.watch<AccountRecordsBlocMapCubit>();
if (activeLocalAccount == null) {
if (!accountInfo.active) {
// If no logged in user is active, show the loading panel
return const HomeNoActive();
}
final accountInfo =
AccountRepository.instance.getAccountInfo(activeLocalAccount);
final activeCubit =
accountRecordsCubit.tryOperate(activeLocalAccount, closure: (c) => c);
final superIdentityRecordKey =
accountInfo.unlockedAccountInfo?.superIdentityRecordKey;
final activeCubit = superIdentityRecordKey == null
? null
: accountRecordsCubit.tryOperate(superIdentityRecordKey,
closure: (c) => c);
if (activeCubit == null) {
return waitingPage();
}
@ -59,8 +59,8 @@ class HomeShellState extends State<HomeShell> {
return const HomeAccountLocked();
case AccountInfoStatus.accountReady:
return MultiProvider(providers: [
Provider<ActiveAccountInfo>.value(
value: accountInfo.activeAccountInfo!,
Provider<UnlockedAccountInfo>.value(
value: accountInfo.unlockedAccountInfo!,
),
Provider<AccountRecordCubit>.value(value: activeCubit),
Provider<ZoomDrawerController>.value(value: _zoomDrawerController),
@ -101,6 +101,7 @@ class HomeShellState extends State<HomeShell> {
// duration: const Duration(milliseconds: 250),
// reverseDuration: const Duration(milliseconds: 250),
menuScreenTapClose: true,
mainScreenTapClose: true,
mainScreenScale: .25,
slideWidth: min(360, MediaQuery.of(context).size.width * 0.9),
)));