mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2025-05-09 17:55:13 -04:00
refactor some more
This commit is contained in:
parent
2adc958128
commit
c516323e7d
91 changed files with 1237 additions and 748 deletions
|
@ -1,13 +1,13 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:signal_strength_indicator/signal_strength_indicator.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:veilid_support/veilid_support.dart';
|
||||
|
||||
import '../providers/connection_state.dart';
|
||||
import '../tools/tools.dart';
|
||||
import '../veilid_support/veilid_support.dart';
|
||||
|
||||
class SignalStrengthMeterWidget extends ConsumerWidget {
|
||||
xxx move to feature level
|
||||
|
||||
class SignalStrengthMeterWidget extends Widget {
|
||||
const SignalStrengthMeterWidget({super.key});
|
||||
|
||||
@override
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'preferences.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$LockPreferenceImpl _$$LockPreferenceImplFromJson(Map<String, dynamic> json) =>
|
||||
_$LockPreferenceImpl(
|
||||
inactivityLockSecs: json['inactivity_lock_secs'] as int,
|
||||
lockWhenSwitching: json['lock_when_switching'] as bool,
|
||||
lockWithSystemLock: json['lock_with_system_lock'] as bool,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$LockPreferenceImplToJson(
|
||||
_$LockPreferenceImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'inactivity_lock_secs': instance.inactivityLockSecs,
|
||||
'lock_when_switching': instance.lockWhenSwitching,
|
||||
'lock_with_system_lock': instance.lockWithSystemLock,
|
||||
};
|
||||
|
||||
_$ThemePreferencesImpl _$$ThemePreferencesImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$ThemePreferencesImpl(
|
||||
brightnessPreference:
|
||||
BrightnessPreference.fromJson(json['brightness_preference']),
|
||||
colorPreference: ColorPreference.fromJson(json['color_preference']),
|
||||
displayScale: (json['display_scale'] as num).toDouble(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ThemePreferencesImplToJson(
|
||||
_$ThemePreferencesImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'brightness_preference': instance.brightnessPreference.toJson(),
|
||||
'color_preference': instance.colorPreference.toJson(),
|
||||
'display_scale': instance.displayScale,
|
||||
};
|
||||
|
||||
_$PreferencesImpl _$$PreferencesImplFromJson(Map<String, dynamic> json) =>
|
||||
_$PreferencesImpl(
|
||||
themePreferences: ThemePreferences.fromJson(json['theme_preferences']),
|
||||
language: LanguagePreference.fromJson(json['language']),
|
||||
locking: LockPreference.fromJson(json['locking']),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$PreferencesImplToJson(_$PreferencesImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'theme_preferences': instance.themePreferences.toJson(),
|
||||
'language': instance.language.toJson(),
|
||||
'locking': instance.locking.toJson(),
|
||||
};
|
|
@ -14,7 +14,7 @@ import 'package:quickalert/quickalert.dart';
|
|||
import 'package:xterm/xterm.dart';
|
||||
|
||||
import '../../tools/tools.dart';
|
||||
import '../../veilid_support/veilid_support.dart';
|
||||
import '../../../packages/veilid_support/veilid_support.dart';
|
||||
|
||||
final globalDebugTerminal = Terminal(
|
||||
maxLines: 50000,
|
||||
|
|
|
@ -18,7 +18,7 @@ import '../../local_accounts/local_accounts.dart';
|
|||
import '../providers/logins.dart';
|
||||
import '../providers/window_control.dart';
|
||||
import '../../tools/tools.dart';
|
||||
import '../../veilid_support/veilid_support.dart';
|
||||
import '../../../packages/veilid_support/veilid_support.dart';
|
||||
import 'main_pager/main_pager.dart';
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
|
|
|
@ -15,7 +15,7 @@ import '../../providers/contact.dart';
|
|||
import '../../providers/contact_invite.dart';
|
||||
import '../../../theme/theme.dart';
|
||||
import '../../../tools/tools.dart';
|
||||
import '../../../veilid_support/veilid_support.dart';
|
||||
import '../../../../packages/veilid_support/veilid_support.dart';
|
||||
|
||||
class AccountPage extends ConsumerStatefulWidget {
|
||||
const AccountPage({
|
||||
|
|
|
@ -13,7 +13,7 @@ import '../../providers/contact.dart';
|
|||
import '../../../local_accounts/local_accounts.dart';
|
||||
import '../../providers/logins.dart';
|
||||
import '../../../tools/tools.dart';
|
||||
import '../../../veilid_support/veilid_support.dart';
|
||||
import '../../../../packages/veilid_support/veilid_support.dart';
|
||||
|
||||
class ChatsPage extends ConsumerStatefulWidget {
|
||||
const ChatsPage({super.key});
|
||||
|
|
|
@ -20,7 +20,7 @@ import '../../../components/send_invite_dialog.dart';
|
|||
import '../../../entities/local_account.dart';
|
||||
import '../../../proto/proto.dart' as proto;
|
||||
import '../../../tools/tools.dart';
|
||||
import '../../../veilid_support/veilid_support.dart';
|
||||
import '../../../../packages/veilid_support/veilid_support.dart';
|
||||
import 'account.dart';
|
||||
import 'chats.dart';
|
||||
|
||||
|
|
|
@ -1,175 +0,0 @@
|
|||
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_translate/flutter_translate.dart';
|
||||
import 'package:form_builder_validators/form_builder_validators.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../components/default_app_bar.dart';
|
||||
import '../../components/signal_strength_meter.dart';
|
||||
import '../../entities/entities.dart';
|
||||
import '../../local_accounts/local_accounts.dart';
|
||||
import '../providers/logins.dart';
|
||||
import '../providers/window_control.dart';
|
||||
import '../../tools/tools.dart';
|
||||
import '../../veilid_support/veilid_support.dart';
|
||||
|
||||
class NewAccountPage extends StatefulWidget {
|
||||
const NewAccountPage({super.key});
|
||||
|
||||
@override
|
||||
NewAccountPageState createState() => NewAccountPageState();
|
||||
}
|
||||
|
||||
class NewAccountPageState extends ConsumerState<NewAccountPage> {
|
||||
final _formKey = GlobalKey<FormBuilderState>();
|
||||
late bool isInAsyncCall = false;
|
||||
static const String formFieldName = 'name';
|
||||
static const String formFieldPronouns = 'pronouns';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
setState(() {});
|
||||
await ref.read(windowControlProvider.notifier).changeWindowSetup(
|
||||
TitleBarStyle.normal, OrientationCapability.portraitOnly);
|
||||
});
|
||||
}
|
||||
|
||||
/// Creates a new master identity, an account associated with the master
|
||||
/// identity, stores the account in the identity key and then logs into
|
||||
/// that account with no password set at this time
|
||||
Future<void> createAccount() async {
|
||||
final localAccounts = ref.read(localAccountsProvider.notifier);
|
||||
final logins = ref.read(loginsProvider.notifier);
|
||||
|
||||
final name = _formKey.currentState!.fields[formFieldName]!.value as String;
|
||||
final pronouns =
|
||||
_formKey.currentState!.fields[formFieldPronouns]!.value as String? ??
|
||||
'';
|
||||
|
||||
final imws = await IdentityMasterWithSecrets.create();
|
||||
try {
|
||||
final localAccount = await localAccounts.newLocalAccount(
|
||||
identityMaster: imws.identityMaster,
|
||||
identitySecret: imws.identitySecret,
|
||||
name: name,
|
||||
pronouns: pronouns);
|
||||
|
||||
// Log in the new account by default with no pin
|
||||
final ok = await logins.login(localAccount.identityMaster.masterRecordKey,
|
||||
EncryptionKeyType.none, '');
|
||||
assert(ok, 'login with none should never fail');
|
||||
} on Exception catch (_) {
|
||||
await imws.delete();
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Widget _newAccountForm(BuildContext context,
|
||||
{required Future<void> Function(GlobalKey<FormBuilderState>)
|
||||
onSubmit}) =>
|
||||
FormBuilder(
|
||||
key: _formKey,
|
||||
child: ListView(
|
||||
children: [
|
||||
Text(translate('new_account_page.header'))
|
||||
.textStyle(context.headlineSmall)
|
||||
.paddingSymmetric(vertical: 16),
|
||||
FormBuilderTextField(
|
||||
autofocus: true,
|
||||
name: formFieldName,
|
||||
decoration:
|
||||
InputDecoration(labelText: translate('account.form_name')),
|
||||
maxLength: 64,
|
||||
// The validator receives the text that the user has entered.
|
||||
validator: FormBuilderValidators.compose([
|
||||
FormBuilderValidators.required(),
|
||||
]),
|
||||
),
|
||||
FormBuilderTextField(
|
||||
name: formFieldPronouns,
|
||||
maxLength: 64,
|
||||
decoration: InputDecoration(
|
||||
labelText: translate('account.form_pronouns')),
|
||||
),
|
||||
Row(children: [
|
||||
const Spacer(),
|
||||
Text(translate('new_account_page.instructions'))
|
||||
.toCenter()
|
||||
.flexible(flex: 6),
|
||||
const Spacer(),
|
||||
]).paddingSymmetric(vertical: 4),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
if (_formKey.currentState?.saveAndValidate() ?? false) {
|
||||
setState(() {
|
||||
isInAsyncCall = true;
|
||||
});
|
||||
try {
|
||||
await onSubmit(_formKey);
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
isInAsyncCall = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
child: Text(translate('new_account_page.create')),
|
||||
).paddingSymmetric(vertical: 4).alignAtCenterRight(),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
ref.watch(windowControlProvider);
|
||||
|
||||
final localAccounts = ref.watch(localAccountsProvider);
|
||||
final logins = ref.watch(loginsProvider);
|
||||
|
||||
final displayModalHUD =
|
||||
isInAsyncCall || !localAccounts.hasValue || !logins.hasValue;
|
||||
|
||||
return Scaffold(
|
||||
// resizeToAvoidBottomInset: false,
|
||||
appBar: DefaultAppBar(
|
||||
title: Text(translate('new_account_page.titlebar')),
|
||||
actions: [
|
||||
const SignalStrengthMeterWidget(),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.settings),
|
||||
tooltip: translate('app_bar.settings_tooltip'),
|
||||
onPressed: () async {
|
||||
context.go('/new_account/settings');
|
||||
})
|
||||
]),
|
||||
body: _newAccountForm(
|
||||
context,
|
||||
onSubmit: (formKey) async {
|
||||
FocusScope.of(context).unfocus();
|
||||
try {
|
||||
await createAccount();
|
||||
} on Exception catch (e) {
|
||||
if (context.mounted) {
|
||||
await showErrorModal(context, translate('new_account_page.error'),
|
||||
'Exception: $e');
|
||||
}
|
||||
}
|
||||
},
|
||||
).paddingSymmetric(horizontal: 24, vertical: 8),
|
||||
).withModalHUD(context, displayModalHUD);
|
||||
}
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties.add(DiagnosticsProperty<bool>('isInAsyncCall', isInAsyncCall));
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|||
import '../../entities/local_account.dart';
|
||||
import '../../entities/user_login.dart';
|
||||
import '../../proto/proto.dart' as proto;
|
||||
import '../../veilid_support/veilid_support.dart';
|
||||
import '../../../packages/veilid_support/veilid_support.dart';
|
||||
import '../../local_accounts/local_accounts.dart';
|
||||
import 'logins.dart';
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|||
|
||||
import '../../proto/proto.dart' as proto;
|
||||
|
||||
import '../../veilid_support/veilid_support.dart';
|
||||
import '../../../packages/veilid_support/veilid_support.dart';
|
||||
import 'account.dart';
|
||||
|
||||
part 'chat.g.dart';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
import '../../veilid_support/veilid_support.dart';
|
||||
import '../../../packages/veilid_support/veilid_support.dart';
|
||||
|
||||
part 'connection_state.freezed.dart';
|
||||
|
||||
|
|
|
@ -30,8 +30,6 @@ abstract class $ConnectionStateCopyWith<$Res> {
|
|||
_$ConnectionStateCopyWithImpl<$Res, ConnectionState>;
|
||||
@useResult
|
||||
$Res call({VeilidStateAttachment attachment});
|
||||
|
||||
$VeilidStateAttachmentCopyWith<$Res> get attachment;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
@ -47,23 +45,15 @@ class _$ConnectionStateCopyWithImpl<$Res, $Val extends ConnectionState>
|
|||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? attachment = null,
|
||||
Object? attachment = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
attachment: null == attachment
|
||||
attachment: freezed == attachment
|
||||
? _value.attachment
|
||||
: attachment // ignore: cast_nullable_to_non_nullable
|
||||
as VeilidStateAttachment,
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$VeilidStateAttachmentCopyWith<$Res> get attachment {
|
||||
return $VeilidStateAttachmentCopyWith<$Res>(_value.attachment, (value) {
|
||||
return _then(_value.copyWith(attachment: value) as $Val);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
@ -75,9 +65,6 @@ abstract class _$$ConnectionStateImplCopyWith<$Res>
|
|||
@override
|
||||
@useResult
|
||||
$Res call({VeilidStateAttachment attachment});
|
||||
|
||||
@override
|
||||
$VeilidStateAttachmentCopyWith<$Res> get attachment;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
@ -91,10 +78,10 @@ class __$$ConnectionStateImplCopyWithImpl<$Res>
|
|||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? attachment = null,
|
||||
Object? attachment = freezed,
|
||||
}) {
|
||||
return _then(_$ConnectionStateImpl(
|
||||
attachment: null == attachment
|
||||
attachment: freezed == attachment
|
||||
? _value.attachment
|
||||
: attachment // ignore: cast_nullable_to_non_nullable
|
||||
as VeilidStateAttachment,
|
||||
|
@ -120,12 +107,13 @@ class _$ConnectionStateImpl extends _ConnectionState {
|
|||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ConnectionStateImpl &&
|
||||
(identical(other.attachment, attachment) ||
|
||||
other.attachment == attachment));
|
||||
const DeepCollectionEquality()
|
||||
.equals(other.attachment, attachment));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, attachment);
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, const DeepCollectionEquality().hash(attachment));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
|
|
|
@ -5,7 +5,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|||
|
||||
import '../../proto/proto.dart' as proto;
|
||||
|
||||
import '../../veilid_support/veilid_support.dart';
|
||||
import '../../../packages/veilid_support/veilid_support.dart';
|
||||
import '../../tools/tools.dart';
|
||||
import 'account.dart';
|
||||
import 'chat.dart';
|
||||
|
|
|
@ -7,7 +7,7 @@ import 'package:mutex/mutex.dart';
|
|||
import '../../entities/entities.dart';
|
||||
import '../../proto/proto.dart' as proto;
|
||||
import '../../tools/tools.dart';
|
||||
import '../../veilid_support/veilid_support.dart';
|
||||
import '../../../packages/veilid_support/veilid_support.dart';
|
||||
import 'account.dart';
|
||||
|
||||
part 'contact_invitation_list_manager.g.dart';
|
||||
|
@ -115,11 +115,11 @@ class ContactInvitationListManager extends _$ContactInvitationListManager {
|
|||
final conversationWriter = _activeAccountInfo.getConversationWriter();
|
||||
|
||||
// Encrypt the writer secret with the encryption key
|
||||
final encryptedSecret = await encryptSecretToBytes(
|
||||
final encryptedSecret = await encryptionKeyType.encryptSecretToBytes(
|
||||
secret: contactRequestWriter.secret,
|
||||
cryptoKind: cs.kind(),
|
||||
encryptionKey: encryptionKey,
|
||||
encryptionKeyType: encryptionKeyType);
|
||||
);
|
||||
|
||||
// Create local chat DHT record with the account record key as its parent
|
||||
// Do not set the encryption of this key yet as it will not yet be written
|
||||
|
|
|
@ -7,7 +7,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|||
import '../../entities/local_account.dart';
|
||||
import '../../proto/proto.dart' as proto;
|
||||
import '../../tools/tools.dart';
|
||||
import '../../veilid_support/veilid_support.dart';
|
||||
import '../../../packages/veilid_support/veilid_support.dart';
|
||||
import 'account.dart';
|
||||
import 'conversation.dart';
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import '../../proto/proto.dart' as proto;
|
|||
|
||||
import '../../tools/tools.dart';
|
||||
import '../../init.dart';
|
||||
import '../../veilid_support/veilid_support.dart';
|
||||
import '../../../packages/veilid_support/veilid_support.dart';
|
||||
import 'account.dart';
|
||||
import 'chat.dart';
|
||||
import 'contact.dart';
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
import '../../tools/responsive.dart';
|
||||
|
||||
export 'package:window_manager/window_manager.dart' show TitleBarStyle;
|
||||
|
||||
part 'window_control.g.dart';
|
||||
|
||||
enum OrientationCapability {
|
||||
normal,
|
||||
portraitOnly,
|
||||
landscapeOnly,
|
||||
}
|
||||
|
||||
// Window Control
|
||||
@riverpod
|
||||
class WindowControl extends _$WindowControl {
|
||||
/// Change window control
|
||||
@override
|
||||
FutureOr<bool> build() async {
|
||||
await _doWindowSetup(TitleBarStyle.hidden, OrientationCapability.normal);
|
||||
return true;
|
||||
}
|
||||
|
||||
static Future<void> initialize() async {
|
||||
if (isDesktop) {
|
||||
await windowManager.ensureInitialized();
|
||||
|
||||
const windowOptions = WindowOptions(
|
||||
size: Size(768, 1024),
|
||||
//minimumSize: Size(480, 480),
|
||||
center: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
skipTaskbar: false,
|
||||
);
|
||||
await windowManager.waitUntilReadyToShow(windowOptions, () async {
|
||||
await windowManager.show();
|
||||
await windowManager.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _doWindowSetup(TitleBarStyle titleBarStyle,
|
||||
OrientationCapability orientationCapability) async {
|
||||
if (isDesktop) {
|
||||
await windowManager.setTitleBarStyle(titleBarStyle);
|
||||
} else {
|
||||
switch (orientationCapability) {
|
||||
case OrientationCapability.normal:
|
||||
await SystemChrome.setPreferredOrientations([
|
||||
DeviceOrientation.portraitUp,
|
||||
DeviceOrientation.landscapeLeft,
|
||||
DeviceOrientation.landscapeRight,
|
||||
]);
|
||||
case OrientationCapability.portraitOnly:
|
||||
await SystemChrome.setPreferredOrientations([
|
||||
DeviceOrientation.portraitUp,
|
||||
]);
|
||||
case OrientationCapability.landscapeOnly:
|
||||
await SystemChrome.setPreferredOrientations([
|
||||
DeviceOrientation.landscapeLeft,
|
||||
DeviceOrientation.landscapeRight,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
/// Mutators and Selectors
|
||||
|
||||
/// Reorder accounts
|
||||
Future<void> changeWindowSetup(TitleBarStyle titleBarStyle,
|
||||
OrientationCapability orientationCapability) async {
|
||||
state = const AsyncValue.loading();
|
||||
await _doWindowSetup(titleBarStyle, orientationCapability);
|
||||
state = const AsyncValue.data(true);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue