mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-17 06:12:31 -06:00
fix: Add custom fields, translations, add app logs to login routes
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {}),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user