Initial commit

This commit is contained in:
Anton Stubenbord
2022-10-30 14:15:37 +01:00
commit cb797df7d2
272 changed files with 16278 additions and 0 deletions

View File

@@ -0,0 +1,116 @@
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_paperless_mobile/extensions/flutter_extensions.dart';
import 'package:flutter_paperless_mobile/features/login/model/client_certificate.dart';
import 'package:flutter_paperless_mobile/features/login/view/widgets/password_text_field.dart';
import 'package:flutter_paperless_mobile/generated/l10n.dart';
class ClientCertificateFormField extends StatefulWidget {
static const fkClientCertificate = 'clientCertificate';
const ClientCertificateFormField({Key? key}) : super(key: key);
@override
State<ClientCertificateFormField> createState() => _ClientCertificateFormFieldState();
}
class _ClientCertificateFormFieldState extends State<ClientCertificateFormField> {
File? _selectedFile;
@override
Widget build(BuildContext context) {
return FormBuilderField<ClientCertificate?>(
initialValue: null,
validator: (value) {
if (value == null) {
return null;
}
assert(_selectedFile != null);
if (_selectedFile?.path.split(".").last != 'pfx') {
return S.of(context).loginPageClientCertificateSettingInvalidFileFormatValidationText;
}
return null;
},
builder: (field) {
return ExpansionTile(
title: Text(S.of(context).loginPageClientCertificateSettingLabel),
subtitle: Text(S.of(context).loginPageClientCertificateSettingDescriptionText),
children: [
InputDecorator(
decoration: InputDecoration(
errorText: field.errorText,
border: InputBorder.none,
),
child: Column(
children: [
ListTile(
leading: ElevatedButton(
onPressed: () => _onSelectFile(field),
child: Text(S.of(context).genericActionSelectText),
),
title: _buildSelectedFileText(field),
trailing: AbsorbPointer(
absorbing: field.value == null,
child: _selectedFile != null
? IconButton(
icon: const Icon(Icons.close),
onPressed: () => setState(() {
_selectedFile = null;
field.didChange(null);
}),
)
: null,
),
),
if (_selectedFile != null) ...[
ObscuredInputTextFormField(
initialValue: field.value?.passphrase,
onChanged: (value) => field.didChange(
field.value?.copyWith(passphrase: value),
),
label: S.of(context).loginPageClientCertificatePassphraseLabel,
).padded(),
] else
...[]
],
),
),
],
);
},
name: ClientCertificateFormField.fkClientCertificate,
);
}
Future<void> _onSelectFile(FormFieldState<ClientCertificate?> field) async {
FilePickerResult? result = await FilePicker.platform.pickFiles();
if (result != null && result.files.single.path != null) {
File file = File(result.files.single.path!);
setState(() {
_selectedFile = file;
});
final changedValue = field.value?.copyWith(bytes: file.readAsBytesSync()) ??
ClientCertificate(bytes: file.readAsBytesSync());
field.didChange(changedValue);
}
}
Widget _buildSelectedFileText(FormFieldState<ClientCertificate?> field) {
if (field.value == null) {
assert(_selectedFile == null);
return Text(
S.of(context).loginPageClientCertificateSettingSelectFileText,
style: TextStyle(color: Theme.of(context).hintColor),
);
} else {
assert(_selectedFile != null);
return Text(
_selectedFile!.path.split("/").last,
style: const TextStyle(
overflow: TextOverflow.ellipsis,
),
);
}
}
}

View File

@@ -0,0 +1,53 @@
import 'package:flutter/material.dart';
class ObscuredInputTextFormField extends StatefulWidget {
final String? initialValue;
final String label;
final void Function(String?) onChanged;
final FormFieldValidator<String>? validator;
const ObscuredInputTextFormField({
super.key,
required this.onChanged,
required this.label,
this.validator,
this.initialValue,
});
@override
State<ObscuredInputTextFormField> createState() => _ObscuredInputTextFormFieldState();
}
class _ObscuredInputTextFormFieldState extends State<ObscuredInputTextFormField> {
bool _showPassword = false;
final FocusNode _passwordFocusNode = FocusNode();
@override
void dispose() {
_passwordFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return TextFormField(
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: widget.validator,
initialValue: widget.initialValue,
focusNode: _passwordFocusNode,
obscureText: !_showPassword,
autocorrect: false,
onChanged: widget.onChanged,
autofillHints: const [AutofillHints.password],
decoration: InputDecoration(
label: Text(widget.label),
suffixIcon: IconButton(
icon: Icon(_showPassword ? Icons.visibility_off : Icons.visibility),
onPressed: () => setState(() {
_showPassword = !_showPassword;
}),
),
),
);
}
}

View File

