veilidchat/lib/layout/home/home_screen.dart

247 lines
8.9 KiB
Dart
Raw Normal View History

2024-07-24 15:20:29 -04:00
import 'dart:async';
2024-06-11 21:27:20 -04:00
import 'dart:math';
2024-07-24 15:20:29 -04:00
import 'package:flutter/gestures.dart';
2024-02-11 23:18:20 -05:00
import 'package:flutter/material.dart';
2024-07-24 15:20:29 -04:00
import 'package:flutter_translate/flutter_translate.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-07-24 15:20:29 -04:00
import 'package:url_launcher/url_launcher_string.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-07-26 16:51:03 -04:00
import '../../settings/settings.dart';
2024-02-11 23:18:20 -05:00
import '../../theme/theme.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-07-09 13:27:54 -04:00
import '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-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;
2024-07-26 16:51:03 -04:00
final displayBetaWarning = context
.read<PreferencesCubit>()
.state
.asData
?.value
.notificationsPreference
.displayBetaWarning ??
true;
if (displayBetaWarning) {
await _doBetaDialog(context);
}
2024-07-24 15:20:29 -04:00
2024-07-03 20:59:54 -04:00
if (!canClose) {
await _zoomDrawerController.open!();
}
});
2024-02-11 23:18:20 -05:00
super.initState();
}
2024-07-24 15:20:29 -04:00
Future<void> _doBetaDialog(BuildContext context) async {
2024-07-26 16:51:03 -04:00
var displayBetaWarning = true;
2024-08-03 00:18:39 -04:00
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
2024-08-07 15:03:23 -04:00
final scaleConfig = theme.extension<ScaleConfig>()!;
2024-07-26 16:51:03 -04:00
2024-08-03 00:18:39 -04:00
await showWarningWidgetModal(
2024-07-26 16:51:03 -04:00
context: context,
title: translate('splash.beta_title'),
2024-08-03 00:18:39 -04:00
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
2024-07-26 16:51:03 -04:00
RichText(
2024-07-24 15:20:29 -04:00
textAlign: TextAlign.center,
text: TextSpan(
children: <TextSpan>[
TextSpan(
text: translate('splash.beta_text'),
2024-08-03 00:18:39 -04:00
style: theme.textTheme.bodyMedium!
.copyWith(color: scale.primaryScale.appText),
2024-07-24 15:20:29 -04:00
),
TextSpan(
2024-08-07 15:03:23 -04:00
text: 'https://veilid.com/chat/knownissues',
2024-08-03 00:18:39 -04:00
style: theme.textTheme.bodyMedium!.copyWith(
2024-08-07 15:03:23 -04:00
color: scaleConfig.useVisualIndicators
? scale.secondaryScale.primaryText
: scale.secondaryScale.primary,
2024-07-24 15:20:29 -04:00
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
2024-08-07 15:03:23 -04:00
..onTap = () =>
launchUrlString('https://veilid.com/chat/knownissues'),
2024-07-24 15:20:29 -04:00
),
],
),
),
2024-07-26 16:51:03 -04:00
Row(mainAxisSize: MainAxisSize.min, children: [
StatefulBuilder(
builder: (context, setState) => Checkbox.adaptive(
value: displayBetaWarning,
onChanged: (value) {
setState(() {
displayBetaWarning = value ?? true;
});
},
)),
2024-08-03 00:18:39 -04:00
Text(
translate('settings_page.display_beta_warning'),
style: theme.textTheme.bodyMedium!
.copyWith(color: scale.primaryScale.appText),
),
2024-07-26 16:51:03 -04:00
]),
]),
);
final preferencesInstance = PreferencesRepository.instance;
await preferencesInstance.set(preferencesInstance.value.copyWith(
notificationsPreference: preferencesInstance
.value.notificationsPreference
.copyWith(displayBetaWarning: displayBetaWarning)));
2024-07-24 15:20:29 -04:00
}
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-07-31 13:04:43 -04:00
child: Navigator(
onPopPage: (route, result) {
if (!route.didPop(result)) {
return false;
}
return true;
},
pages: const [MaterialPage(child: HomeAccountReady())]));
2024-06-19 11:35:51 -04:00
}
2024-06-15 23:29:15 -04:00
}
2024-07-06 20:09:18 -04:00
Widget _applyPageBorder(Widget child) {
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
return ValueListenableBuilder(
valueListenable: _zoomDrawerController.stateNotifier!,
child: child,
builder: (context, drawerState, staticChild) => clipBorder(
clipEnabled: drawerState != DrawerState.closed,
borderEnabled:
scaleConfig.preferBorders && scaleConfig.useVisualIndicators,
borderRadius: 16 * scaleConfig.borderRadiusScale,
borderColor: scale.primaryScale.border,
child: staticChild!));
}
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) {
2024-07-06 20:09:18 -04:00
return _applyPageBorder(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);
2024-07-06 20:09:18 -04:00
accountPages.add(_applyPageBorder(accountPage));
2024-06-24 19:44:08 -04:00
}
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);
2024-06-11 21:27:20 -04:00
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-07-06 20:09:18 -04:00
child: DefaultTextStyle(
style: theme.textTheme.bodySmall!,
2024-06-11 21:27:20 -04:00
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-07-06 20:09:18 -04:00
borderRadius: 0,
2024-06-11 21:27:20 -04:00
angle: 0,
2024-07-06 20:09:18 -04:00
mainScreenOverlayColor: theme.shadowColor.withAlpha(0x2F),
2024-06-11 21:27:20 -04:00
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-08-01 17:03:50 -04:00
mainScreenScale: .25,
2024-06-11 21:27:20 -04:00
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-02-11 23:18:20 -05:00
}