veilidchat/lib/pages/home.dart

268 lines
8.7 KiB
Dart
Raw Normal View History

2023-09-23 12:56:54 -04:00
import 'package:awesome_extensions/awesome_extensions.dart';
2023-08-07 00:55:57 -04:00
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
2023-01-08 22:27:33 -05:00
import 'package:flutter/material.dart';
2023-09-23 12:56:54 -04:00
import 'package:flutter_animate/flutter_animate.dart';
2023-01-09 22:50:34 -05:00
import 'package:flutter_riverpod/flutter_riverpod.dart';
2023-09-23 12:56:54 -04:00
import 'package:flutter_translate/flutter_translate.dart';
import 'package:go_router/go_router.dart';
2023-01-08 22:27:33 -05:00
2023-09-26 18:46:02 -04:00
import '../proto/proto.dart' as proto;
2023-07-29 10:55:35 -04:00
import '../components/chat_component.dart';
2023-08-07 00:55:57 -04:00
import '../components/empty_chat_widget.dart';
2023-09-23 12:56:54 -04:00
import '../components/profile_widget.dart';
import '../entities/local_account.dart';
2023-08-05 19:34:00 -04:00
import '../providers/account.dart';
2023-08-07 00:55:57 -04:00
import '../providers/chat.dart';
2023-08-05 19:34:00 -04:00
import '../providers/contact.dart';
2023-09-23 12:56:54 -04:00
import '../providers/local_accounts.dart';
import '../providers/logins.dart';
2023-07-28 20:36:05 -04:00
import '../providers/window_control.dart';
2023-07-26 22:38:09 -04:00
import '../tools/tools.dart';
2023-09-23 12:56:54 -04:00
import '../veilid_support/veilid_support.dart';
2023-07-28 20:36:05 -04:00
import 'main_pager/main_pager.dart';
2023-07-26 22:38:09 -04:00
class HomePage extends ConsumerStatefulWidget {
2023-01-09 22:50:34 -05:00
const HomePage({super.key});
2023-01-08 22:27:33 -05:00
@override
2023-07-26 22:38:09 -04:00
HomePageState createState() => HomePageState();
2023-08-08 02:03:26 -04:00
static Widget buildChatComponent(BuildContext context, WidgetRef ref) {
final contactList = ref.watch(fetchContactListProvider).asData?.value ??
const IListConst([]);
final activeChat = ref.watch(activeChatStateProvider).asData?.value;
if (activeChat == null) {
return const EmptyChatWidget();
}
final activeAccountInfo =
ref.watch(fetchActiveAccountProvider).asData?.value;
if (activeAccountInfo == null) {
return const EmptyChatWidget();
}
final activeChatContactIdx = contactList.indexWhere(
(c) =>
proto.TypedKeyProto.fromProto(c.remoteConversationRecordKey) ==
activeChat,
);
if (activeChatContactIdx == -1) {
activeChatState.add(null);
return const EmptyChatWidget();
}
final activeChatContact = contactList[activeChatContactIdx];
return ChatComponent(
activeAccountInfo: activeAccountInfo,
activeChat: activeChat,
activeChatContact: activeChatContact);
}
}
2023-08-05 19:34:00 -04:00
2023-07-26 22:38:09 -04:00
class HomePageState extends ConsumerState<HomePage>
with TickerProviderStateMixin {
final _unfocusNode = FocusNode();
2023-07-28 20:36:05 -04:00
2023-07-26 22:38:09 -04:00
@override
void initState() {
super.initState();
2023-07-28 20:36:05 -04:00
WidgetsBinding.instance.addPostFrameCallback((_) async {
setState(() {});
await ref.read(windowControlProvider.notifier).changeWindowSetup(
TitleBarStyle.normal, OrientationCapability.normal);
});
2023-07-26 22:38:09 -04:00
}
@override
void dispose() {
_unfocusNode.dispose();
super.dispose();
}
2023-09-23 12:56:54 -04:00
// ignore: prefer_expression_function_bodies
Widget buildAccountList() {
2023-09-26 18:46:02 -04:00
return const Column(children: [
2023-09-23 12:56:54 -04:00
Center(child: Text("Small Profile")),
Center(child: Text("Contact invitations")),
Center(child: Text("Contacts"))
]);
}
Widget buildUnlockAccount(
BuildContext context,
IList<LocalAccount> localAccounts,
// ignore: prefer_expression_function_bodies
) {
2023-09-26 18:46:02 -04:00
return const Center(child: Text("unlock account"));
2023-09-23 12:56:54 -04:00
}
/// We have an active, unlocked, user login
Widget buildReadyAccount(
BuildContext context,
IList<LocalAccount> localAccounts,
TypedKey activeUserLogin,
proto.Account account) {
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
return Column(children: <Widget>[
Row(children: [
IconButton(
icon: const Icon(Icons.settings),
color: scale.secondaryScale.text,
constraints: const BoxConstraints.expand(height: 64, width: 64),
style: ButtonStyle(
2023-09-24 15:30:54 -04:00
backgroundColor:
MaterialStateProperty.all(scale.secondaryScale.border),
2023-09-23 12:56:54 -04:00
shape: MaterialStateProperty.all(const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(16))))),
tooltip: translate('app_bar.settings_tooltip'),
onPressed: () async {
context.go('/home/settings');
}).paddingLTRB(0, 0, 8, 0),
ProfileWidget(name: account.profile.name, title: account.profile.title)
.expanded(),
]).paddingAll(8),
MainPager(
localAccounts: localAccounts,
activeUserLogin: activeUserLogin,
account: account)
.expanded()
]);
}
Widget buildUserPanel() {
final localAccountsV = ref.watch(localAccountsProvider);
final loginsV = ref.watch(loginsProvider);
if (!localAccountsV.hasValue || !loginsV.hasValue) {
return waitingPage(context);
}
final localAccounts = localAccountsV.requireValue;
final logins = loginsV.requireValue;
final activeUserLogin = logins.activeUserLogin;
if (activeUserLogin == null) {
// If no logged in user is active, show the list of account
return buildAccountList();
}
final accountV = ref
.watch(fetchAccountProvider(accountMasterRecordKey: activeUserLogin));
if (!accountV.hasValue) {
return waitingPage(context);
}
final account = accountV.requireValue;
switch (account.status) {
case AccountInfoStatus.noAccount:
Future.delayed(0.ms, () async {
await showErrorModal(context, translate('home.missing_account_title'),
translate('home.missing_account_text'));
// Delete account
await ref
.read(localAccountsProvider.notifier)
.deleteLocalAccount(activeUserLogin);
// Switch to no active user login
await ref.read(loginsProvider.notifier).switchToAccount(null);
});
return waitingPage(context);
case AccountInfoStatus.accountInvalid:
Future.delayed(0.ms, () async {
await showErrorModal(context, translate('home.invalid_account_title'),
translate('home.invalid_account_text'));
// Delete account
await ref
.read(localAccountsProvider.notifier)
.deleteLocalAccount(activeUserLogin);
// Switch to no active user login
await ref.read(loginsProvider.notifier).switchToAccount(null);
});
return waitingPage(context);
case AccountInfoStatus.accountLocked:
// Show unlock widget
return buildUnlockAccount(context, localAccounts);
case AccountInfoStatus.accountReady:
return buildReadyAccount(
context,
localAccounts,
activeUserLogin,
account.account!,
);
}
}
2023-07-28 20:36:05 -04:00
// ignore: prefer_expression_function_bodies
Widget buildPhone(BuildContext context) {
2023-09-23 12:56:54 -04:00
return Material(color: Colors.transparent, child: buildUserPanel());
2023-07-28 20:36:05 -04:00
}
// ignore: prefer_expression_function_bodies
Widget buildTabletLeftPane(BuildContext context) {
//
2023-09-23 12:56:54 -04:00
return Material(color: Colors.transparent, child: buildUserPanel());
2023-07-28 20:36:05 -04:00
}
// ignore: prefer_expression_function_bodies
Widget buildTabletRightPane(BuildContext context) {
//
2023-08-08 02:03:26 -04:00
return HomePage.buildChatComponent(context, ref);
2023-07-28 20:36:05 -04:00
}
// ignore: prefer_expression_function_bodies
Widget buildTablet(BuildContext context) {
2023-07-29 10:55:35 -04:00
final w = MediaQuery.of(context).size.width;
2023-09-24 15:30:54 -04:00
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
2023-07-28 20:36:05 -04:00
final children = [
2023-07-29 10:55:35 -04:00
ConstrainedBox(
2023-09-21 21:00:58 -04:00
constraints: const BoxConstraints(minWidth: 300, maxWidth: 300),
2023-07-29 10:55:35 -04:00
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: w / 2),
child: buildTabletLeftPane(context))),
2023-09-24 15:30:54 -04:00
SizedBox(
width: 2,
height: double.infinity,
child: ColoredBox(color: scale.primaryScale.hoverBorder)),
2023-07-29 10:55:35 -04:00
Expanded(child: buildTabletRightPane(context)),
2023-07-28 20:36:05 -04:00
];
2023-07-29 10:55:35 -04:00
return Row(
children: children,
);
2023-07-28 20:36:05 -04:00
2023-07-29 10:55:35 -04:00
// final theme = MultiSplitViewTheme(
// data: isDesktop
// ? MultiSplitViewThemeData(
// dividerThickness: 1,
// dividerPainter: DividerPainters.grooved2(thickness: 1))
// : MultiSplitViewThemeData(
// dividerThickness: 3,
// dividerPainter: DividerPainters.grooved2(thickness: 1)),
// child: multiSplitView);
2023-07-28 20:36:05 -04:00
}
2023-07-26 22:38:09 -04:00
@override
2023-07-28 20:36:05 -04:00
Widget build(BuildContext context) {
ref.watch(windowControlProvider);
2023-09-23 12:56:54 -04:00
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
2023-07-28 20:36:05 -04:00
return SafeArea(
2023-07-26 22:38:09 -04:00
child: GestureDetector(
2023-09-23 12:56:54 -04:00
onTap: () => FocusScope.of(context).requestFocus(_unfocusNode),
child: DecoratedBox(
2023-09-24 15:30:54 -04:00
decoration: BoxDecoration(
color: scale.primaryScale.activeElementBackground),
2023-09-23 12:56:54 -04:00
child: responsiveVisibility(
context: context,
phone: false,
)
? buildTablet(context)
: buildPhone(context),
)));
2023-07-28 20:36:05 -04:00
}
2023-01-08 22:27:33 -05:00
}