@@ -0,0 +1,74 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_paperless_mobile/core/service/connectivity_status.service.dart';
import 'package:flutter_paperless_mobile/di_initializer.dart';
import 'package:flutter_paperless_mobile/generated/l10n.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
class ServerAddressFormField extends StatefulWidget {
static const String fkServerAddress = "serverAddress";
const ServerAddressFormField({
Key? key,
}) : super(key: key);
@override
State<ServerAddressFormField> createState() => _ServerAddressFormFieldState();
}
class _ServerAddressFormFieldState extends State<ServerAddressFormField> {
ReachabilityStatus _reachabilityStatus = ReachabilityStatus.undefined;
@override
Widget build(BuildContext context) {
return FormBuilderTextField(
name: ServerAddressFormField.fkServerAddress,
validator: FormBuilderValidators.required(
errorText: S.of(context).loginPageServerUrlValidatorMessageText,
),
decoration: InputDecoration(
suffixIcon: _buildIsReachableIcon(),
hintText: "http://192.168.1.50:8000",
labelText: S.of(context).loginPageServerUrlFieldLabel,
),
onSubmitted: _updateIsAddressReachableStatus,
);
}
Widget? _buildIsReachableIcon() {
switch (_reachabilityStatus) {
case ReachabilityStatus.reachable:
return const Icon(
Icons.done,
color: Colors.green,
);
case ReachabilityStatus.notReachable:
return Icon(
Icons.close,
color: Theme.of(context).colorScheme.error,
);
case ReachabilityStatus.testing:
return const RefreshProgressIndicator();
case ReachabilityStatus.undefined:
return null;
}
}
void _updateIsAddressReachableStatus(String? address) async {
if (address == null || address.isEmpty) {
setState(() {
_reachabilityStatus = ReachabilityStatus.undefined;
});
return;
}
//https://stackoverflow.com/questions/49648022/check-whether-there-is-an-internet-connection-available-on-flutter-app
setState(() => _reachabilityStatus = ReachabilityStatus.testing);
final isReachable = await getIt<ConnectivityStatusService>().isServerReachable(address);
if (isReachable) {
setState(() => _reachabilityStatus = ReachabilityStatus.reachable);
} else {
setState(() => _reachabilityStatus = ReachabilityStatus.notReachable);
}
}
}
enum ReachabilityStatus { reachable, notReachable, testing, undefined }

View File

@@ -0,0 +1,96 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_paperless_mobile/extensions/flutter_extensions.dart';
import 'package:flutter_paperless_mobile/features/login/model/user_credentials.model.dart';
import 'package:flutter_paperless_mobile/features/login/view/widgets/password_text_field.dart';
import 'package:flutter_paperless_mobile/generated/l10n.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
class UserCredentialsFormField extends StatefulWidget {
static const fkCredentials = 'credentials';
const UserCredentialsFormField({Key? key}) : super(key: key);
@override
State<UserCredentialsFormField> createState() =>
_UserCredentialsFormFieldState();
}
class _UserCredentialsFormFieldState extends State<UserCredentialsFormField> {
@override
Widget build(BuildContext context) {
return FormBuilderField<UserCredentials?>(
name: UserCredentialsFormField.fkCredentials,
builder: (field) => AutofillGroup(
child: Column(
children: [
TextFormField(
textCapitalization: TextCapitalization.words,
autovalidateMode: AutovalidateMode.onUserInteraction,
// USERNAME
autocorrect: false,
onChanged: (username) => field.didChange(
field.value?.copyWith(username: username) ??
UserCredentials(username: username),
),
validator: FormBuilderValidators.required(
errorText: S.of(context).loginPageUsernameValidatorMessageText,
),
autofillHints: const [AutofillHints.username],
decoration: InputDecoration(
label: Text(S.of(context).loginPageUsernameLabel),
),
),
ObscuredInputTextFormField(
label: S.of(context).loginPagePasswordFieldLabel,
onChanged: (password) => field.didChange(
field.value?.copyWith(password: password) ??
UserCredentials(password: password),
),
validator: FormBuilderValidators.required(
errorText: S.of(context).loginPagePasswordValidatorMessageText,
),
),
].map((child) => child.padded()).toList(),
),
),
);
}
}
/**
* AutofillGroup(
child: Column(
children: [
FormBuilderTextField(
name: fkUsername,
focusNode: _focusNodes[fkUsername],
onSubmitted: (_) {
FocusScope.of(context).requestFocus(_focusNodes[fkPassword]);
},
validator: FormBuilderValidators.required(
errorText: S.of(context).loginPageUsernameValidatorMessageText,
),
autofillHints: const [AutofillHints.username],
decoration: InputDecoration(
labelText: S.of(context).loginPageUsernameLabel,
),
).padded(),
FormBuilderTextField(
name: fkPassword,
focusNode: _focusNodes[fkPassword],
onSubmitted: (_) {
FocusScope.of(context).unfocus();
},
autofillHints: const [AutofillHints.password],
validator: FormBuilderValidators.required(
errorText: S.of(context).loginPagePasswordValidatorMessageText,
),
obscureText: true,
decoration: InputDecoration(
labelText: S.of(context).loginPagePasswordFieldLabel,
),
).padded(),
],
),
);
*/