Fixed bugs, added serialization for documents state

This commit is contained in:
Anton Stubenbord
2023-01-06 18:22:43 +01:00
parent 738ef99bc5
commit 23bcb355b1
76 changed files with 1333 additions and 595 deletions

View File

@@ -1,3 +1,4 @@
import 'package:dio/dio.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/security/authentication_aware_dio_manager.dart';
@@ -34,7 +35,6 @@ class AuthenticationCubit extends Cubit<AuthenticationState>
username: credentials.username!,
password: credentials.password!,
);
_dioWrapper.updateSettings(
baseUrl: serverUrl,
clientCertificate: clientCertificate,

View File

@@ -2,16 +2,17 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/type/types.dart';
import 'package:paperless_mobile/features/login/bloc/authentication_cubit.dart';
import 'package:paperless_mobile/features/login/view/widgets/client_certificate_form_field.dart';
import 'package:paperless_mobile/features/login/view/widgets/server_address_form_field.dart';
import 'package:paperless_mobile/features/login/view/widgets/server_connection_page.dart';
import 'package:paperless_mobile/features/login/view/widgets/user_credentials_form_field.dart';
import 'package:paperless_mobile/features/login/view/widgets/form_fields/client_certificate_form_field.dart';
import 'package:paperless_mobile/features/login/view/widgets/form_fields/server_address_form_field.dart';
import 'package:paperless_mobile/features/login/view/widgets/form_fields/user_credentials_form_field.dart';
import 'package:paperless_mobile/features/login/view/widgets/login_pages/server_connection_page.dart';
import 'package:paperless_mobile/generated/l10n.dart';
import 'package:paperless_mobile/util.dart';
import 'widgets/never_scrollable_scroll_behavior.dart';
import 'widgets/server_login_page.dart';
import 'widgets/login_pages/server_login_page.dart';
class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
@@ -29,14 +30,6 @@ class _LoginPageState extends State<LoginPage> {
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false, // appBar: AppBar(
// title: Text(S.of(context).loginPageTitle),
// bottom: _isLoginLoading
// ? const PreferredSize(
// preferredSize: Size(double.infinity, 4),
// child: LinearProgressIndicator(),
// )
// : null,
// ),
body: FormBuilder(
key: _formKey,
child: PageView(
@@ -47,8 +40,9 @@ class _LoginPageState extends State<LoginPage> {
formBuilderKey: _formKey,
onContinue: () {
_pageController.nextPage(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut);
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
},
),
ServerLoginPage(
@@ -58,58 +52,10 @@ class _LoginPageState extends State<LoginPage> {
],
),
),
// Padding(
// padding: const EdgeInsets.all(8.0),
// child: FormBuilder(
// key: _formKey,
// child: ListView(
// children: [
// const ServerAddressFormField().padded(),
// const UserCredentialsFormField(),
// Align(
// alignment: Alignment.centerLeft,
// child: Padding(
// padding: const EdgeInsets.only(top: 16.0),
// child: Text(
// S.of(context).loginPageAdvancedLabel,
// style: Theme.of(context).textTheme.bodyLarge,
// ).padded(),
// ),
// ),
// const ClientCertificateFormField(),
// LayoutBuilder(builder: (context, constraints) {
// return Padding(
// padding: const EdgeInsets.all(8.0),
// child: SizedBox(
// width: constraints.maxWidth,
// child: _buildLoginButton(),
// ),
// );
// }),
// ],
// ),
// ),
// ),
);
}
Widget _buildLoginButton() {
return ElevatedButton(
key: const ValueKey('login-login-button'),
style: ButtonStyle(
backgroundColor: MaterialStatePropertyAll(
Theme.of(context).colorScheme.primaryContainer,
),
elevation: const MaterialStatePropertyAll(0),
),
onPressed: _login,
child: Text(
S.of(context).loginPageLoginButtonLabel,
),
);
}
void _login() async {
Future<void> _login() async {
FocusScope.of(context).unfocus();
if (_formKey.currentState?.saveAndValidate() ?? false) {
final form = _formKey.currentState!.value;
@@ -122,11 +68,15 @@ class _LoginPageState extends State<LoginPage> {
);
} on PaperlessServerException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace);
} on Map<String, dynamic> catch (error, stackTrace) {
showGenericError(context, error.values.first, stackTrace);
} on PaperlessValidationErrors catch (error, stackTrace) {
if (error.hasFieldUnspecificError) {
showLocalizedError(context, error.fieldUnspecificError!);
} else {
showGenericError(context, error.values.first, stackTrace);
}
} catch (unknownError, stackTrace) {
showGenericError(context, unknownError.toString(), stackTrace);
} finally {}
}
}
}
}

