import 'package:async_tools/async_tools.dart'; import 'package:awesome_extensions/awesome_extensions.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_translate/flutter_translate.dart'; import 'package:provider/provider.dart'; import '../../chat/chat.dart'; import '../../chat_list/chat_list.dart'; import '../../layout/layout.dart'; import '../../proto/proto.dart' as proto; import '../../theme/theme.dart'; import '../contacts.dart'; const _kDoBackArrow = 'doBackArrow'; class ContactsDialog extends StatefulWidget { const ContactsDialog._({required this.modalContext}); @override State createState() => _ContactsDialogState(); static Future show(BuildContext modalContext) async { await showDialog( context: modalContext, barrierDismissible: false, useRootNavigator: false, builder: (context) => ContactsDialog._(modalContext: modalContext)); } final BuildContext modalContext; @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties .add(DiagnosticsProperty('modalContext', modalContext)); } } class _ContactsDialogState extends State { @override void initState() { super.initState(); } @override Widget build(BuildContext context) { final theme = Theme.of(context); final scale = theme.extension()!; final appBarIconColor = scale.primaryScale.borderText; final enableSplit = !isMobileWidth(context); final enableLeft = enableSplit || _selectedContact == null; final enableRight = enableSplit || _selectedContact != null; return SizedBox( width: MediaQuery.of(context).size.width, child: StyledScaffold( appBar: DefaultAppBar( title: Text(!enableSplit && enableRight ? translate('contacts_dialog.edit_contact') : translate('contacts_dialog.contacts')), leading: IconButton( icon: const Icon(Icons.arrow_back), onPressed: () { singleFuture((this, _kDoBackArrow), () async { final confirmed = await _onContactSelected(null); if (!enableSplit && enableRight) { } else { if (confirmed) { if (context.mounted) { Navigator.pop(context); } } } }); }, ), actions: [ if (_selectedContact != null) FittedBox( fit: BoxFit.scaleDown, child: Column(mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: const Icon(Icons.chat_bubble), color: appBarIconColor, tooltip: translate('contacts_dialog.new_chat'), onPressed: () async { await _onChatStarted(_selectedContact!); }), Text(translate('contacts_dialog.new_chat'), style: theme.textTheme.labelSmall! .copyWith(color: appBarIconColor)), ])).paddingLTRB(8, 0, 8, 0), if (enableSplit && _selectedContact != null) FittedBox( fit: BoxFit.scaleDown, child: Column(mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: const Icon(Icons.close), color: appBarIconColor, tooltip: translate('contacts_dialog.close_contact'), onPressed: () async { await _onContactSelected(null); }), Text(translate('contacts_dialog.close_contact'), style: theme.textTheme.labelSmall! .copyWith(color: appBarIconColor)), ])).paddingLTRB(8, 0, 8, 0), ]), body: LayoutBuilder(builder: (context, constraint) { final maxWidth = constraint.maxWidth; return ColoredBox( color: scale.primaryScale.appBackground, child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Offstage( offstage: !enableLeft, child: SizedBox( width: enableLeft && !enableRight ? maxWidth : (maxWidth / 3).clamp(200, 500), child: DecoratedBox( decoration: BoxDecoration( color: scale .primaryScale.subtleBackground), child: ContactsBrowser( selectedContactRecordKey: _selectedContact ?.localConversationRecordKey .toVeilid(), onContactSelected: _onContactSelected, onStartChat: _onChatStarted, ).paddingLTRB(8, 0, 8, 8)))), if (enableRight && enableLeft) Container( constraints: const BoxConstraints( minWidth: 1, maxWidth: 1), color: scale.primaryScale.subtleBorder), if (enableRight) if (_selectedContact == null) const NoContactWidget().expanded() else ContactDetailsWidget( contact: _selectedContact!, onModifiedState: _onModifiedState) .paddingLTRB(16, 16, 16, 16) .expanded(), ])); }))); } void _onModifiedState(bool isModified) { setState(() { _isModified = isModified; }); } Future _onContactSelected(proto.Contact? contact) async { if (contact != _selectedContact && _isModified) { final ok = await showConfirmModal( context: context, title: translate('confirmation.discard_changes'), text: translate('confirmation.are_you_sure_discard')); if (!ok) { return false; } } setState(() { _selectedContact = contact; _isModified = false; }); return true; } Future _onChatStarted(proto.Contact contact) async { final chatListCubit = context.read(); await chatListCubit.getOrCreateChatSingleContact(contact: contact); if (mounted) { context .read() .setActiveChat(contact.localConversationRecordKey.toVeilid()); Navigator.pop(context); } } proto.Contact? _selectedContact; bool _isModified = false; }