veilidchat/lib/layout/home/home_screen.dart

213 lines
7.4 KiB
Dart
Raw Normal View History

2024-06-11 21:27:20 -04:00
import 'dart:math';
2024-02-11 23:18:20 -05:00
import 'package:flutter/material.dart';
2024-06-24 19:44:08 -04:00
import 'package:flutter_bloc/flutter_bloc.dart';
2024-06-11 21:27:20 -04:00
import 'package:flutter_zoom_drawer/flutter_zoom_drawer.dart';
2024-02-13 22:03:26 -05:00
import 'package:provider/provider.dart';
2024-06-24 19:44:08 -04:00
import 'package:transitioned_indexed_stack/transitioned_indexed_stack.dart';
2024-06-15 23:29:15 -04:00
import 'package:veilid_support/veilid_support.dart';
2024-02-11 23:18:20 -05:00
2024-02-13 22:03:26 -05:00
import '../../account_manager/account_manager.dart';
2024-06-15 23:29:15 -04:00
import '../../chat/chat.dart';
2024-02-11 23:18:20 -05:00
import '../../theme/theme.dart';
2024-06-16 22:12:24 -04:00
import '../../tools/tools.dart';
2024-06-11 21:27:20 -04:00
import 'drawer_menu/drawer_menu.dart';
2024-02-13 22:03:26 -05:00
import 'home_account_invalid.dart';
import 'home_account_locked.dart';
import 'home_account_missing.dart';
2024-06-16 22:12:24 -04:00
import 'home_account_ready/home_account_ready.dart';
2024-02-13 22:03:26 -05:00
import 'home_no_active.dart';
2024-02-11 23:18:20 -05:00
2024-06-16 22:12:24 -04:00
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
2024-02-11 23:18:20 -05:00
@override
2024-06-16 22:12:24 -04:00
HomeScreenState createState() => HomeScreenState();
2024-06-24 19:44:08 -04:00
static HomeScreenState? of(BuildContext context) =>
context.findAncestorStateOfType<HomeScreenState>();
2024-02-11 23:18:20 -05:00
}
2024-06-24 19:44:08 -04:00
class HomeScreenState extends State<HomeScreen>
with SingleTickerProviderStateMixin {
2024-02-11 23:18:20 -05:00
@override
void initState() {
2024-06-24 19:44:08 -04:00
// Chat animation setup (open in phone mode)
_chatAnimationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 250),
);
_chatAnimation = Tween<Offset>(
begin: const Offset(1, 0),
end: Offset.zero,
).animate(CurvedAnimation(
parent: _chatAnimationController,
curve: Curves.easeInOut,
));
2024-07-03 20:59:54 -04:00
WidgetsBinding.instance.addPostFrameCallback((_) async {
final localAccounts = context.read<LocalAccountsCubit>().state;
final activeLocalAccount = context.read<ActiveLocalAccountCubit>().state;
final activeIndex = localAccounts
.indexWhere((x) => x.superIdentity.recordKey == activeLocalAccount);
final canClose = activeIndex != -1;
await changeWindowSetup(
TitleBarStyle.normal, OrientationCapability.normal);
if (!canClose) {
await _zoomDrawerController.open!();
}
});
2024-02-11 23:18:20 -05:00
super.initState();
}
@override
void dispose() {
2024-06-24 19:44:08 -04:00
_chatAnimationController.dispose();
2024-02-11 23:18:20 -05:00
super.dispose();
}
2024-06-16 22:12:24 -04:00
Widget _buildAccountReadyDeviceSpecific(BuildContext context) {
if (responsiveVisibility(
context: context,
tablet: false,
tabletLandscape: false,
desktop: false)) {
2024-06-24 19:44:08 -04:00
return BlocConsumer<ActiveChatCubit, TypedKey?>(
listener: (context, activeChat) {
final hasActiveChat = activeChat != null;
if (hasActiveChat) {
_chatAnimationController.forward();
} else {
_chatAnimationController.reset();
}
},
builder: (context, activeChat) => Stack(
children: <Widget>[
const HomeAccountReadyMain(),
Offstage(
offstage: activeChat == null,
child: SlideTransition(
position: _chatAnimation,
child: const HomeAccountReadyChat())),
],
));
2024-06-16 22:12:24 -04:00
}
return const HomeAccountReadyMain();
}
2024-06-24 19:44:08 -04:00
Widget _buildAccountPage(
BuildContext context,
TypedKey superIdentityRecordKey,
2024-06-19 11:35:51 -04:00
PerAccountCollectionState perAccountCollectionState) {
switch (perAccountCollectionState.accountInfo.status) {
case AccountInfoStatus.accountInvalid:
return const HomeAccountInvalid();
case AccountInfoStatus.accountLocked:
return const HomeAccountLocked();
case AccountInfoStatus.accountUnlocked:
// Are we ready to render?
if (!perAccountCollectionState.isReady) {
return waitingPage();
}
2024-02-13 22:03:26 -05:00
2024-06-19 11:35:51 -04:00
// Re-export all ready blocs to the account display subtree
return perAccountCollectionState.provide(
2024-06-20 19:04:39 -04:00
child: Builder(builder: _buildAccountReadyDeviceSpecific));
2024-06-19 11:35:51 -04:00
}
2024-06-15 23:29:15 -04:00
}
2024-06-16 22:12:24 -04:00
Widget _buildAccountPageView(BuildContext context) {
final localAccounts = context.watch<LocalAccountsCubit>().state;
2024-06-20 19:04:39 -04:00
final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state;
2024-06-19 11:35:51 -04:00
final perAccountCollectionBlocMapState =
context.watch<PerAccountCollectionBlocMapCubit>().state;
2024-06-16 22:12:24 -04:00
2024-06-20 19:04:39 -04:00
final activeIndex = localAccounts
.indexWhere((x) => x.superIdentity.recordKey == activeLocalAccount);
2024-06-16 22:12:24 -04:00
if (activeIndex == -1) {
return const HomeNoActive();
2024-02-13 22:03:26 -05:00
}
2024-06-16 22:12:24 -04:00
2024-06-24 19:44:08 -04:00
final accountPages = <Widget>[];
for (var i = 0; i < localAccounts.length; i++) {
final superIdentityRecordKey = localAccounts[i].superIdentity.recordKey;
final perAccountCollectionState =
perAccountCollectionBlocMapState.get(superIdentityRecordKey);
if (perAccountCollectionState == null) {
return HomeAccountMissing(key: ValueKey(superIdentityRecordKey));
}
final accountPage = _buildAccountPage(
context, superIdentityRecordKey, perAccountCollectionState);
accountPages.add(KeyedSubtree.wrap(accountPage, i));
}
return SlideIndexedStack(
index: activeIndex,
beginSlideOffset: const Offset(1, 0),
children: accountPages,
);
2024-02-13 22:03:26 -05:00
}
2024-02-11 23:18:20 -05:00
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
2024-06-11 21:27:20 -04:00
final gradient = LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
scale.tertiaryScale.subtleBackground,
scale.tertiaryScale.appBackground,
]);
2024-07-03 20:59:54 -04:00
final localAccounts = context.watch<LocalAccountsCubit>().state;
final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state;
final activeIndex = localAccounts
.indexWhere((x) => x.superIdentity.recordKey == activeLocalAccount);
final canClose = activeIndex != -1;
2024-02-11 23:18:20 -05:00
return SafeArea(
2024-04-10 16:13:08 -04:00
child: DecoratedBox(
2024-06-11 21:27:20 -04:00
decoration: BoxDecoration(gradient: gradient),
child: ZoomDrawer(
controller: _zoomDrawerController,
//menuBackgroundColor: Colors.transparent,
2024-06-24 19:44:08 -04:00
menuScreen: Builder(builder: (context) {
final zoomDrawer = ZoomDrawer.of(context);
zoomDrawer!.stateNotifier.addListener(() {
if (zoomDrawer.isOpen()) {
FocusManager.instance.primaryFocus?.unfocus();
}
});
return const DrawerMenu();
}),
mainScreen: Provider<ZoomDrawerController>.value(
value: _zoomDrawerController,
child: Builder(builder: _buildAccountPageView)),
2024-06-11 21:27:20 -04:00
borderRadius: 24,
2024-06-24 19:44:08 -04:00
//showShadow: false,
2024-06-11 21:27:20 -04:00
angle: 0,
drawerShadowsBackgroundColor: theme.shadowColor,
mainScreenOverlayColor: theme.shadowColor.withAlpha(0x3F),
openCurve: Curves.fastEaseInToSlowEaseOut,
// duration: const Duration(milliseconds: 250),
// reverseDuration: const Duration(milliseconds: 250),
2024-07-03 20:59:54 -04:00
menuScreenTapClose: canClose,
mainScreenTapClose: canClose,
disableDragGesture: !canClose,
2024-06-11 21:27:20 -04:00
mainScreenScale: .25,
slideWidth: min(360, MediaQuery.of(context).size.width * 0.9),
)));
2024-02-11 23:18:20 -05:00
}
2024-06-11 21:27:20 -04:00
2024-06-24 19:44:08 -04:00
////////////////////////////////////////////////////////////////////////////
2024-06-15 23:29:15 -04:00
final _zoomDrawerController = ZoomDrawerController();
2024-06-24 19:44:08 -04:00
late final Animation<Offset> _chatAnimation;
late final AnimationController _chatAnimationController;
2024-02-11 23:18:20 -05:00
}