fix: Add custom fields, translations, add app logs to login routes

This commit is contained in:
Anton Stubenbord
2023-12-10 12:48:32 +01:00
parent 5e5e5d2df3
commit 9f6b95f506
102 changed files with 2399 additions and 1088 deletions

View File

@@ -7,7 +7,8 @@ import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:paperless_mobile/core/extensions/flutter_extensions.dart';
import 'package:paperless_mobile/features/login/model/client_certificate_form_model.dart';
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
import 'package:paperless_mobile/helpers/message_helpers.dart';
import 'package:path/path.dart' as p;
import 'obscured_input_text_form_field.dart';
class ClientCertificateFormField extends StatefulWidget {
@@ -16,10 +17,10 @@ class ClientCertificateFormField extends StatefulWidget {
final String? initialPassphrase;
final Uint8List? initialBytes;
final void Function(ClientCertificateFormModel? cert) onChanged;
final ValueChanged<ClientCertificateFormModel?>? onChanged;
const ClientCertificateFormField({
super.key,
required this.onChanged,
this.onChanged,
this.initialPassphrase,
this.initialBytes,
});
@@ -29,13 +30,15 @@ class ClientCertificateFormField extends StatefulWidget {
_ClientCertificateFormFieldState();
}
class _ClientCertificateFormFieldState
extends State<ClientCertificateFormField> {
class _ClientCertificateFormFieldState extends State<ClientCertificateFormField>
with AutomaticKeepAliveClientMixin {
File? _selectedFile;
@override
Widget build(BuildContext context) {
super.build(context);
return FormBuilderField<ClientCertificateFormModel?>(
key: const ValueKey('login-client-cert'),
name: ClientCertificateFormField.fkClientCertificate,
onChanged: widget.onChanged,
initialValue: widget.initialBytes != null
? ClientCertificateFormModel(
@@ -43,16 +46,6 @@ class _ClientCertificateFormFieldState
passphrase: widget.initialPassphrase,
)
: null,
validator: (value) {
if (value == null) {
return null;
}
assert(_selectedFile != null);
if (_selectedFile?.path.split(".").last != 'pfx') {
return S.of(context)!.invalidCertificateFormat;
}
return null;
},
builder: (field) {
final theme =
Theme.of(context).copyWith(dividerColor: Colors.transparent); //new
@@ -127,7 +120,6 @@ class _ClientCertificateFormFieldState
),
);
},
name: ClientCertificateFormField.fkClientCertificate,
);
}
@@ -140,6 +132,11 @@ class _ClientCertificateFormFieldState
if (result == null || result.files.single.path == null) {
return;
}
final path = result.files.single.path!;
if (p.extension(path) != '.pfx') {
showSnackBar(context, S.of(context)!.invalidCertificateFormat);
return;
}
File file = File(result.files.single.path!);
setState(() {
_selectedFile = file;
@@ -171,4 +168,7 @@ class _ClientCertificateFormFieldState
);
}
}
@override
bool get wantKeepAlive => true;
}

View File

@@ -0,0 +1,22 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:paperless_mobile/features/login/view/widgets/form_fields/client_certificate_form_field.dart';
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
class LoginSettingsPage extends StatelessWidget {
const LoginSettingsPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(S.of(context)!.settings),
),
body: ListView(
children: [
ClientCertificateFormField(onChanged: (certificate) {}),
],
),
);
}
}

View File

