2023-08-03 00:49:48 -04:00
|
|
|
import 'dart:async';
|
2023-09-23 22:32:27 -04:00
|
|
|
import 'dart:math';
|
2023-08-03 00:49:48 -04:00
|
|
|
|
2023-08-02 21:09:28 -04:00
|
|
|
import 'package:awesome_extensions/awesome_extensions.dart';
|
2023-08-03 00:49:48 -04:00
|
|
|
import 'package:flutter/foundation.dart';
|
2023-08-02 21:09:28 -04:00
|
|
|
import 'package:flutter/material.dart';
|
2023-08-05 01:00:46 -04:00
|
|
|
import 'package:flutter/services.dart';
|
2024-01-29 22:38:19 -05:00
|
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
2023-08-02 21:09:28 -04:00
|
|
|
import 'package:flutter_translate/flutter_translate.dart';
|
2024-01-09 20:58:27 -05:00
|
|
|
import 'package:veilid_support/veilid_support.dart';
|
2023-08-02 21:09:28 -04:00
|
|
|
|
2024-01-09 20:58:27 -05:00
|
|
|
import '../../account_manager/account_manager.dart';
|
|
|
|
import '../../tools/tools.dart';
|
2024-01-30 14:14:11 -05:00
|
|
|
import '../contact_invitation.dart';
|
2023-08-02 21:09:28 -04:00
|
|
|
|
2024-01-09 20:58:27 -05:00
|
|
|
class SendInviteDialog extends StatefulWidget {
|
2024-02-14 21:33:15 -05:00
|
|
|
const SendInviteDialog({required this.modalContext, super.key});
|
2023-08-02 21:09:28 -04:00
|
|
|
|
|
|
|
@override
|
|
|
|
SendInviteDialogState createState() => SendInviteDialogState();
|
2023-09-23 12:56:54 -04:00
|
|
|
|
|
|
|
static Future<void> show(BuildContext context) async {
|
2023-09-23 22:19:53 -04:00
|
|
|
await showStyledDialog<void>(
|
2023-09-23 12:56:54 -04:00
|
|
|
context: context,
|
2023-09-23 22:19:53 -04:00
|
|
|
title: translate('send_invite_dialog.title'),
|
2024-02-14 21:33:15 -05:00
|
|
|
child: SendInviteDialog(modalContext: context));
|
|
|
|
}
|
|
|
|
|
|
|
|
final BuildContext modalContext;
|
|
|
|
|
|
|
|
@override
|
|
|
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
|
|
|
super.debugFillProperties(properties);
|
|
|
|
properties
|
|
|
|
.add(DiagnosticsProperty<BuildContext>('modalContext', modalContext));
|
2023-09-23 12:56:54 -04:00
|
|
|
}
|
2023-08-02 21:09:28 -04:00
|
|
|
}
|
|
|
|
|
2024-01-09 20:58:27 -05:00
|
|
|
class SendInviteDialogState extends State<SendInviteDialog> {
|
2023-08-03 00:49:48 -04:00
|
|
|
final _messageTextController = TextEditingController(
|
2023-08-02 21:09:28 -04:00
|
|
|
text: translate('send_invite_dialog.connect_with_me'));
|
|
|
|
|
|
|
|
EncryptionKeyType _encryptionKeyType = EncryptionKeyType.none;
|
|
|
|
String _encryptionKey = '';
|
2023-08-03 00:49:48 -04:00
|
|
|
Timestamp? _expiration;
|
2023-08-02 21:09:28 -04:00
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
super.initState();
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> _onNoneEncryptionSelected(bool selected) async {
|
|
|
|
setState(() {
|
|
|
|
if (selected) {
|
|
|
|
_encryptionKeyType = EncryptionKeyType.none;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> _onPinEncryptionSelected(bool selected) async {
|
|
|
|
final description = translate('send_invite_dialog.pin_description');
|
|
|
|
final pin = await showDialog<String>(
|
|
|
|
context: context,
|
2023-09-26 22:32:13 -04:00
|
|
|
builder: (context) =>
|
|
|
|
EnterPinDialog(reenter: false, description: description));
|
2023-08-02 21:09:28 -04:00
|
|
|
if (pin == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// ignore: use_build_context_synchronously
|
|
|
|
if (!context.mounted) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
final matchpin = await showDialog<String>(
|
|
|
|
context: context,
|
|
|
|
builder: (context) => EnterPinDialog(
|
2023-09-26 22:32:13 -04:00
|
|
|
reenter: true,
|
2023-08-02 21:09:28 -04:00
|
|
|
description: description,
|
|
|
|
));
|
|
|
|
if (matchpin == null) {
|
|
|
|
return;
|
|
|
|
} else if (pin == matchpin) {
|
|
|
|
setState(() {
|
|
|
|
_encryptionKeyType = EncryptionKeyType.pin;
|
|
|
|
_encryptionKey = pin;
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
// ignore: use_build_context_synchronously
|
|
|
|
if (!context.mounted) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
showErrorToast(
|
|
|
|
context, translate('send_invite_dialog.pin_does_not_match'));
|
|
|
|
setState(() {
|
|
|
|
_encryptionKeyType = EncryptionKeyType.none;
|
|
|
|
_encryptionKey = '';
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> _onPasswordEncryptionSelected(bool selected) async {
|
2023-09-26 22:32:13 -04:00
|
|
|
final description = translate('send_invite_dialog.password_description');
|
|
|
|
final password = await showDialog<String>(
|
|
|
|
context: context,
|
|
|
|
builder: (context) => EnterPasswordDialog(description: description));
|
|
|
|
if (password == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// ignore: use_build_context_synchronously
|
|
|
|
if (!context.mounted) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
final matchpass = await showDialog<String>(
|
|
|
|
context: context,
|
|
|
|
builder: (context) => EnterPasswordDialog(
|
|
|
|
matchPass: password,
|
|
|
|
description: description,
|
|
|
|
));
|
|
|
|
if (matchpass == null) {
|
|
|
|
return;
|
|
|
|
} else if (password == matchpass) {
|
|
|
|
setState(() {
|
2023-08-02 21:09:28 -04:00
|
|
|
_encryptionKeyType = EncryptionKeyType.password;
|
2023-09-26 22:32:13 -04:00
|
|
|
_encryptionKey = password;
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
// ignore: use_build_context_synchronously
|
|
|
|
if (!context.mounted) {
|
|
|
|
return;
|
2023-08-02 21:09:28 -04:00
|
|
|
}
|
2023-09-26 22:32:13 -04:00
|
|
|
showErrorToast(
|
|
|
|
context, translate('send_invite_dialog.password_does_not_match'));
|
|
|
|
setState(() {
|
|
|
|
_encryptionKeyType = EncryptionKeyType.none;
|
|
|
|
_encryptionKey = '';
|
|
|
|
});
|
|
|
|
}
|
2023-08-02 21:09:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> _onGenerateButtonPressed() async {
|
2023-08-03 00:49:48 -04:00
|
|
|
final navigator = Navigator.of(context);
|
|
|
|
|
|
|
|
// Start generation
|
2024-01-30 14:14:11 -05:00
|
|
|
final contactInvitationListCubit =
|
2024-02-14 21:33:15 -05:00
|
|
|
widget.modalContext.read<ContactInvitationListCubit>();
|
2024-01-29 22:38:19 -05:00
|
|
|
|
2024-01-30 14:14:11 -05:00
|
|
|
final generator = contactInvitationListCubit.createInvitation(
|
2023-08-03 00:49:48 -04:00
|
|
|
encryptionKeyType: _encryptionKeyType,
|
|
|
|
encryptionKey: _encryptionKey,
|
2023-08-04 01:00:38 -04:00
|
|
|
message: _messageTextController.text,
|
2023-08-03 00:49:48 -04:00
|
|
|
expiration: _expiration);
|
|
|
|
// ignore: use_build_context_synchronously
|
|
|
|
if (!context.mounted) {
|
|
|
|
return;
|
|
|
|
}
|
2023-08-02 21:09:28 -04:00
|
|
|
await showDialog<void>(
|
|
|
|
context: context,
|
2024-02-14 21:33:15 -05:00
|
|
|
builder: (context) => BlocProvider(
|
|
|
|
create: (context) => InvitationGeneratorCubit(generator),
|
|
|
|
child: ContactInvitationDisplayDialog(
|
2023-08-03 00:49:48 -04:00
|
|
|
message: _messageTextController.text,
|
2024-02-14 21:33:15 -05:00
|
|
|
)));
|
2023-08-02 21:09:28 -04:00
|
|
|
// if (ret == null) {
|
|
|
|
// return;
|
|
|
|
// }
|
2023-08-03 00:49:48 -04:00
|
|
|
navigator.pop();
|
2023-08-02 21:09:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
// ignore: prefer_expression_function_bodies
|
|
|
|
Widget build(BuildContext context) {
|
2023-09-23 22:19:53 -04:00
|
|
|
final windowSize = MediaQuery.of(context).size;
|
2023-09-23 22:32:27 -04:00
|
|
|
final maxDialogWidth = min(windowSize.width - 64.0, 800.0 - 64.0);
|
|
|
|
final maxDialogHeight = windowSize.height - 64.0;
|
2023-09-23 22:19:53 -04:00
|
|
|
|
2023-08-02 21:09:28 -04:00
|
|
|
final theme = Theme.of(context);
|
|
|
|
//final scale = theme.extension<ScaleScheme>()!;
|
|
|
|
final textTheme = theme.textTheme;
|
2023-09-23 22:19:53 -04:00
|
|
|
return ConstrainedBox(
|
|
|
|
constraints:
|
|
|
|
BoxConstraints(maxHeight: maxDialogHeight, maxWidth: maxDialogWidth),
|
2023-08-02 21:09:28 -04:00
|
|
|
child: SingleChildScrollView(
|
|
|
|
padding: const EdgeInsets.all(8),
|
|
|
|
child: Column(
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: <Widget>[
|
|
|
|
Text(
|
|
|
|
translate('send_invite_dialog.message_to_contact'),
|
|
|
|
).paddingAll(8),
|
|
|
|
TextField(
|
2023-08-03 00:49:48 -04:00
|
|
|
controller: _messageTextController,
|
2023-08-05 01:00:46 -04:00
|
|
|
inputFormatters: [
|
2023-08-09 02:33:31 -04:00
|
|
|
LengthLimitingTextInputFormatter(128),
|
2023-08-05 01:00:46 -04:00
|
|
|
],
|
2023-08-02 21:09:28 -04:00
|
|
|
decoration: InputDecoration(
|
|
|
|
border: const OutlineInputBorder(),
|
|
|
|
hintText: translate('send_invite_dialog.enter_message_hint'),
|
|
|
|
labelText: translate('send_invite_dialog.message')),
|
|
|
|
).paddingAll(8),
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
Text(translate('send_invite_dialog.protect_this_invitation'),
|
|
|
|
style: textTheme.labelLarge)
|
|
|
|
.paddingAll(8),
|
|
|
|
Wrap(spacing: 5, children: [
|
|
|
|
ChoiceChip(
|
|
|
|
label: Text(translate('send_invite_dialog.unlocked')),
|
|
|
|
selected: _encryptionKeyType == EncryptionKeyType.none,
|
|
|
|
onSelected: _onNoneEncryptionSelected,
|
|
|
|
),
|
|
|
|
ChoiceChip(
|
2023-09-23 12:56:54 -04:00
|
|
|
label: Text(translate('send_invite_dialog.pin')),
|
2023-08-02 21:09:28 -04:00
|
|
|
selected: _encryptionKeyType == EncryptionKeyType.pin,
|
|
|
|
onSelected: _onPinEncryptionSelected,
|
|
|
|
),
|
|
|
|
ChoiceChip(
|
|
|
|
label: Text(translate('send_invite_dialog.password')),
|
|
|
|
selected: _encryptionKeyType == EncryptionKeyType.password,
|
|
|
|
onSelected: _onPasswordEncryptionSelected,
|
|
|
|
)
|
|
|
|
]).paddingAll(8),
|
|
|
|
Container(
|
|
|
|
width: double.infinity,
|
|
|
|
height: 60,
|
|
|
|
padding: const EdgeInsets.all(8),
|
|
|
|
child: ElevatedButton(
|
|
|
|
onPressed: _onGenerateButtonPressed,
|
|
|
|
child: Text(
|
|
|
|
translate('send_invite_dialog.generate'),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
Text(translate('send_invite_dialog.note')).paddingAll(8),
|
|
|
|
Text(
|
|
|
|
translate('send_invite_dialog.note_text'),
|
|
|
|
style: Theme.of(context).textTheme.bodySmall,
|
|
|
|
).paddingAll(8),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
2023-08-03 00:49:48 -04:00
|
|
|
|
|
|
|
@override
|
|
|
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
|
|
|
super.debugFillProperties(properties);
|
|
|
|
properties.add(DiagnosticsProperty<TextEditingController>(
|
|
|
|
'messageTextController', _messageTextController));
|
|
|
|
}
|
2023-08-02 21:09:28 -04:00
|
|
|
}
|