View File

@@ -5,8 +5,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
import 'package:paperless_mobile/features/login/model/client_certificate.dart';
import 'package:paperless_mobile/features/login/view/widgets/password_text_field.dart';
import 'package:paperless_mobile/generated/l10n.dart';
import 'package:paperless_mobile/util.dart';
import 'package:permission_handler/permission_handler.dart';
import 'obscured_input_text_form_field.dart';
class ClientCertificateFormField extends StatefulWidget {
static const fkClientCertificate = 'clientCertificate';
@@ -24,7 +27,6 @@ class ClientCertificateFormField extends StatefulWidget {
class _ClientCertificateFormFieldState
extends State<ClientCertificateFormField> {
RestorableString? _selectedFilePath;
File? _selectedFile;
@override
Widget build(BuildContext context) {
@@ -105,7 +107,9 @@ class _ClientCertificateFormFieldState
}
Future<void> _onSelectFile(FormFieldState<ClientCertificate?> field) async {
FilePickerResult? result = await FilePicker.platform.pickFiles();
FilePickerResult? result = await FilePicker.platform.pickFiles(
allowMultiple: false,
);
if (result != null && result.files.single.path != null) {
File file = File(result.files.single.path!);
setState(() {

View File

@@ -1,10 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:paperless_mobile/core/service/connectivity_status_service.dart';
import 'package:paperless_mobile/features/login/model/client_certificate.dart';
import 'package:paperless_mobile/generated/l10n.dart';
import 'package:provider/provider.dart';
class ServerAddressFormField extends StatefulWidget {
static const String fkServerAddress = "serverAddress";

View File

@@ -3,7 +3,7 @@ import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
import 'package:paperless_mobile/features/login/model/user_credentials.model.dart';
import 'package:paperless_mobile/features/login/view/widgets/password_text_field.dart';
import 'package:paperless_mobile/features/login/view/widgets/form_fields/obscured_input_text_form_field.dart';
import 'package:paperless_mobile/generated/l10n.dart';
class UserCredentialsFormField extends StatefulWidget {

View File

@@ -4,8 +4,8 @@ import 'package:paperless_mobile/core/service/connectivity_status_service.dart';
import 'package:paperless_mobile/core/widgets/paperless_logo.dart';
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
import 'package:paperless_mobile/features/login/model/reachability_status.dart';
import 'package:paperless_mobile/features/login/view/widgets/client_certificate_form_field.dart';
import 'package:paperless_mobile/features/login/view/widgets/server_address_form_field.dart';
import 'package:paperless_mobile/features/login/view/widgets/form_fields/client_certificate_form_field.dart';
import 'package:paperless_mobile/features/login/view/widgets/form_fields/server_address_form_field.dart';
import 'package:paperless_mobile/generated/l10n.dart';
import 'package:provider/provider.dart';
@@ -28,7 +28,6 @@ class _ServerConnectionPageState extends State<ServerConnectionPage> {
@override
Widget build(BuildContext context) {
final logoHeight = MediaQuery.of(context).size.width / 2;
return Scaffold(
appBar: AppBar(
title: Text(S.of(context).loginPageTitle),
@@ -52,7 +51,7 @@ class _ServerConnectionPageState extends State<ServerConnectionPage> {
mainAxisAlignment: MainAxisAlignment.end,
children: [
FilledButton(
child: Text("Continue"),
child: Text(S.of(context).loginPageContinueLabel),
onPressed: _reachabilityStatus == ReachabilityStatus.reachable
? widget.onContinue
: null,
@@ -84,31 +83,33 @@ class _ServerConnectionPageState extends State<ServerConnectionPage> {
case ReachabilityStatus.reachable:
return _buildIconText(
Icons.done,
"Connection established.",
S.of(context).loginPageReachabilitySuccessText,
Colors.green,
);
case ReachabilityStatus.notReachable:
return _buildIconText(
Icons.close,
"Could not establish a connection to the server.",
S.of(context).loginPageReachabilityNotReachableText,
errorColor,
);
case ReachabilityStatus.unknownHost:
return _buildIconText(
Icons.close,
"Host could not be resolved.",
S.of(context).loginPageReachabilityUnresolvedHostText,
errorColor,
);
case ReachabilityStatus.missingClientCertificate:
return _buildIconText(
Icons.close,
"A client certificate was expected but not sent. Please provide a certificate.",
S.of(context).loginPageReachabilityMissingClientCertificateText,
errorColor,
);
case ReachabilityStatus.invalidClientCertificateConfiguration:
return _buildIconText(
Icons.close,
"Incorrect or missing client certificate passphrase.",
S
.of(context)
.loginPageReachabilityInvalidClientCertificateConfigurationText,
errorColor,
);
}

View File

@@ -0,0 +1,64 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
import 'package:paperless_mobile/features/login/view/widgets/form_fields/server_address_form_field.dart';
import 'package:paperless_mobile/features/login/view/widgets/form_fields/user_credentials_form_field.dart';
import 'package:paperless_mobile/generated/l10n.dart';
class ServerLoginPage extends StatefulWidget {
final Future<void> Function() onDone;
final GlobalKey<FormBuilderState> formBuilderKey;
const ServerLoginPage({
super.key,
required this.onDone,
required this.formBuilderKey,
});
@override
State<ServerLoginPage> createState() => _ServerLoginPageState();
}
class _ServerLoginPageState extends State<ServerLoginPage> {
bool _isLoginLoading = false;
@override
Widget build(BuildContext context) {
final serverAddress = (widget.formBuilderKey.currentState
?.getRawValue(ServerAddressFormField.fkServerAddress)
as String?)
?.replaceAll(RegExp(r'https?://'), '') ??
'';
return Scaffold(
appBar: AppBar(
title: Text(S.of(context).loginPageSignInTitle),
bottom: _isLoginLoading
? const PreferredSize(
preferredSize: Size.fromHeight(4.0),
child: LinearProgressIndicator(),
)
: null,
),
body: ListView(
children: [
Text(S.of(context).loginPageSignInToPrefixText(serverAddress))
.padded(),
const UserCredentialsFormField(),
],
),
bottomNavigationBar: BottomAppBar(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FilledButton(
onPressed: () async {
setState(() => _isLoginLoading = true);
await widget.onDone();
setState(() => _isLoginLoading = false);
},
child: Text(S.of(context).loginPageSignInButtonLabel),
)
],
),
),
);
}
}

View File

@@ -1,49 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
import 'package:paperless_mobile/features/login/view/widgets/server_address_form_field.dart';
import 'package:paperless_mobile/features/login/view/widgets/user_credentials_form_field.dart';
class ServerLoginPage extends StatefulWidget {
final VoidCallback onDone;
final GlobalKey<FormBuilderState> formBuilderKey;
const ServerLoginPage({
super.key,
required this.onDone,
required this.formBuilderKey,
});
@override
State<ServerLoginPage> createState() => _ServerLoginPageState();
}
class _ServerLoginPageState extends State<ServerLoginPage> {
@override
Widget build(BuildContext context) {
final serverAddress = (widget.formBuilderKey.currentState
?.getRawValue(ServerAddressFormField.fkServerAddress) as String?)
?.replaceAll(RegExp(r'https?://'), '');
return Scaffold(
appBar: AppBar(
title: Text("Sign In"),
),
body: ListView(
children: [
Text("Sign in to $serverAddress").padded(),
UserCredentialsFormField(),
],
),
bottomNavigationBar: BottomAppBar(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FilledButton(
onPressed: widget.onDone,
child: Text("Sign In"),
)
],
),
),
);
}
}