@@ -9,10 +9,11 @@ import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
class ServerAddressFormField extends StatefulWidget {
static const String fkServerAddress = "serverAddress";
final String? initialValue;
final void Function(String? address) onSubmit;
final ValueChanged<String?>? onChanged;
const ServerAddressFormField({
Key? key,
required this.onSubmit,
this.onChanged,
this.initialValue,
}) : super(key: key);
@@ -20,8 +21,10 @@ class ServerAddressFormField extends StatefulWidget {
State<ServerAddressFormField> createState() => _ServerAddressFormFieldState();
}
class _ServerAddressFormFieldState extends State<ServerAddressFormField> {
class _ServerAddressFormFieldState extends State<ServerAddressFormField>
with AutomaticKeepAliveClientMixin {
bool _canClear = false;
final _textFieldKey = GlobalKey();
@override
void initState() {
@@ -38,10 +41,12 @@ class _ServerAddressFormFieldState extends State<ServerAddressFormField> {
@override
Widget build(BuildContext context) {
super.build(context);
return FormBuilderField<String>(
initialValue: widget.initialValue,
name: ServerAddressFormField.fkServerAddress,
autovalidateMode: AutovalidateMode.onUserInteraction,
onChanged: widget.onChanged,
builder: (field) {
return RawAutocomplete<String>(
focusNode: _focusNode,
@@ -51,6 +56,7 @@ class _ServerAddressFormFieldState extends State<ServerAddressFormField> {
onSelected: onSelected,
options: options,
maxOptionsHeight: 200.0,
maxWidth: MediaQuery.sizeOf(context).width - 40,
);
},
key: const ValueKey('login-server-address'),
@@ -60,12 +66,12 @@ class _ServerAddressFormFieldState extends State<ServerAddressFormField> {
.where((element) => element.contains(textEditingValue.text));
},
onSelected: (option) {
_formatInput();
field.didChange(_textEditingController.text);
_formatInput(field);
},
fieldViewBuilder:
(context, textEditingController, focusNode, onFieldSubmitted) {
return TextFormField(
key: _textFieldKey,
controller: textEditingController,
focusNode: focusNode,
decoration: InputDecoration(
@@ -78,15 +84,22 @@ class _ServerAddressFormFieldState extends State<ServerAddressFormField> {
onPressed: () {
textEditingController.clear();
field.didChange(textEditingController.text);
widget.onSubmit(textEditingController.text);
},
)
: null,
),
autofocus: false,
onFieldSubmitted: (_) {
_formatInput(field);
onFieldSubmitted();
_formatInput();
},
onTapOutside: (event) {
if (!FocusScope.of(context).hasFocus) {
return;
}
_formatInput(field);
onFieldSubmitted();
FocusScope.of(context).unfocus();
},
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (value) {
@@ -113,7 +126,7 @@ class _ServerAddressFormFieldState extends State<ServerAddressFormField> {
);
}
void _formatInput() {
void _formatInput(FormFieldState<String> field) {
String address = _textEditingController.text.trim();
address = address.replaceAll(RegExp(r'^\/+|\/+$'), '');
_textEditingController.text = address;
@@ -121,8 +134,11 @@ class _ServerAddressFormFieldState extends State<ServerAddressFormField> {
baseOffset: address.length,
extentOffset: address.length,
);
widget.onSubmit(address);
field.didChange(_textEditingController.text);
}
@override
bool get wantKeepAlive => true;
}
/// Taken from [Autocomplete]
@@ -131,12 +147,14 @@ class _AutocompleteOptions extends StatelessWidget {
required this.onSelected,
required this.options,
required this.maxOptionsHeight,
required this.maxWidth,
});
final AutocompleteOnSelected<String> onSelected;
final Iterable<String> options;
final double maxOptionsHeight;
final double maxWidth;
@override
Widget build(BuildContext context) {
@@ -145,7 +163,10 @@ class _AutocompleteOptions extends StatelessWidget {
child: Material(
elevation: 4.0,
child: ConstrainedBox(
constraints: BoxConstraints(maxHeight: maxOptionsHeight),
constraints: BoxConstraints(
maxHeight: maxOptionsHeight,
maxWidth: maxWidth,
),
child: ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,

View File

@@ -12,13 +12,13 @@ import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
class UserCredentialsFormField extends StatefulWidget {
static const fkCredentials = 'credentials';
final void Function() onFieldsSubmitted;
final VoidCallback? onFieldsSubmitted;
final String? initialUsername;
final String? initialPassword;
final GlobalKey<FormBuilderState> formKey;
const UserCredentialsFormField({
Key? key,
required this.onFieldsSubmitted,
this.onFieldsSubmitted,
this.initialUsername,
this.initialPassword,
required this.formKey,
@@ -29,12 +29,14 @@ class UserCredentialsFormField extends StatefulWidget {
_UserCredentialsFormFieldState();
}
class _UserCredentialsFormFieldState extends State<UserCredentialsFormField> {
class _UserCredentialsFormFieldState extends State<UserCredentialsFormField>
with AutomaticKeepAliveClientMixin {
final _usernameFocusNode = FocusNode();
final _passwordFocusNode = FocusNode();
@override
Widget build(BuildContext context) {
super.build(context);
return FormBuilderField<LoginFormCredentials?>(
initialValue: LoginFormCredentials(
password: widget.initialPassword,
@@ -87,7 +89,7 @@ class _UserCredentialsFormFieldState extends State<UserCredentialsFormField> {
LoginFormCredentials(password: password),
),
onFieldSubmitted: (_) {
widget.onFieldsSubmitted();
widget.onFieldsSubmitted?.call();
},
validator: (value) {
if (value?.trim().isEmpty ?? true) {
@@ -100,6 +102,9 @@ class _UserCredentialsFormFieldState extends State<UserCredentialsFormField> {
),
);
}
@override
bool get wantKeepAlive => true;
}
/**