mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2024-09-07 23:31:53 +00:00
layout fixes
This commit is contained in:
parent
71f4d37efa
commit
216aef8173
@ -59,7 +59,7 @@
|
||||
"instructions_details": "This key is the ONLY way to recover your VeilidChat account in the event of a forgotton password or a lost, stolen, or compromised device.",
|
||||
"instructions_options": "Here are some options for your recovery key:",
|
||||
"instructions_print": "Print the recovery key and keep it somewhere safe",
|
||||
"instructions_view": "View the recovery key and write it down on paper",
|
||||
"instructions_view": "View the recovery key and take a screenshot",
|
||||
"instructions_share": "Share the recovery key to another app to save it",
|
||||
"print": "Print",
|
||||
"view": "View",
|
||||
|
22
assets/js/pdf/3.2.146/pdf.min.js
vendored
Normal file
22
assets/js/pdf/3.2.146/pdf.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -1,6 +1,8 @@
|
||||
PODS:
|
||||
- camera_avfoundation (0.0.1):
|
||||
- Flutter
|
||||
- file_saver (0.0.1):
|
||||
- Flutter
|
||||
- Flutter (1.0.0)
|
||||
- flutter_native_splash (0.0.1):
|
||||
- Flutter
|
||||
@ -63,6 +65,8 @@ PODS:
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- printing (1.0.0):
|
||||
- Flutter
|
||||
- PromisesObjC (2.4.0)
|
||||
- share_plus (0.0.1):
|
||||
- Flutter
|
||||
@ -83,12 +87,14 @@ PODS:
|
||||
|
||||
DEPENDENCIES:
|
||||
- camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`)
|
||||
- file_saver (from `.symlinks/plugins/file_saver/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
||||
- mobile_scanner (from `.symlinks/plugins/mobile_scanner/ios`)
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- pasteboard (from `.symlinks/plugins/pasteboard/ios`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- printing (from `.symlinks/plugins/printing/ios`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- smart_auth (from `.symlinks/plugins/smart_auth/ios`)
|
||||
@ -115,6 +121,8 @@ SPEC REPOS:
|
||||
EXTERNAL SOURCES:
|
||||
camera_avfoundation:
|
||||
:path: ".symlinks/plugins/camera_avfoundation/ios"
|
||||
file_saver:
|
||||
:path: ".symlinks/plugins/file_saver/ios"
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
flutter_native_splash:
|
||||
@ -127,6 +135,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/pasteboard/ios"
|
||||
path_provider_foundation:
|
||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||
printing:
|
||||
:path: ".symlinks/plugins/printing/ios"
|
||||
share_plus:
|
||||
:path: ".symlinks/plugins/share_plus/ios"
|
||||
shared_preferences_foundation:
|
||||
@ -144,6 +154,7 @@ EXTERNAL SOURCES:
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
camera_avfoundation: 759172d1a77ae7be0de08fc104cfb79738b8a59e
|
||||
file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778
|
||||
GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a
|
||||
@ -161,6 +172,7 @@ SPEC CHECKSUMS:
|
||||
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
|
||||
pasteboard: 982969ebaa7c78af3e6cc7761e8f5e77565d9ce0
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
printing: 233e1b73bd1f4a05615548e9b5a324c98588640b
|
||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||
share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad
|
||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||
|
@ -132,7 +132,8 @@ class AccountRepository {
|
||||
/// Creates a new super identity, an identity instance, an account associated
|
||||
/// with the identity instance, stores the account in the identity key and
|
||||
/// then logs into that account with no password set at this time
|
||||
Future<SecretKey> createWithNewSuperIdentity(proto.Profile newProfile) async {
|
||||
Future<WritableSuperIdentity> createWithNewSuperIdentity(
|
||||
proto.Profile newProfile) async {
|
||||
log.debug('Creating super identity');
|
||||
final wsi = await WritableSuperIdentity.create();
|
||||
try {
|
||||
@ -146,7 +147,7 @@ class AccountRepository {
|
||||
localAccount.superIdentity.recordKey, EncryptionKeyType.none, '');
|
||||
assert(ok, 'login with none should never fail');
|
||||
|
||||
return wsi.superSecret;
|
||||
return wsi;
|
||||
} on Exception catch (_) {
|
||||
await wsi.delete();
|
||||
rethrow;
|
||||
|
@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -55,6 +57,13 @@ class _EditAccountPageState extends State<EditAccountPage> {
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
unawaited(
|
||||
changeWindowSetup(TitleBarStyle.normal, OrientationCapability.normal));
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Widget _editAccountForm(BuildContext context,
|
||||
{required Future<void> Function(GlobalKey<FormBuilderState>)
|
||||
onSubmit}) =>
|
||||
@ -282,30 +291,27 @@ class _EditAccountPageState extends State<EditAccountPage> {
|
||||
await GoRouterHelper(context).push('/settings');
|
||||
})
|
||||
]),
|
||||
body: Column(children: [
|
||||
body: SingleChildScrollView(
|
||||
child: Column(children: [
|
||||
_editAccountForm(
|
||||
context,
|
||||
onSubmit: _onSubmit,
|
||||
).expanded(),
|
||||
Text(translate('edit_account_page.remove_account_description')),
|
||||
ElevatedButton(
|
||||
onPressed: _onRemoveAccount,
|
||||
child: Row(mainAxisSize: MainAxisSize.min, children: [
|
||||
const Icon(Icons.person_remove_alt_1, size: 16)
|
||||
.paddingLTRB(0, 0, 4, 0),
|
||||
Text(translate('edit_account_page.remove_account'))
|
||||
.paddingLTRB(0, 0, 4, 0)
|
||||
])).paddingLTRB(0, 8, 0, 24),
|
||||
Text(translate('edit_account_page.destroy_account_description')),
|
||||
ElevatedButton(
|
||||
onPressed: _onDestroyAccount,
|
||||
child: Row(mainAxisSize: MainAxisSize.min, children: [
|
||||
const Icon(Icons.person_off, size: 16)
|
||||
.paddingLTRB(0, 0, 4, 0),
|
||||
Text(translate('edit_account_page.destroy_account'))
|
||||
.paddingLTRB(0, 0, 4, 0)
|
||||
])).paddingLTRB(0, 8, 0, 24)
|
||||
]).paddingSymmetric(horizontal: 24, vertical: 8))
|
||||
).paddingLTRB(0, 0, 0, 32),
|
||||
OptionBox(
|
||||
instructions:
|
||||
translate('edit_account_page.remove_account_description'),
|
||||
buttonIcon: Icons.person_remove_alt_1,
|
||||
buttonText: translate('edit_account_page.remove_account'),
|
||||
onClick: _onRemoveAccount,
|
||||
),
|
||||
OptionBox(
|
||||
instructions:
|
||||
translate('edit_account_page.destroy_account_description'),
|
||||
buttonIcon: Icons.person_off,
|
||||
buttonText: translate('edit_account_page.destroy_account'),
|
||||
onClick: _onDestroyAccount,
|
||||
)
|
||||
]).paddingSymmetric(horizontal: 24, vertical: 8)))
|
||||
.withModalHUD(context, displayModalHUD);
|
||||
}
|
||||
}
|
||||
|
@ -70,10 +70,10 @@ class _NewAccountPageState extends State<NewAccountPage> {
|
||||
_isInAsyncCall = true;
|
||||
});
|
||||
try {
|
||||
final superSecret = await AccountRepository.instance
|
||||
final writableSuperIdentity = await AccountRepository.instance
|
||||
.createWithNewSuperIdentity(newProfile);
|
||||
GoRouterHelper(context)
|
||||
.pushReplacement('/new_account/recovery_key', extra: superSecret);
|
||||
GoRouterHelper(context).pushReplacement('/new_account/recovery_key',
|
||||
extra: [writableSuperIdentity, newProfile.name]);
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
@ -94,7 +94,6 @@ class _NewAccountPageState extends State<NewAccountPage> {
|
||||
final displayModalHUD = _isInAsyncCall;
|
||||
|
||||
return StyledScaffold(
|
||||
// resizeToAvoidBottomInset: false,
|
||||
appBar: DefaultAppBar(
|
||||
title: Text(translate('new_account_page.titlebar')),
|
||||
leading: Navigator.canPop(context)
|
||||
@ -114,10 +113,11 @@ class _NewAccountPageState extends State<NewAccountPage> {
|
||||
await GoRouterHelper(context).push('/settings');
|
||||
})
|
||||
]),
|
||||
body: _newAccountForm(
|
||||
body: SingleChildScrollView(
|
||||
child: _newAccountForm(
|
||||
context,
|
||||
onSubmit: _onSubmit,
|
||||
).paddingSymmetric(horizontal: 24, vertical: 8),
|
||||
)).paddingSymmetric(horizontal: 24, vertical: 8),
|
||||
).withModalHUD(context, displayModalHUD);
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ class _EditProfileFormState extends State<EditProfileForm> {
|
||||
) =>
|
||||
FormBuilder(
|
||||
key: _formKey,
|
||||
child: ListView(
|
||||
child: Column(
|
||||
children: [
|
||||
Text(widget.header)
|
||||
.textStyle(context.headlineSmall)
|
||||
|
@ -7,12 +7,15 @@ import '../../theme/theme.dart';
|
||||
class ProfileWidget extends StatelessWidget {
|
||||
const ProfileWidget({
|
||||
required proto.Profile profile,
|
||||
required bool showPronouns,
|
||||
super.key,
|
||||
}) : _profile = profile;
|
||||
}) : _profile = profile,
|
||||
_showPronouns = showPronouns;
|
||||
|
||||
//
|
||||
|
||||
final proto.Profile _profile;
|
||||
final bool _showPronouns;
|
||||
|
||||
//
|
||||
|
||||
@ -42,22 +45,25 @@ class ProfileWidget extends StatelessWidget {
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(16 * scaleConfig.borderRadiusScale))),
|
||||
),
|
||||
child: Column(children: [
|
||||
child: Row(children: [
|
||||
const Spacer(),
|
||||
Text(
|
||||
_profile.name,
|
||||
style: textTheme.headlineSmall!.copyWith(
|
||||
style: textTheme.titleMedium!.copyWith(
|
||||
color: scaleConfig.preferBorders
|
||||
? scale.primaryScale.border
|
||||
: scale.primaryScale.borderText),
|
||||
textAlign: TextAlign.left,
|
||||
).paddingAll(4),
|
||||
if (_profile.pronouns.isNotEmpty)
|
||||
Text(_profile.pronouns,
|
||||
style: textTheme.bodyMedium!.copyWith(
|
||||
).paddingAll(12),
|
||||
if (_profile.pronouns.isNotEmpty && _showPronouns)
|
||||
Text('(${_profile.pronouns})',
|
||||
textAlign: TextAlign.right,
|
||||
style: textTheme.bodySmall!.copyWith(
|
||||
color: scaleConfig.preferBorders
|
||||
? scale.primaryScale.border
|
||||
: scale.primaryScale.borderText))
|
||||
.paddingLTRB(4, 0, 4, 4),
|
||||
: scale.primaryScale.primary))
|
||||
.paddingAll(12),
|
||||
const Spacer()
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
@ -1,10 +1,18 @@
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:async_tools/async_tools.dart';
|
||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||
import 'package:file_saver/file_saver.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_translate/flutter_translate.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:pdf/widgets.dart' as pw;
|
||||
import 'package:printing/printing.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart';
|
||||
import 'package:screenshot/screenshot.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
import 'package:veilid_support/veilid_support.dart';
|
||||
|
||||
import '../../layout/default_app_bar.dart';
|
||||
@ -13,13 +21,18 @@ import '../../tools/tools.dart';
|
||||
import '../../veilid_processor/veilid_processor.dart';
|
||||
|
||||
class ShowRecoveryKeyPage extends StatefulWidget {
|
||||
const ShowRecoveryKeyPage({required SecretKey secretKey, super.key})
|
||||
: _secretKey = secretKey;
|
||||
const ShowRecoveryKeyPage(
|
||||
{required WritableSuperIdentity writableSuperIdentity,
|
||||
required String name,
|
||||
super.key})
|
||||
: _writableSuperIdentity = writableSuperIdentity,
|
||||
_name = name;
|
||||
|
||||
@override
|
||||
ShowRecoveryKeyPageState createState() => ShowRecoveryKeyPageState();
|
||||
|
||||
final SecretKey _secretKey;
|
||||
final WritableSuperIdentity _writableSuperIdentity;
|
||||
final String _name;
|
||||
}
|
||||
|
||||
class ShowRecoveryKeyPageState extends State<ShowRecoveryKeyPage> {
|
||||
@ -33,18 +46,99 @@ class ShowRecoveryKeyPageState extends State<ShowRecoveryKeyPage> {
|
||||
});
|
||||
}
|
||||
|
||||
Widget _recoveryKeyWidget(SecretKey _secretKey) {
|
||||
Future<void> _shareRecoveryKey(
|
||||
BuildContext context, Uint8List recoveryKey, String name) async {
|
||||
setState(() {
|
||||
_isInAsyncCall = true;
|
||||
});
|
||||
|
||||
final screenshotController = ScreenshotController();
|
||||
final bytes = await screenshotController.captureFromWidget(
|
||||
Container(
|
||||
color: Colors.white,
|
||||
width: 400,
|
||||
height: 400,
|
||||
child: _recoveryKeyWidget(context, recoveryKey, name)),
|
||||
);
|
||||
|
||||
setState(() {
|
||||
_isInAsyncCall = false;
|
||||
});
|
||||
|
||||
if (Platform.isLinux) {
|
||||
// Share plus doesn't do Linux yet
|
||||
await FileSaver.instance.saveFile(name: 'recovery_key.png', bytes: bytes);
|
||||
} else {
|
||||
final xfile = XFile.fromData(
|
||||
bytes,
|
||||
mimeType: 'image/png',
|
||||
name: 'recovery_key.png',
|
||||
);
|
||||
await Share.shareXFiles([xfile]);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> _printRecoveryKey(
|
||||
BuildContext context, Uint8List recoveryKey, String name) async {
|
||||
final wrapped = await WidgetWrapper.fromWidget(
|
||||
context: context,
|
||||
widget: SizedBox(
|
||||
width: 400,
|
||||
height: 400,
|
||||
child: _recoveryKeyWidget(context, recoveryKey, name)),
|
||||
constraints: const BoxConstraints(maxWidth: 400, maxHeight: 400),
|
||||
pixelRatio: 3);
|
||||
|
||||
final doc = pw.Document()
|
||||
..addPage(pw.Page(
|
||||
build: (context) =>
|
||||
pw.Center(child: pw.Image(wrapped, width: 400)) // Center
|
||||
)); // Page
|
||||
|
||||
await Printing.layoutPdf(onLayout: (format) async => doc.save());
|
||||
}
|
||||
|
||||
static Widget _recoveryKeyWidget(
|
||||
BuildContext context, Uint8List recoveryKey, String name) {
|
||||
final theme = Theme.of(context);
|
||||
final textTheme = theme.textTheme;
|
||||
//final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||
|
||||
return Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
Text(
|
||||
style: textTheme.headlineSmall!.copyWith(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
translate('show_recovery_key_page.recovery_key'))
|
||||
.paddingLTRB(16, 16, 16, 0),
|
||||
FittedBox(
|
||||
child: QrImageView.withQr(
|
||||
size: 300,
|
||||
qr: QrCode.fromUint8List(
|
||||
data: recoveryKey,
|
||||
errorCorrectLevel: QrErrorCorrectLevel.L)))
|
||||
.paddingLTRB(16, 16, 16, 8)
|
||||
.expanded(),
|
||||
Text(
|
||||
style: textTheme.labelMedium!.copyWith(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
name)
|
||||
.paddingLTRB(16, 8, 16, 24),
|
||||
]);
|
||||
}
|
||||
|
||||
static Widget _recoveryKeyDialog(
|
||||
BuildContext context, Uint8List recoveryKey, String name) {
|
||||
final theme = Theme.of(context);
|
||||
//final textTheme = theme.textTheme;
|
||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||
|
||||
final cardsize =
|
||||
min<double>(MediaQuery.of(context).size.shortestSide - 48.0, 400);
|
||||
|
||||
final phonoString = prettyPhonoString(
|
||||
encodePhono(_secretKey.decode()),
|
||||
wordsPerLine: 2,
|
||||
);
|
||||
return Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
side: const BorderSide(width: 2),
|
||||
@ -55,65 +149,19 @@ class ShowRecoveryKeyPageState extends State<ShowRecoveryKeyPage> {
|
||||
constraints: BoxConstraints(
|
||||
minWidth: cardsize,
|
||||
maxWidth: cardsize,
|
||||
minHeight: cardsize,
|
||||
maxHeight: cardsize),
|
||||
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
Text(
|
||||
style: textTheme.headlineSmall!.copyWith(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
translate('show_recovery_key_page.recovery_key'))
|
||||
.paddingAll(32),
|
||||
Text(
|
||||
style: textTheme.headlineSmall!.copyWith(
|
||||
color: Colors.black, fontFamily: 'Source Code Pro'),
|
||||
phonoString)
|
||||
])));
|
||||
}
|
||||
|
||||
Widget _optionBox(
|
||||
{required String instructions,
|
||||
required Icon buttonIcon,
|
||||
required String buttonText,
|
||||
required void Function() onClick}) {
|
||||
final theme = Theme.of(context);
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||
|
||||
return Container(
|
||||
constraints: const BoxConstraints(maxWidth: 400),
|
||||
decoration: BoxDecoration(
|
||||
color: scale.primaryScale.subtleBackground,
|
||||
borderRadius:
|
||||
BorderRadius.circular(8 * scaleConfig.borderRadiusScale),
|
||||
border: Border.all(color: scale.primaryScale.border)),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
style: theme.textTheme.labelMedium!
|
||||
.copyWith(color: scale.primaryScale.appText),
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.center,
|
||||
instructions),
|
||||
ElevatedButton(
|
||||
onPressed: onClick,
|
||||
child: Row(mainAxisSize: MainAxisSize.min, children: [
|
||||
buttonIcon.paddingLTRB(0, 8, 12, 8),
|
||||
Text(textAlign: TextAlign.center, buttonText)
|
||||
])).paddingLTRB(0, 12, 0, 0).toCenter()
|
||||
]).paddingAll(12))
|
||||
.paddingLTRB(24, 0, 24, 12);
|
||||
minHeight: cardsize + 16,
|
||||
maxHeight: cardsize + 16),
|
||||
child: _recoveryKeyWidget(context, recoveryKey, name)));
|
||||
}
|
||||
|
||||
@override
|
||||
// ignore: prefer_expression_function_bodies
|
||||
Widget build(BuildContext context) {
|
||||
final secretKey = widget._secretKey;
|
||||
final theme = Theme.of(context);
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||
// final scale = theme.extension<ScaleScheme>()!;
|
||||
// final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||
|
||||
final displayModalHUD = _isInAsyncCall;
|
||||
|
||||
return StyledScaffold(
|
||||
// resizeToAvoidBottomInset: false,
|
||||
@ -146,42 +194,55 @@ class ShowRecoveryKeyPageState extends State<ShowRecoveryKeyPage> {
|
||||
Text(
|
||||
textAlign: TextAlign.center,
|
||||
translate('show_recovery_key_page.instructions_options'))
|
||||
.paddingLTRB(12, 0, 12, 12),
|
||||
_optionBox(
|
||||
.paddingLTRB(12, 0, 12, 24),
|
||||
OptionBox(
|
||||
instructions:
|
||||
translate('show_recovery_key_page.instructions_print'),
|
||||
buttonIcon: const Icon(Icons.print),
|
||||
buttonIcon: Icons.print,
|
||||
buttonText: translate('show_recovery_key_page.print'),
|
||||
onClick: () {
|
||||
//
|
||||
setState(() {
|
||||
_codeHandled = true;
|
||||
});
|
||||
}),
|
||||
_optionBox(
|
||||
instructions:
|
||||
translate('show_recovery_key_page.instructions_view'),
|
||||
buttonIcon: const Icon(Icons.edit_document),
|
||||
buttonText: translate('show_recovery_key_page.view'),
|
||||
onClick: () {
|
||||
//
|
||||
singleFuture(this, () async {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => _recoveryKeyWidget(secretKey));
|
||||
await _printRecoveryKey(context,
|
||||
widget._writableSuperIdentity.recoveryKey, widget._name);
|
||||
});
|
||||
|
||||
setState(() {
|
||||
_codeHandled = true;
|
||||
});
|
||||
}),
|
||||
_optionBox(
|
||||
OptionBox(
|
||||
instructions:
|
||||
translate('show_recovery_key_page.instructions_view'),
|
||||
buttonIcon: Icons.edit_document,
|
||||
buttonText: translate('show_recovery_key_page.view'),
|
||||
onClick: () {
|
||||
//
|
||||
singleFuture(this, () async {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => _recoveryKeyDialog(
|
||||
context,
|
||||
widget._writableSuperIdentity.recoveryKey,
|
||||
widget._name));
|
||||
});
|
||||
|
||||
setState(() {
|
||||
_codeHandled = true;
|
||||
});
|
||||
}),
|
||||
OptionBox(
|
||||
instructions:
|
||||
translate('show_recovery_key_page.instructions_share'),
|
||||
buttonIcon: const Icon(Icons.ios_share),
|
||||
buttonIcon: Icons.ios_share,
|
||||
buttonText: translate('show_recovery_key_page.share'),
|
||||
onClick: () {
|
||||
//
|
||||
singleFuture(this, () async {
|
||||
await _shareRecoveryKey(context,
|
||||
widget._writableSuperIdentity.recoveryKey, widget._name);
|
||||
});
|
||||
|
||||
setState(() {
|
||||
_codeHandled = true;
|
||||
});
|
||||
@ -198,8 +259,9 @@ class ShowRecoveryKeyPageState extends State<ShowRecoveryKeyPage> {
|
||||
},
|
||||
child: Text(translate('button.finish')).paddingAll(8))
|
||||
.paddingAll(12))
|
||||
])));
|
||||
]))).withModalHUD(context, displayModalHUD);
|
||||
}
|
||||
|
||||
bool _codeHandled = false;
|
||||
bool _isInAsyncCall = false;
|
||||
}
|
||||
|
@ -149,8 +149,8 @@ class VeilidChatApp extends StatelessWidget {
|
||||
scale.grayScale.subtleBackground,
|
||||
]
|
||||
: [
|
||||
scale.tertiaryScale.hoverElementBackground,
|
||||
scale.tertiaryScale.subtleBackground,
|
||||
scale.primaryScale.hoverElementBackground,
|
||||
scale.primaryScale.subtleBackground,
|
||||
]);
|
||||
|
||||
return DecoratedBox(
|
||||
|
@ -14,14 +14,13 @@ class NoConversationWidget extends StatelessWidget {
|
||||
final theme = Theme.of(context);
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
return DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
color: scale.primaryScale.appBackground,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.diversity_3,
|
||||
@ -29,6 +28,7 @@ class NoConversationWidget extends StatelessWidget {
|
||||
size: 48,
|
||||
),
|
||||
Text(
|
||||
textAlign: TextAlign.center,
|
||||
translate('chat.start_a_conversation'),
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: scale.primaryScale.subtleBorder,
|
||||
|
@ -11,7 +11,6 @@ import 'package:qr_flutter/qr_flutter.dart';
|
||||
import 'package:veilid_support/veilid_support.dart';
|
||||
|
||||
import '../../theme/theme.dart';
|
||||
import '../../tools/tools.dart';
|
||||
import '../contact_invitation.dart';
|
||||
|
||||
class ContactInvitationDisplayDialog extends StatelessWidget {
|
||||
|
@ -49,7 +49,7 @@ class ContactInvitationListWidgetState
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
|
||||
)),
|
||||
constraints: const BoxConstraints(maxHeight: 200),
|
||||
constraints: const BoxConstraints(maxHeight: 100),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
decoration: ShapeDecoration(
|
||||
@ -59,6 +59,7 @@ class ContactInvitationListWidgetState
|
||||
BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
|
||||
)),
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
controller: _scrollController,
|
||||
itemCount: widget.contactInvitationRecordList.length,
|
||||
itemBuilder: (context, index) {
|
||||
|
@ -11,7 +11,6 @@ import 'package:veilid_support/veilid_support.dart';
|
||||
|
||||
import '../../account_manager/account_manager.dart';
|
||||
import '../../theme/theme.dart';
|
||||
import '../../tools/tools.dart';
|
||||
import '../contact_invitation.dart';
|
||||
|
||||
class CreateInvitationDialog extends StatefulWidget {
|
||||
|
@ -270,11 +270,12 @@ class InvitationDialogState extends State<InvitationDialog> {
|
||||
if (_validInvitation != null && !_isValidating)
|
||||
Column(children: [
|
||||
Container(
|
||||
constraints: const BoxConstraints(maxHeight: 64),
|
||||
width: double.infinity,
|
||||
child:
|
||||
ProfileWidget(profile: _validInvitation!.remoteProfile))
|
||||
.paddingLTRB(0, 0, 0, 16),
|
||||
constraints: const BoxConstraints(maxHeight: 64),
|
||||
width: double.infinity,
|
||||
child: ProfileWidget(
|
||||
profile: _validInvitation!.remoteProfile,
|
||||
showPronouns: true,
|
||||
)).paddingLTRB(0, 0, 0, 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
|
@ -8,7 +8,6 @@ import 'package:provider/provider.dart';
|
||||
import 'package:veilid_support/veilid_support.dart';
|
||||
|
||||
import '../../theme/theme.dart';
|
||||
import '../../tools/tools.dart';
|
||||
import 'invitation_dialog.dart';
|
||||
|
||||
class PasteInvitationDialog extends StatefulWidget {
|
||||
|
@ -13,7 +13,6 @@ import 'package:provider/provider.dart';
|
||||
import 'package:zxing2/qrcode.dart';
|
||||
|
||||
import '../../theme/theme.dart';
|
||||
import '../../tools/tools.dart';
|
||||
import 'invitation_dialog.dart';
|
||||
|
||||
// class BarcodeOverlay extends CustomPainter {
|
||||
|
@ -10,12 +10,15 @@ import '../../theme/theme.dart';
|
||||
import 'contact_item_widget.dart';
|
||||
import 'empty_contact_list_widget.dart';
|
||||
|
||||
class ContactListWidget extends StatelessWidget {
|
||||
class ContactListWidget extends StatefulWidget {
|
||||
const ContactListWidget(
|
||||
{required this.contactList, required this.disabled, super.key});
|
||||
final IList<proto.Contact> contactList;
|
||||
final bool disabled;
|
||||
|
||||
@override
|
||||
State<ContactListWidget> createState() => _ContactListWidgetState();
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
@ -23,45 +26,51 @@ class ContactListWidget extends StatelessWidget {
|
||||
..add(IterableProperty<proto.Contact>('contactList', contactList))
|
||||
..add(DiagnosticsProperty<bool>('disabled', disabled));
|
||||
}
|
||||
}
|
||||
|
||||
class _ContactListWidgetState extends State<ContactListWidget> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
|
||||
return SizedBox.expand(
|
||||
child: styledTitleContainer(
|
||||
context: context,
|
||||
title: translate('contact_list.title'),
|
||||
child: SizedBox.expand(
|
||||
child: (contactList.isEmpty)
|
||||
? const EmptyContactListWidget()
|
||||
: SearchableList<proto.Contact>(
|
||||
initialList: contactList.toList(),
|
||||
itemBuilder: (c) =>
|
||||
ContactItemWidget(contact: c, disabled: disabled)
|
||||
.paddingLTRB(0, 4, 0, 0),
|
||||
filter: (value) {
|
||||
final lowerValue = value.toLowerCase();
|
||||
return contactList
|
||||
.where((element) =>
|
||||
element.nickname
|
||||
.toLowerCase()
|
||||
.contains(lowerValue) ||
|
||||
element.profile.name
|
||||
.toLowerCase()
|
||||
.contains(lowerValue) ||
|
||||
element.profile.pronouns
|
||||
.toLowerCase()
|
||||
.contains(lowerValue))
|
||||
.toList();
|
||||
},
|
||||
spaceBetweenSearchAndList: 4,
|
||||
defaultSuffixIconColor: scale.primaryScale.border,
|
||||
inputDecoration: InputDecoration(
|
||||
labelText: translate('contact_list.search'),
|
||||
),
|
||||
).paddingAll(8),
|
||||
))).paddingLTRB(8, 0, 8, 8);
|
||||
return styledTitleContainer(
|
||||
context: context,
|
||||
title: translate('contact_list.title'),
|
||||
child: SearchableList<proto.Contact>(
|
||||
shrinkWrap: true,
|
||||
initialList: widget.contactList.toList(),
|
||||
itemBuilder: (c) =>
|
||||
ContactItemWidget(contact: c, disabled: widget.disabled)
|
||||
.paddingLTRB(0, 4, 0, 0),
|
||||
filter: (value) {
|
||||
final lowerValue = value.toLowerCase();
|
||||
return widget.contactList
|
||||
.where((element) =>
|
||||
element.nickname.toLowerCase().contains(lowerValue) ||
|
||||
element.profile.name.toLowerCase().contains(lowerValue) ||
|
||||
element.profile.pronouns.toLowerCase().contains(lowerValue))
|
||||
.toList();
|
||||
},
|
||||
searchFieldHeight: 40,
|
||||
spaceBetweenSearchAndList: 4,
|
||||
emptyWidget: const EmptyContactListWidget(),
|
||||
defaultSuffixIconColor: scale.primaryScale.border,
|
||||
closeKeyboardWhenScrolling: true,
|
||||
inputDecoration: InputDecoration(
|
||||
labelText: translate('contact_list.search'),
|
||||
),
|
||||
).paddingAll(8),
|
||||
).paddingLTRB(8, 0, 8, 8);
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ class EmptyContactListWidget extends StatelessWidget {
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
@ -25,6 +26,7 @@ class EmptyContactListWidget extends StatelessWidget {
|
||||
size: 48,
|
||||
),
|
||||
Text(
|
||||
textAlign: TextAlign.center,
|
||||
translate('contact_list.invite_people'),
|
||||
style: textTheme.bodyMedium?.copyWith(
|
||||
color: scale.primaryScale.subtleBorder,
|
||||
|
@ -1,7 +1,6 @@
|
||||
import 'package:async_tools/async_tools.dart';
|
||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
@ -20,7 +19,7 @@ class DrawerMenu extends StatefulWidget {
|
||||
const DrawerMenu({super.key});
|
||||
|
||||
@override
|
||||
State createState() => _DrawerMenuState();
|
||||
State<DrawerMenu> createState() => _DrawerMenuState();
|
||||
}
|
||||
|
||||
class _DrawerMenuState extends State<DrawerMenu> {
|
||||
@ -105,10 +104,12 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||
width: 34,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: border,
|
||||
width: 2,
|
||||
strokeAlign: BorderSide.strokeAlignOutside),
|
||||
border: scaleConfig.preferBorders
|
||||
? Border.all(
|
||||
color: border,
|
||||
width: 2,
|
||||
strokeAlign: BorderSide.strokeAlignOutside)
|
||||
: null,
|
||||
color: Colors.blue,
|
||||
),
|
||||
child: AvatarImage(
|
||||
@ -130,9 +131,18 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||
backgroundColor: background,
|
||||
backgroundHoverColor: hoverBackground,
|
||||
backgroundFocusColor: activeBackground,
|
||||
borderColor: border,
|
||||
borderHoverColor: hoverBorder,
|
||||
borderFocusColor: activeBorder,
|
||||
borderColor:
|
||||
(scaleConfig.preferBorders || scaleConfig.useVisualIndicators)
|
||||
? border
|
||||
: null,
|
||||
borderHoverColor:
|
||||
(scaleConfig.preferBorders || scaleConfig.useVisualIndicators)
|
||||
? hoverBorder
|
||||
: null,
|
||||
borderFocusColor:
|
||||
(scaleConfig.preferBorders || scaleConfig.useVisualIndicators)
|
||||
? activeBorder
|
||||
: null,
|
||||
borderRadius: 16 * scaleConfig.borderRadiusScale,
|
||||
callback: callback,
|
||||
footerButtonIcon: loggedIn ? Icons.edit_outlined : null,
|
||||
@ -143,7 +153,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||
));
|
||||
}
|
||||
|
||||
Widget _getAccountList(
|
||||
List<Widget> _getAccountList(
|
||||
{required IList<LocalAccount> localAccounts,
|
||||
required TypedKey? activeLocalAccount,
|
||||
required PerAccountCollectionBlocMapState
|
||||
@ -164,7 +174,9 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||
final avAccountRecordState = perAccountState?.avAccountRecordState;
|
||||
if (perAccountState != null && avAccountRecordState != null) {
|
||||
// Account is logged in
|
||||
final scale = theme.extension<ScaleScheme>()!.primaryScale;
|
||||
final scale = scaleConfig.useVisualIndicators
|
||||
? theme.extension<ScaleScheme>()!.primaryScale
|
||||
: theme.extension<ScaleScheme>()!.tertiaryScale;
|
||||
final loggedInAccount = avAccountRecordState.when(
|
||||
data: (value) => _makeAccountWidget(
|
||||
name: value.profile.name,
|
||||
@ -209,14 +221,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||
}
|
||||
|
||||
// Assemble main menu
|
||||
final mainMenu = <Widget>[...loggedInAccounts, ...loggedOutAccounts];
|
||||
|
||||
// Return main menu widgets
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[...mainMenu],
|
||||
);
|
||||
return <Widget>[...loggedInAccounts, ...loggedOutAccounts];
|
||||
}
|
||||
|
||||
Widget _getButton(
|
||||
@ -262,18 +267,18 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||
}), shape: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.contains(WidgetState.hovered)) {
|
||||
return RoundedRectangleBorder(
|
||||
side: BorderSide(color: hoverBorder),
|
||||
side: BorderSide(color: hoverBorder, width: 2),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(16 * scaleConfig.borderRadiusScale)));
|
||||
}
|
||||
if (states.contains(WidgetState.focused)) {
|
||||
return RoundedRectangleBorder(
|
||||
side: BorderSide(color: activeBorder),
|
||||
side: BorderSide(color: activeBorder, width: 2),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(16 * scaleConfig.borderRadiusScale)));
|
||||
}
|
||||
return RoundedRectangleBorder(
|
||||
side: BorderSide(color: border),
|
||||
side: BorderSide(color: border, width: 2),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(16 * scaleConfig.borderRadiusScale)));
|
||||
})),
|
||||
@ -306,7 +311,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [settingsButton, addButton]).paddingLTRB(0, 16, 0, 0);
|
||||
children: [settingsButton, addButton]).paddingLTRB(0, 16, 0, 16);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -323,8 +328,8 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
scale.tertiaryScale.border,
|
||||
scale.tertiaryScale.subtleBorder,
|
||||
scale.tertiaryScale.subtleBackground,
|
||||
]);
|
||||
|
||||
return DecoratedBox(
|
||||
@ -391,35 +396,21 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||
? grayColorFilter
|
||||
: null),
|
||||
]))),
|
||||
const Spacer(),
|
||||
DecoratedBox(
|
||||
decoration: ShapeDecoration(
|
||||
shape: RoundedRectangleBorder(
|
||||
side: !scaleConfig.useVisualIndicators
|
||||
? BorderSide.none
|
||||
: scaleConfig.preferBorders
|
||||
? BorderSide(color: scale.tertiaryScale.border)
|
||||
: BorderSide(color: scale.tertiaryScale.primary),
|
||||
borderRadius: BorderRadius.circular(
|
||||
16 * scaleConfig.borderRadiusScale)),
|
||||
color: scaleConfig.preferBorders
|
||||
? Colors.transparent
|
||||
: scale.tertiaryScale.border.withAlpha(0x5F)),
|
||||
child: Column(children: [
|
||||
Text(translate('menu.accounts'),
|
||||
style: theme.textTheme.titleMedium!.copyWith(
|
||||
color: scaleConfig.preferBorders
|
||||
? scale.tertiaryScale.border
|
||||
: scale.tertiaryScale.primary))
|
||||
.paddingLTRB(0, 0, 0, 16),
|
||||
_getAccountList(
|
||||
localAccounts: localAccounts,
|
||||
activeLocalAccount: activeLocalAccount,
|
||||
perAccountCollectionBlocMapState:
|
||||
perAccountCollectionBlocMapState)
|
||||
]).paddingAll(16)),
|
||||
Text(translate('menu.accounts'),
|
||||
style: theme.textTheme.titleMedium!.copyWith(
|
||||
color: scaleConfig.preferBorders
|
||||
? scale.tertiaryScale.border
|
||||
: scale.tertiaryScale.borderText))
|
||||
.paddingLTRB(0, 16, 0, 16),
|
||||
ListView(
|
||||
shrinkWrap: true,
|
||||
children: _getAccountList(
|
||||
localAccounts: localAccounts,
|
||||
activeLocalAccount: activeLocalAccount,
|
||||
perAccountCollectionBlocMapState:
|
||||
perAccountCollectionBlocMapState))
|
||||
.expanded(),
|
||||
_getBottomButtons(),
|
||||
const Spacer(),
|
||||
Row(children: [
|
||||
Text('${translate('menu.version')} $packageInfoVersion',
|
||||
style: theme.textTheme.labelMedium!
|
||||
|
@ -72,7 +72,7 @@ class MenuItemWidget extends StatelessWidget {
|
||||
).paddingAll(8)),
|
||||
),
|
||||
if (footerButtonIcon != null)
|
||||
IconButton.outlined(
|
||||
IconButton(
|
||||
color: footerButtonIconColor,
|
||||
focusColor: footerButtonIconFocusColor,
|
||||
hoverColor: footerButtonIconHoverColor,
|
||||
|
@ -34,6 +34,7 @@ class HomeAccountReadyChatState extends State<HomeAccountReadyChat> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SafeArea(
|
||||
bottom: false,
|
||||
child: buildChatComponent(context),
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_translate/flutter_translate.dart';
|
||||
@ -9,7 +8,6 @@ import '../../../account_manager/account_manager.dart';
|
||||
import '../../../chat/chat.dart';
|
||||
import '../../../proto/proto.dart' as proto;
|
||||
import '../../../theme/theme.dart';
|
||||
import '../../../tools/tools.dart';
|
||||
import 'main_pager/main_pager.dart';
|
||||
|
||||
class HomeAccountReadyMain extends StatefulWidget {
|
||||
@ -44,7 +42,7 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
|
||||
? scale.primaryScale.border
|
||||
: scale.primaryScale.borderText,
|
||||
constraints:
|
||||
const BoxConstraints.expand(height: 64, width: 64),
|
||||
const BoxConstraints.expand(height: 48, width: 48),
|
||||
style: ButtonStyle(
|
||||
backgroundColor: WidgetStateProperty.all(
|
||||
scaleConfig.preferBorders
|
||||
@ -61,7 +59,7 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
|
||||
: scale.primaryScale.borderText,
|
||||
width: 2),
|
||||
borderRadius: BorderRadius.all(Radius.circular(
|
||||
16 * scaleConfig.borderRadiusScale))),
|
||||
12 * scaleConfig.borderRadiusScale))),
|
||||
)),
|
||||
tooltip: translate('menu.settings_tooltip'),
|
||||
onPressed: () async {
|
||||
@ -69,7 +67,10 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
|
||||
await ctrl.toggle?.call();
|
||||
//await GoRouterHelper(context).push('/settings');
|
||||
}).paddingLTRB(0, 0, 8, 0),
|
||||
ProfileWidget(profile: profile).expanded(),
|
||||
ProfileWidget(
|
||||
profile: profile,
|
||||
showPronouns: false,
|
||||
).expanded(),
|
||||
]).paddingAll(8),
|
||||
MainPager(key: _mainPagerKey).expanded()
|
||||
]));
|
||||
|
@ -55,6 +55,8 @@ class AccountPageState extends State<AccountPage> {
|
||||
tilePadding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
|
||||
backgroundColor: scale.primaryScale.border,
|
||||
collapsedBackgroundColor: scale.primaryScale.border,
|
||||
dense: true,
|
||||
minTileHeight: 16,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
|
||||
@ -66,10 +68,11 @@ class AccountPageState extends State<AccountPage> {
|
||||
title: Text(
|
||||
translate('account_page.contact_invitations'),
|
||||
textAlign: TextAlign.center,
|
||||
style: textTheme.titleMedium!
|
||||
style: textTheme.titleSmall!
|
||||
.copyWith(color: scale.primaryScale.borderText),
|
||||
),
|
||||
iconColor: scale.primaryScale.borderText,
|
||||
collapsedIconColor: scale.primaryScale.borderText,
|
||||
initiallyExpanded: true,
|
||||
children: [
|
||||
ContactInvitationListWidget(
|
||||
|
@ -46,6 +46,7 @@ class BottomSheetActionButtonState extends State<BottomSheetActionButton> {
|
||||
return _showFab
|
||||
? FloatingActionButton(
|
||||
elevation: 0,
|
||||
heroTag: this,
|
||||
hoverElevation: 0,
|
||||
shape: widget.shape,
|
||||
foregroundColor: widget.foregroundColor,
|
||||
|
@ -113,7 +113,7 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Text(
|
||||
_bottomLabelList[index],
|
||||
style: theme.textTheme.labelLarge!.copyWith(
|
||||
style: theme.textTheme.labelMedium!.copyWith(
|
||||
fontWeight: isActive ? FontWeight.bold : FontWeight.normal,
|
||||
color: color),
|
||||
),
|
||||
|
@ -74,7 +74,10 @@ class HomeScreenState extends State<HomeScreen>
|
||||
tablet: false,
|
||||
tabletLandscape: false,
|
||||
desktop: false)) {
|
||||
final activeChatCubit = context.watch<ActiveChatCubit>();
|
||||
|
||||
return BlocConsumer<ActiveChatCubit, TypedKey?>(
|
||||
bloc: activeChatCubit,
|
||||
listener: (context, activeChat) {
|
||||
final hasActiveChat = activeChat != null;
|
||||
if (hasActiveChat) {
|
||||
@ -179,6 +182,7 @@ class HomeScreenState extends State<HomeScreen>
|
||||
final canClose = activeIndex != -1;
|
||||
|
||||
return SafeArea(
|
||||
bottom: false,
|
||||
child: DefaultTextStyle(
|
||||
style: theme.textTheme.bodySmall!,
|
||||
child: ZoomDrawer(
|
||||
|
@ -78,10 +78,14 @@ class RouterCubit extends Cubit<RouterState> {
|
||||
builder: (context, state) => const NewAccountPage(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/new_account/recovery_key',
|
||||
builder: (context, state) =>
|
||||
ShowRecoveryKeyPage(secretKey: state.extra! as SecretKey),
|
||||
),
|
||||
path: '/new_account/recovery_key',
|
||||
builder: (context, state) {
|
||||
final extra = state.extra! as List<Object?>;
|
||||
|
||||
return ShowRecoveryKeyPage(
|
||||
writableSuperIdentity: extra[0]! as WritableSuperIdentity,
|
||||
name: extra[1]! as String);
|
||||
}),
|
||||
GoRoute(
|
||||
path: '/settings',
|
||||
builder: (context, state) => const SettingsPage(),
|
||||
|
@ -31,6 +31,7 @@ ChatTheme makeChatTheme(
|
||||
),
|
||||
inputBackgroundColor: Colors.blue,
|
||||
inputBorderRadius: BorderRadius.zero,
|
||||
inputTextStyle: textTheme.bodyLarge!,
|
||||
inputTextDecoration: InputDecoration(
|
||||
filled: !scaleConfig.preferBorders,
|
||||
fillColor: scale.primaryScale.subtleBackground,
|
||||
@ -77,13 +78,10 @@ ChatTheme makeChatTheme(
|
||||
color: Colors.white,
|
||||
fontSize: 64,
|
||||
),
|
||||
receivedMessageBodyTextStyle: TextStyle(
|
||||
receivedMessageBodyTextStyle: textTheme.bodyLarge!.copyWith(
|
||||
color: scaleConfig.preferBorders
|
||||
? scale.secondaryScale.calloutBackground
|
||||
: scale.secondaryScale.calloutText,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.5,
|
||||
),
|
||||
receivedEmojiMessageTextStyle: const TextStyle(
|
||||
color: Colors.white,
|
||||
|
@ -106,7 +106,7 @@ class SliderTile extends StatelessWidget {
|
||||
? tileColor.border
|
||||
: tileColor.borderText)
|
||||
: scale.scale(a.actionScale).primaryText,
|
||||
icon: a.icon,
|
||||
icon: subtitle.isNotEmpty ? a.icon : null,
|
||||
label: a.label,
|
||||
padding: const EdgeInsets.all(2)),
|
||||
)
|
||||
@ -129,7 +129,7 @@ class SliderTile extends StatelessWidget {
|
||||
? tileColor.border
|
||||
: tileColor.borderText)
|
||||
: scale.scale(a.actionScale).primaryText,
|
||||
icon: a.icon,
|
||||
icon: subtitle.isNotEmpty ? a.icon : null,
|
||||
label: a.label,
|
||||
padding: const EdgeInsets.all(2)),
|
||||
)
|
||||
@ -140,9 +140,12 @@ class SliderTile extends StatelessWidget {
|
||||
: const EdgeInsets.fromLTRB(0, 2, 0, 2),
|
||||
child: ListTile(
|
||||
onTap: onTap,
|
||||
dense: true,
|
||||
visualDensity: const VisualDensity(vertical: -4),
|
||||
title: Text(
|
||||
title,
|
||||
softWrap: true,
|
||||
overflow: TextOverflow.fade,
|
||||
softWrap: false,
|
||||
),
|
||||
subtitle: subtitle.isNotEmpty ? Text(subtitle) : null,
|
||||
iconColor: textColor,
|
||||
|
@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_translate/flutter_translate.dart';
|
||||
|
||||
import '../theme/theme.dart';
|
||||
import '../theme.dart';
|
||||
|
||||
class EnterPasswordDialog extends StatefulWidget {
|
||||
const EnterPasswordDialog({
|
@ -5,7 +5,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_translate/flutter_translate.dart';
|
||||
import 'package:pinput/pinput.dart';
|
||||
|
||||
import '../theme/theme.dart';
|
||||
import '../theme.dart';
|
||||
|
||||
class EnterPinDialog extends StatefulWidget {
|
||||
const EnterPinDialog({
|
54
lib/theme/views/option_box.dart
Normal file
54
lib/theme/views/option_box.dart
Normal file
@ -0,0 +1,54 @@
|
||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../theme.dart';
|
||||
|
||||
class OptionBox extends StatelessWidget {
|
||||
const OptionBox(
|
||||
{required String instructions,
|
||||
required IconData buttonIcon,
|
||||
required String buttonText,
|
||||
required void Function() onClick,
|
||||
super.key})
|
||||
: _instructions = instructions,
|
||||
_buttonIcon = buttonIcon,
|
||||
_buttonText = buttonText,
|
||||
_onClick = onClick;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||
|
||||
return Container(
|
||||
constraints: const BoxConstraints(maxWidth: 400),
|
||||
decoration: BoxDecoration(
|
||||
color: scale.primaryScale.subtleBackground,
|
||||
borderRadius:
|
||||
BorderRadius.circular(8 * scaleConfig.borderRadiusScale),
|
||||
border: Border.all(color: scale.primaryScale.border)),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
style: theme.textTheme.labelMedium!
|
||||
.copyWith(color: scale.primaryScale.appText),
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.center,
|
||||
_instructions),
|
||||
ElevatedButton(
|
||||
onPressed: _onClick,
|
||||
child: Row(mainAxisSize: MainAxisSize.min, children: [
|
||||
Icon(_buttonIcon, size: 24).paddingLTRB(0, 8, 8, 8),
|
||||
Text(textAlign: TextAlign.center, _buttonText)
|
||||
])).paddingLTRB(0, 12, 0, 0).toCenter()
|
||||
]).paddingAll(12))
|
||||
.paddingLTRB(24, 0, 24, 12);
|
||||
}
|
||||
|
||||
final String _instructions;
|
||||
final IconData _buttonIcon;
|
||||
final String _buttonText;
|
||||
final void Function() _onClick;
|
||||
}
|
0
lib/theme/views/recovery_key_widget.dart
Normal file
0
lib/theme/views/recovery_key_widget.dart
Normal file
@ -9,7 +9,7 @@ bool get isWeb => kIsWeb;
|
||||
bool get isDesktop =>
|
||||
!isWeb && (Platform.isWindows || Platform.isLinux || Platform.isMacOS);
|
||||
|
||||
const kMobileWidthCutoff = 479.0;
|
||||
const kMobileWidthCutoff = 500.0;
|
||||
|
||||
bool isMobileWidth(BuildContext context) =>
|
||||
MediaQuery.of(context).size.width < kMobileWidthCutoff;
|
@ -12,13 +12,15 @@ class StyledScaffold extends StatelessWidget {
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||
|
||||
return clipBorder(
|
||||
clipEnabled: true,
|
||||
borderEnabled: scaleConfig.useVisualIndicators,
|
||||
borderRadius: 16 * scaleConfig.borderRadiusScale,
|
||||
borderColor: scale.primaryScale.border,
|
||||
child: Scaffold(appBar: appBar, body: body, key: key))
|
||||
.paddingAll(32);
|
||||
return isDesktop
|
||||
? clipBorder(
|
||||
clipEnabled: true,
|
||||
borderEnabled: scaleConfig.useVisualIndicators,
|
||||
borderRadius: 16 * scaleConfig.borderRadiusScale,
|
||||
borderColor: scale.primaryScale.border,
|
||||
child: Scaffold(appBar: appBar, body: body, key: key))
|
||||
.paddingAll(32)
|
||||
: Scaffold(appBar: appBar, body: body, key: key);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1,5 +1,11 @@
|
||||
export 'brightness_preferences.dart';
|
||||
export 'color_preferences.dart';
|
||||
export 'enter_password.dart';
|
||||
export 'enter_pin.dart';
|
||||
export 'option_box.dart';
|
||||
export 'pop_control.dart';
|
||||
export 'recovery_key_widget.dart';
|
||||
export 'responsive.dart';
|
||||
export 'scanner_error_widget.dart';
|
||||
export 'styled_dialog.dart';
|
||||
export 'styled_scaffold.dart';
|
||||
|
@ -183,9 +183,9 @@ Widget styledTitleContainer({
|
||||
child: Column(children: [
|
||||
Text(
|
||||
title,
|
||||
style: textTheme.titleMedium!
|
||||
style: textTheme.titleSmall!
|
||||
.copyWith(color: titleColor ?? scale.primaryScale.borderText),
|
||||
).paddingLTRB(8, 8, 8, 4),
|
||||
).paddingLTRB(8, 6, 8, 2),
|
||||
DecoratedBox(
|
||||
decoration: ShapeDecoration(
|
||||
color:
|
||||
|
@ -9,7 +9,7 @@ import 'package:loggy/loggy.dart';
|
||||
import 'package:veilid_support/veilid_support.dart';
|
||||
|
||||
import '../veilid_processor/views/developer.dart';
|
||||
import 'responsive.dart';
|
||||
import '../theme/views/responsive.dart';
|
||||
import 'state_logger.dart';
|
||||
|
||||
String wrapWithLogColor(LogLevel? level, String text) {
|
||||
|
@ -1,13 +1,8 @@
|
||||
|
||||
export 'animations.dart';
|
||||
export 'enter_password.dart';
|
||||
export 'enter_pin.dart';
|
||||
export 'loggy.dart';
|
||||
export 'misc.dart';
|
||||
export 'package_info.dart';
|
||||
export 'phono_byte.dart';
|
||||
export 'pop_control.dart';
|
||||
export 'responsive.dart';
|
||||
export 'shared_preferences.dart';
|
||||
export 'state_logger.dart';
|
||||
export 'stream_listenable.dart';
|
||||
|
@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
import '../../tools/responsive.dart';
|
||||
import '../theme/views/responsive.dart';
|
||||
|
||||
export 'package:window_manager/window_manager.dart' show TitleBarStyle;
|
||||
|
||||
@ -21,7 +21,7 @@ Future<void> initializeWindowControl() async {
|
||||
|
||||
const windowOptions = WindowOptions(
|
||||
size: Size(768, 1024),
|
||||
//minimumSize: Size(480, 480),
|
||||
minimumSize: Size(400, 500),
|
||||
center: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
skipTaskbar: false,
|
||||
|
@ -273,59 +273,61 @@ class _DeveloperPageState extends State<DeveloperPage> {
|
||||
body: GestureDetector(
|
||||
onTap: () => FocusScope.of(context).unfocus(),
|
||||
child: SafeArea(
|
||||
bottom: false,
|
||||
child: Column(children: [
|
||||
Stack(alignment: AlignmentDirectional.center, children: [
|
||||
Image.asset('assets/images/ellet.png'),
|
||||
TerminalView(globalDebugTerminal,
|
||||
textStyle: kDefaultTerminalStyle,
|
||||
controller: _terminalController,
|
||||
keyboardType: TextInputType.none,
|
||||
//autofocus: true,
|
||||
backgroundOpacity: _showEllet ? 0.75 : 1.0,
|
||||
onSecondaryTapDown: (details, offset) async {
|
||||
await copySelection(context);
|
||||
})
|
||||
]).expanded(),
|
||||
TextField(
|
||||
controller: _debugCommandController,
|
||||
onTapOutside: (event) {
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
filled: true,
|
||||
contentPadding: const EdgeInsets.fromLTRB(8, 2, 8, 2),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
8 * scaleConfig.borderRadiusScale),
|
||||
borderSide: BorderSide.none),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
8 * scaleConfig.borderRadiusScale),
|
||||
),
|
||||
fillColor: scale.primaryScale.subtleBackground,
|
||||
hintText: translate('developer.command'),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(Icons.send,
|
||||
color: _debugCommandController.text.isEmpty
|
||||
? scale.primaryScale.primary.withAlpha(0x3F)
|
||||
: scale.primaryScale.primary),
|
||||
onPressed: _debugCommandController.text.isEmpty
|
||||
? null
|
||||
: () async {
|
||||
final debugCommand = _debugCommandController.text;
|
||||
_debugCommandController.clear();
|
||||
await _sendDebugCommand(debugCommand);
|
||||
},
|
||||
)),
|
||||
onChanged: (_) {
|
||||
setState(() => {});
|
||||
},
|
||||
onSubmitted: (debugCommand) async {
|
||||
_debugCommandController.clear();
|
||||
await _sendDebugCommand(debugCommand);
|
||||
},
|
||||
).paddingAll(4)
|
||||
]))));
|
||||
Stack(alignment: AlignmentDirectional.center, children: [
|
||||
Image.asset('assets/images/ellet.png'),
|
||||
TerminalView(globalDebugTerminal,
|
||||
textStyle: kDefaultTerminalStyle,
|
||||
controller: _terminalController,
|
||||
keyboardType: TextInputType.none,
|
||||
//autofocus: true,
|
||||
backgroundOpacity: _showEllet ? 0.75 : 1.0,
|
||||
onSecondaryTapDown: (details, offset) async {
|
||||
await copySelection(context);
|
||||
})
|
||||
]).expanded(),
|
||||
TextField(
|
||||
controller: _debugCommandController,
|
||||
onTapOutside: (event) {
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
filled: true,
|
||||
contentPadding: const EdgeInsets.fromLTRB(8, 2, 8, 2),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
8 * scaleConfig.borderRadiusScale),
|
||||
borderSide: BorderSide.none),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
8 * scaleConfig.borderRadiusScale),
|
||||
),
|
||||
fillColor: scale.primaryScale.subtleBackground,
|
||||
hintText: translate('developer.command'),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(Icons.send,
|
||||
color: _debugCommandController.text.isEmpty
|
||||
? scale.primaryScale.primary.withAlpha(0x3F)
|
||||
: scale.primaryScale.primary),
|
||||
onPressed: _debugCommandController.text.isEmpty
|
||||
? null
|
||||
: () async {
|
||||
final debugCommand =
|
||||
_debugCommandController.text;
|
||||
_debugCommandController.clear();
|
||||
await _sendDebugCommand(debugCommand);
|
||||
},
|
||||
)),
|
||||
onChanged: (_) {
|
||||
setState(() => {});
|
||||
},
|
||||
onSubmitted: (debugCommand) async {
|
||||
_debugCommandController.clear();
|
||||
await _sendDebugCommand(debugCommand);
|
||||
},
|
||||
).paddingAll(4)
|
||||
]))));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -6,7 +6,9 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <file_saver/file_saver_plugin.h>
|
||||
#include <pasteboard/pasteboard_plugin.h>
|
||||
#include <printing/printing_plugin.h>
|
||||
#include <screen_retriever/screen_retriever_plugin.h>
|
||||
#include <smart_auth/smart_auth_plugin.h>
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
@ -14,9 +16,15 @@
|
||||
#include <window_manager/window_manager_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) file_saver_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSaverPlugin");
|
||||
file_saver_plugin_register_with_registrar(file_saver_registrar);
|
||||
g_autoptr(FlPluginRegistrar) pasteboard_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin");
|
||||
pasteboard_plugin_register_with_registrar(pasteboard_registrar);
|
||||
g_autoptr(FlPluginRegistrar) printing_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "PrintingPlugin");
|
||||
printing_plugin_register_with_registrar(printing_registrar);
|
||||
g_autoptr(FlPluginRegistrar) screen_retriever_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin");
|
||||
screen_retriever_plugin_register_with_registrar(screen_retriever_registrar);
|
||||
|
@ -3,7 +3,9 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
file_saver
|
||||
pasteboard
|
||||
printing
|
||||
screen_retriever
|
||||
smart_auth
|
||||
url_launcher_linux
|
||||
|
@ -5,10 +5,12 @@
|
||||
import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import file_saver
|
||||
import mobile_scanner
|
||||
import package_info_plus
|
||||
import pasteboard
|
||||
import path_provider_foundation
|
||||
import printing
|
||||
import screen_retriever
|
||||
import share_plus
|
||||
import shared_preferences_foundation
|
||||
@ -19,10 +21,12 @@ import veilid
|
||||
import window_manager
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FileSaverPlugin.register(with: registry.registrar(forPlugin: "FileSaverPlugin"))
|
||||
MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin"))
|
||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
PrintingPlugin.register(with: registry.registrar(forPlugin: "PrintingPlugin"))
|
||||
ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin"))
|
||||
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
|
@ -1,4 +1,6 @@
|
||||
PODS:
|
||||
- file_saver (0.0.1):
|
||||
- FlutterMacOS
|
||||
- FlutterMacOS (1.0.0)
|
||||
- mobile_scanner (5.1.1):
|
||||
- FlutterMacOS
|
||||
@ -9,6 +11,8 @@ PODS:
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- printing (1.0.0):
|
||||
- FlutterMacOS
|
||||
- screen_retriever (0.0.1):
|
||||
- FlutterMacOS
|
||||
- share_plus (0.0.1):
|
||||
@ -29,11 +33,13 @@ PODS:
|
||||
- FlutterMacOS
|
||||
|
||||
DEPENDENCIES:
|
||||
- file_saver (from `Flutter/ephemeral/.symlinks/plugins/file_saver/macos`)
|
||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||
- mobile_scanner (from `Flutter/ephemeral/.symlinks/plugins/mobile_scanner/macos`)
|
||||
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
|
||||
- pasteboard (from `Flutter/ephemeral/.symlinks/plugins/pasteboard/macos`)
|
||||
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- printing (from `Flutter/ephemeral/.symlinks/plugins/printing/macos`)
|
||||
- screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`)
|
||||
- share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`)
|
||||
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
@ -44,6 +50,8 @@ DEPENDENCIES:
|
||||
- window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
file_saver:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/file_saver/macos
|
||||
FlutterMacOS:
|
||||
:path: Flutter/ephemeral
|
||||
mobile_scanner:
|
||||
@ -54,6 +62,8 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/pasteboard/macos
|
||||
path_provider_foundation:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
|
||||
printing:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/printing/macos
|
||||
screen_retriever:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos
|
||||
share_plus:
|
||||
@ -72,11 +82,13 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
file_saver: 44e6fbf666677faf097302460e214e977fdd977b
|
||||
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
||||
mobile_scanner: 1efac1e53c294b24e3bb55bcc7f4deee0233a86b
|
||||
package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c
|
||||
pasteboard: 9b69dba6fedbb04866be632205d532fe2f6b1d99
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
printing: 1dd6a1fce2209ec240698e2439a4adbb9b427637
|
||||
screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38
|
||||
share_plus: 36537c04ce0c3e3f5bd297ce4318b6d5ee5fd6cf
|
||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||
|
@ -12,6 +12,8 @@
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
<key>com.apple.security.print</key>
|
||||
<true/>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$(AppIdentifierPrefix)com.veilid.veilidchat</string>
|
||||
|
@ -10,6 +10,8 @@
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
<key>com.apple.security.print</key>
|
||||
<true/>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$(AppIdentifierPrefix)com.veilid.veilidchat</string>
|
||||
|
@ -19,7 +19,9 @@ class IdentityInstance with _$IdentityInstance {
|
||||
required PublicKey publicKey,
|
||||
|
||||
// Secret key of identity instance
|
||||
// Encrypted with DH(publicKey, SuperIdentity.secret) with appended salt
|
||||
// Encrypted with appended salt, key is DeriveSharedSecret(
|
||||
// password = SuperIdentity.secret,
|
||||
// salt = publicKey)
|
||||
// Used to recover accounts without generating a new instance
|
||||
@Uint8ListJsonConverter() required Uint8List encryptedSecretKey,
|
||||
|
||||
|
@ -69,6 +69,12 @@ class WritableSuperIdentity {
|
||||
/// Delete a super identity with secrets
|
||||
Future<void> delete() async => superIdentity.delete();
|
||||
|
||||
/// Produce a recovery key for this superIdentity
|
||||
Uint8List get recoveryKey => (BytesBuilder()
|
||||
..add(superIdentity.recordKey.decode())
|
||||
..add(superSecret.decode()))
|
||||
.toBytes();
|
||||
|
||||
/// xxx: migration support, new identities, reveal identity secret etc
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
@ -113,8 +119,8 @@ class WritableSuperIdentity {
|
||||
// Make encrypted secret key
|
||||
final cs = await Veilid.instance.getCryptoSystem(identityRecordKey.kind);
|
||||
|
||||
final encryptionKey = await cs.generateSharedSecret(
|
||||
identityPublicKey, superSecret, identityCryptoDomain);
|
||||
final encryptionKey = await cs.deriveSharedSecret(
|
||||
superSecret.decode(), identityPublicKey.decode());
|
||||
final encryptedSecretKey = await cs.encryptNoAuthWithNonce(
|
||||
identitySecretKey.decode(), encryptionKey);
|
||||
|
||||
|
114
pubspec.lock
114
pubspec.lock
@ -97,6 +97,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
barcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: barcode
|
||||
sha256: ab180ce22c6555d77d45f0178a523669db67f95856e3378259ef2ffeb43e6003
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.8"
|
||||
basic_utils:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -105,6 +113,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.7.0"
|
||||
bidi:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: bidi
|
||||
sha256: "1a7d0c696324b2089f72e7671fd1f1f64fef44c980f3cebc84e803967c597b63"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.10"
|
||||
bloc:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -237,10 +253,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: camera_android
|
||||
sha256: "3af7f0b55f184d392d2eec238aaa30552ebeef2915e5e094f5488bf50d6d7ca2"
|
||||
sha256: "981654e0e56a4c735f7ecc7bd3921385eb5f7dd13deaf4a6431255d9731df01a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.10.9+3"
|
||||
version: "0.10.9+7"
|
||||
camera_avfoundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -409,6 +425,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.1"
|
||||
dio:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dio
|
||||
sha256: e17f6b3097b8c51b72c74c9f071a605c47bcc8893839bd66732457a5ebe73714
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.5.0+1"
|
||||
dio_web_adapter:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dio_web_adapter
|
||||
sha256: "36c5b2d79eb17cdae41e974b7a8284fec631651d2a6f39a8a2ff22327e90aeac"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
equatable:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -441,6 +473,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
file_saver:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: file_saver
|
||||
sha256: d375b351e3331663abbaf99747abd72f159260c58fbbdbca9f926f02c01bdc48
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.13"
|
||||
fixnum:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -466,10 +506,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_bloc
|
||||
sha256: f0ecf6e6eb955193ca60af2d5ca39565a86b8a142452c5b24d96fb477428f4d2
|
||||
sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.1.5"
|
||||
version: "8.1.6"
|
||||
flutter_cache_manager:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -489,9 +529,11 @@ packages:
|
||||
flutter_chat_ui:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "../flutter_chat_ui"
|
||||
relative: true
|
||||
source: path
|
||||
path: "."
|
||||
ref: main
|
||||
resolved-ref: d4b9d507d10f5d640156cacfd754f661f8c0f4c1
|
||||
url: "https://gitlab.com/veilid/flutter-chat-ui.git"
|
||||
source: git
|
||||
version: "1.6.14"
|
||||
flutter_form_builder:
|
||||
dependency: "direct main"
|
||||
@ -534,10 +576,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_native_splash
|
||||
sha256: edf39bcf4d74aca1eb2c1e43c3e445fd9f494013df7f0da752fefe72020eedc0
|
||||
sha256: aa06fec78de2190f3db4319dd60fdc8d12b2626e93ef9828633928c2dcaea840
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
version: "2.4.1"
|
||||
flutter_parsed_text:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -627,10 +669,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: freezed_annotation
|
||||
sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d
|
||||
sha256: f54946fdb1fa7b01f780841937b1a80783a20b393485f3f6cdf336fd6f4705f2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
version: "2.4.2"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -659,10 +701,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: go_router
|
||||
sha256: abec47eb8c8c36ebf41d0a4c64dbbe7f956e39a012b3aafc530e951bdc12fe3f
|
||||
sha256: cdae1b9c8bd7efadcef6112e81c903662ef2ce105cbd220a04bbb7c3425b5554
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.1.4"
|
||||
version: "14.2.0"
|
||||
graphs:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -931,10 +973,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: "9c96da072b421e98183f9ea7464898428e764bc0ce5567f27ec8693442e72514"
|
||||
sha256: bca87b0165ffd7cdb9cad8edd22d18d2201e886d9a9f19b4fb3452ea7df3a72a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.5"
|
||||
version: "2.2.6"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -967,6 +1009,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
pdf:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: pdf
|
||||
sha256: "81d5522bddc1ef5c28e8f0ee40b71708761753c163e0c93a40df56fd515ea0f0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.11.0"
|
||||
pdf_widget_wrapper:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pdf_widget_wrapper
|
||||
sha256: c930860d987213a3d58c7ec3b7ecf8085c3897f773e8dc23da9cae60a5d6d0f5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -995,10 +1053,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
|
||||
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.4"
|
||||
version: "3.1.5"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1031,6 +1089,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
printing:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: printing
|
||||
sha256: cc4b256a5a89d5345488e3318897b595867f5181b8c5ed6fc63bfa5f2044aec3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.13.1"
|
||||
protobuf:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1075,10 +1141,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: qr_code_dart_scan
|
||||
sha256: "948271f8dc39ab3798341783f0ab7bfdb723054fdc9ea0928c0a5be8503ee01c"
|
||||
sha256: "52912da40f5e40a197b890108af9d2a6baa0c5812b77bfb085c8ee9e3c4f1f52"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.0"
|
||||
version: "0.8.1"
|
||||
qr_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1135,6 +1201,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.9"
|
||||
screenshot:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: screenshot
|
||||
sha256: "63817697a7835e6ce82add4228e15d233b74d42975c143ad8cfe07009fab866b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
scroll_to_index:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1547,7 +1621,7 @@ packages:
|
||||
path: "../veilid/veilid-flutter"
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.3.2"
|
||||
version: "0.3.3"
|
||||
veilid_support:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
12
pubspec.yaml
12
pubspec.yaml
@ -28,6 +28,7 @@ dependencies:
|
||||
cupertino_icons: ^1.0.8
|
||||
equatable: ^2.0.5
|
||||
fast_immutable_collections: ^10.2.4
|
||||
file_saver: ^0.2.13
|
||||
fixnum: ^1.1.0
|
||||
flutter:
|
||||
sdk: flutter
|
||||
@ -63,8 +64,10 @@ dependencies:
|
||||
pasteboard: ^0.2.0
|
||||
path: ^1.9.0
|
||||
path_provider: ^2.1.3
|
||||
pdf: ^3.11.0
|
||||
pinput: ^4.0.0
|
||||
preload_page_view: ^0.2.0
|
||||
printing: ^5.13.1
|
||||
protobuf: ^3.1.0
|
||||
provider: ^6.1.2
|
||||
qr_code_dart_scan: ^0.8.0
|
||||
@ -72,6 +75,7 @@ dependencies:
|
||||
quickalert: ^1.1.0
|
||||
radix_colors: ^1.0.4
|
||||
reorderable_grid: ^1.0.10
|
||||
screenshot: ^3.0.0
|
||||
scroll_to_index: ^3.0.1
|
||||
searchable_listview: ^2.14.0
|
||||
share_plus: ^9.0.0
|
||||
@ -95,13 +99,13 @@ dependencies:
|
||||
xterm: ^4.0.0
|
||||
zxing2: ^0.2.3
|
||||
|
||||
dependency_overrides:
|
||||
# dependency_overrides:
|
||||
# async_tools:
|
||||
# path: ../dart_async_tools
|
||||
# bloc_advanced_tools:
|
||||
# path: ../bloc_advanced_tools
|
||||
flutter_chat_ui:
|
||||
path: ../flutter_chat_ui
|
||||
# flutter_chat_ui:
|
||||
# path: ../flutter_chat_ui
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: ^2.4.11
|
||||
@ -146,6 +150,8 @@ flutter:
|
||||
- assets/images/title.svg
|
||||
- assets/images/vlogo.svg
|
||||
- assets/images/ellet.png
|
||||
# Printing
|
||||
- assets/js/pdf/3.2.146/pdf.min.js
|
||||
# Fonts
|
||||
fonts:
|
||||
- family: Source Code Pro
|
||||
|
@ -56,7 +56,10 @@
|
||||
}
|
||||
run();
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var dartPdfJsBaseUrl = "assets/js/pdf/3.2.146/";
|
||||
|
||||
window.addEventListener('load', function (ev) {
|
||||
// Download main.dart.js
|
||||
_flutter.loader.loadEntrypoint({
|
||||
@ -72,4 +75,4 @@
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
@ -6,7 +6,9 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <file_saver/file_saver_plugin.h>
|
||||
#include <pasteboard/pasteboard_plugin.h>
|
||||
#include <printing/printing_plugin.h>
|
||||
#include <screen_retriever/screen_retriever_plugin.h>
|
||||
#include <share_plus/share_plus_windows_plugin_c_api.h>
|
||||
#include <smart_auth/smart_auth_plugin.h>
|
||||
@ -15,8 +17,12 @@
|
||||
#include <window_manager/window_manager_plugin.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
FileSaverPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSaverPlugin"));
|
||||
PasteboardPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("PasteboardPlugin"));
|
||||
PrintingPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("PrintingPlugin"));
|
||||
ScreenRetrieverPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("ScreenRetrieverPlugin"));
|
||||
SharePlusWindowsPluginCApiRegisterWithRegistrar(
|
||||
|
@ -3,7 +3,9 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
file_saver
|
||||
pasteboard
|
||||
printing
|
||||
screen_retriever
|
||||
share_plus
|
||||
smart_auth
|
||||
|
Loading…
Reference in New Issue
Block a user