feat: bugfixes, finished go_router migration, implemented better visibility of states

This commit is contained in:
Anton Stubenbord
2023-10-06 01:17:08 +02:00
parent ad23df4f89
commit a2c5ced3b7
102 changed files with 1512 additions and 3090 deletions

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
final rootNavigatorKey = GlobalKey<NavigatorState>();
final outerShellNavigatorKey = GlobalKey<NavigatorState>();
final landingNavigatorKey = GlobalKey<NavigatorState>();
final documentsNavigatorKey = GlobalKey<NavigatorState>();
final scannerNavigatorKey = GlobalKey<NavigatorState>();

View File

@@ -2,9 +2,10 @@ class R {
const R._();
static const landing = "landing";
static const login = "login";
static const loginToExistingAccount = 'loginToExistingAccount';
static const documents = "documents";
static const verifyIdentity = "verifyIdentity";
static const switchingAccounts = "switchingAccounts";
static const switchingAccount = "switchingAccount";
static const savedView = "savedView";
static const createSavedView = "createSavedView";
static const editSavedView = "editSavedView";
@@ -21,6 +22,8 @@ class R {
static const linkedDocuments = "linkedDocuments";
static const bulkEditDocuments = "bulkEditDocuments";
static const uploadQueue = "uploadQueue";
static const checkingLogin = "checkingLogin";
static const authenticating = "authenticating";
static const loggingOut = "loggingOut";
static const restoringSession = "restoringSession";
static const addAccount = 'addAccount';
}

View File

@@ -54,7 +54,8 @@ class DocumentsRoute extends GoRouteData {
}
class DocumentDetailsRoute extends GoRouteData {
static final GlobalKey<NavigatorState> $parentNavigatorKey = rootNavigatorKey;
static final GlobalKey<NavigatorState> $parentNavigatorKey =
outerShellNavigatorKey;
final bool isLabelClickable;
final DocumentModel $extra;
@@ -86,7 +87,8 @@ class DocumentDetailsRoute extends GoRouteData {
}
class EditDocumentRoute extends GoRouteData {
static final GlobalKey<NavigatorState> $parentNavigatorKey = rootNavigatorKey;
static final GlobalKey<NavigatorState> $parentNavigatorKey =
outerShellNavigatorKey;
final DocumentModel $extra;
@@ -114,7 +116,8 @@ class EditDocumentRoute extends GoRouteData {
}
class DocumentPreviewRoute extends GoRouteData {
static final GlobalKey<NavigatorState> $parentNavigatorKey = rootNavigatorKey;
static final GlobalKey<NavigatorState> $parentNavigatorKey =
outerShellNavigatorKey;
final DocumentModel $extra;
final String? title;

View File

@@ -49,7 +49,8 @@ class LabelsRoute extends GoRouteData {
}
class EditLabelRoute extends GoRouteData {
static final GlobalKey<NavigatorState> $parentNavigatorKey = rootNavigatorKey;
static final GlobalKey<NavigatorState> $parentNavigatorKey =
outerShellNavigatorKey;
final Label $extra;
@@ -67,7 +68,8 @@ class EditLabelRoute extends GoRouteData {
}
class CreateLabelRoute extends GoRouteData {
static final GlobalKey<NavigatorState> $parentNavigatorKey = rootNavigatorKey;
static final GlobalKey<NavigatorState> $parentNavigatorKey =
outerShellNavigatorKey;
final LabelType $extra;
final String? name;
@@ -88,7 +90,8 @@ class CreateLabelRoute extends GoRouteData {
}
class LinkedDocumentsRoute extends GoRouteData {
static final GlobalKey<NavigatorState> $parentNavigatorKey = rootNavigatorKey;
static final GlobalKey<NavigatorState> $parentNavigatorKey =
outerShellNavigatorKey;
final DocumentFilter $extra;
const LinkedDocumentsRoute(this.$extra);

View File

@@ -52,7 +52,8 @@ class ScannerRoute extends GoRouteData {
}
class DocumentUploadRoute extends GoRouteData {
static final GlobalKey<NavigatorState> $parentNavigatorKey = rootNavigatorKey;
static final GlobalKey<NavigatorState> $parentNavigatorKey =
outerShellNavigatorKey;
final FutureOr<Uint8List> $extra;
final String? title;
final String? filename;
@@ -72,6 +73,7 @@ class DocumentUploadRoute extends GoRouteData {
context.read(),
context.read(),
context.read(),
context.read(),
),
child: DocumentUploadPreparationPage(
title: title,

View File

@@ -11,7 +11,8 @@ part 'upload_queue_route.g.dart';
name: R.uploadQueue,
)
class UploadQueueRoute extends GoRouteData {
static final GlobalKey<NavigatorState> $parentNavigatorKey = rootNavigatorKey;
static final GlobalKey<NavigatorState> $parentNavigatorKey =
outerShellNavigatorKey;
@override
Widget build(BuildContext context, GoRouterState state) {

View File

@@ -7,7 +7,7 @@ import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
import 'package:paperless_mobile/core/factory/paperless_api_factory.dart';
import 'package:paperless_mobile/features/home/view/home_shell_widget.dart';
import 'package:paperless_mobile/features/sharing/cubit/receive_share_cubit.dart';
import 'package:paperless_mobile/features/sharing/view/widgets/upload_queue_shell.dart';
import 'package:paperless_mobile/features/sharing/view/widgets/event_listener_shell.dart';
import 'package:paperless_mobile/routes/navigation_keys.dart';
import 'package:provider/provider.dart';
@@ -50,7 +50,7 @@ import 'package:provider/provider.dart';
// )
class ProviderShellRoute extends ShellRouteData {
final PaperlessApiFactory apiFactory;
static final GlobalKey<NavigatorState> $navigatorKey = rootNavigatorKey;
static final GlobalKey<NavigatorState> $navigatorKey = outerShellNavigatorKey;
const ProviderShellRoute(this.apiFactory);
@@ -77,7 +77,7 @@ class ProviderShellRoute extends ShellRouteData {
child: ChangeNotifierProvider(
create: (context) => ConsumptionChangeNotifier()
..loadFromConsumptionDirectory(userId: currentUserId),
child: UploadQueueShell(child: navigator),
child: EventListenerShell(child: navigator),
),
);
}

View File

@@ -0,0 +1,80 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/model/info_message_exception.dart';
import 'package:paperless_mobile/features/login/cubit/authentication_cubit.dart';
import 'package:paperless_mobile/features/login/model/login_form_credentials.dart';
import 'package:paperless_mobile/features/login/view/add_account_page.dart';
import 'package:paperless_mobile/features/settings/view/dialogs/switch_account_dialog.dart';
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
import 'package:paperless_mobile/helpers/message_helpers.dart';
import 'package:paperless_mobile/routes/navigation_keys.dart';
import 'package:paperless_mobile/routes/routes.dart';
part 'add_account_route.g.dart';
@TypedGoRoute<AddAccountRoute>(
path: '/add-account',
name: R.addAccount,
)
class AddAccountRoute extends GoRouteData {
const AddAccountRoute();
static final $parentNavigatorKey = rootNavigatorKey;
@override
Widget build(BuildContext context, GoRouterState state) {
return AddAccountPage(
titleText: S.of(context)!.addAccount,
onSubmit:
(context, username, password, serverUrl, clientCertificate) async {
try {
final userId = await context.read<AuthenticationCubit>().addAccount(
credentials: LoginFormCredentials(
username: username,
password: password,
),
clientCertificate: clientCertificate,
serverUrl: serverUrl,
enableBiometricAuthentication: false,
locale: Localizations.localeOf(context).languageCode,
);
final shoudSwitch = await showDialog<bool>(
context: context,
builder: (context) => const SwitchAccountDialog(),
) ??
false;
if (shoudSwitch) {
await context.read<AuthenticationCubit>().switchAccount(userId);
} else {
while (context.canPop()) {
context.pop();
}
}
} on PaperlessApiException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace);
// context.pop();
} on PaperlessFormValidationException catch (exception, stackTrace) {
if (exception.hasUnspecificErrorMessage()) {
showLocalizedError(context, exception.unspecificErrorMessage()!);
// context.pop();
} else {
showGenericError(
context,
exception.validationMessages.values.first,
stackTrace,
); //TODO: Check if we can show error message directly on field here.
}
} on InfoMessageException catch (error) {
showInfoMessage(context, error);
// context.pop();
} catch (unknownError, stackTrace) {
showGenericError(context, unknownError.toString(), stackTrace);
// context.pop();
}
},
submitText: S.of(context)!.addAccount,
);
}
}

View File

@@ -1,23 +0,0 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:paperless_mobile/routes/routes.dart';
part 'checking_login_route.g.dart';
@TypedGoRoute<CheckingLoginRoute>(
path: "/checking-login",
name: R.checkingLogin,
)
class CheckingLoginRoute extends GoRouteData {
const CheckingLoginRoute();
@override
Widget build(BuildContext context, GoRouterState state) {
return Scaffold(
body: Center(
child: Text("Logging in..."),
),
);
}
}

View File

@@ -6,12 +6,12 @@ import 'package:paperless_mobile/routes/routes.dart';
part 'logging_out_route.g.dart';
@TypedGoRoute<LogginOutRoute>(
@TypedGoRoute<LoggingOutRoute>(
path: "/logging-out",
name: R.loggingOut,
)
class LogginOutRoute extends GoRouteData {
const LogginOutRoute();
class LoggingOutRoute extends GoRouteData {
const LoggingOutRoute();
@override
Widget build(BuildContext context, GoRouterState state) {
return Scaffold(

View File

@@ -1,10 +1,18 @@
import 'dart:async';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:hive_flutter/adapters.dart';
import 'package:paperless_mobile/core/config/hive/hive_extensions.dart';
import 'package:paperless_mobile/features/login/cubit/authentication_cubit.dart';
import 'package:paperless_mobile/features/login/model/client_certificate.dart';
import 'package:paperless_mobile/features/login/view/login_page.dart';
import 'package:paperless_mobile/features/login/view/login_to_existing_account_page.dart';
import 'package:paperless_mobile/features/login/view/verify_identity_page.dart';
import 'package:paperless_mobile/features/login/view/widgets/login_transition_page.dart';
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
import 'package:paperless_mobile/routes/navigation_keys.dart';
import 'package:paperless_mobile/routes/routes.dart';
part 'login_route.g.dart';
@@ -12,12 +20,51 @@ part 'login_route.g.dart';
@TypedGoRoute<LoginRoute>(
path: "/login",
name: R.login,
routes: [
TypedGoRoute<SwitchingAccountsRoute>(
path: "switching-account",
name: R.switchingAccount,
),
TypedGoRoute<AuthenticatingRoute>(
path: 'authenticating',
name: R.authenticating,
),
TypedGoRoute<VerifyIdentityRoute>(
path: 'verify-identity',
name: R.verifyIdentity,
),
TypedGoRoute<LoginToExistingAccountRoute>(
path: 'existing',
name: R.loginToExistingAccount,
),
TypedGoRoute<RestoringSessionRoute>(
path: 'restoring-session',
name: R.restoringSession,
),
],
)
class LoginRoute extends GoRouteData {
const LoginRoute();
static final $parentNavigatorKey = rootNavigatorKey;
final String? serverUrl;
final String? username;
final String? password;
final ClientCertificate? $extra;
const LoginRoute({
this.serverUrl,
this.username,
this.password,
this.$extra,
});
@override
Widget build(BuildContext context, GoRouterState state) {
return const LoginPage();
return LoginPage(
initialServerUrl: serverUrl,
initialUsername: username,
initialPassword: password,
initialClientCertificate: $extra,
);
}
@override
@@ -28,3 +75,77 @@ class LoginRoute extends GoRouteData {
return null;
}
}
class SwitchingAccountsRoute extends GoRouteData {
static final $parentNavigatorKey = rootNavigatorKey;
const SwitchingAccountsRoute();
@override
Widget build(BuildContext context, GoRouterState state) {
return LoginTransitionPage(
text: S.of(context)!.switchingAccountsPleaseWait,
);
}
}
class AuthenticatingRoute extends GoRouteData {
static final $parentNavigatorKey = rootNavigatorKey;
final String checkLoginStageName;
const AuthenticatingRoute(this.checkLoginStageName);
@override
Widget build(BuildContext context, GoRouterState state) {
final stage = AuthenticatingStage.values.byName(checkLoginStageName);
final text = switch (stage) {
AuthenticatingStage.authenticating => S.of(context)!.authenticatingDots,
AuthenticatingStage.persistingLocalUserData =>
S.of(context)!.persistingUserInformation,
AuthenticatingStage.fetchingUserInformation =>
S.of(context)!.fetchingUserInformation,
};
return LoginTransitionPage(text: text);
}
}
class VerifyIdentityRoute extends GoRouteData {
static final $parentNavigatorKey = rootNavigatorKey;
final String userId;
const VerifyIdentityRoute({required this.userId});
@override
Widget build(BuildContext context, GoRouterState state) {
return VerifyIdentityPage(userId: userId);
}
}
class LoginToExistingAccountRoute extends GoRouteData {
static final $parentNavigatorKey = rootNavigatorKey;
const LoginToExistingAccountRoute();
@override
FutureOr<String?> redirect(BuildContext context, GoRouterState state) {
if (Hive.localUserAccountBox.isEmpty) {
return "/login";
}
return null;
}
@override
Widget build(BuildContext context, GoRouterState state) {
return const LoginToExistingAccountPage();
}
}
class RestoringSessionRoute extends GoRouteData {
static final $parentNavigatorKey = rootNavigatorKey;
const RestoringSessionRoute();
@override
Widget build(BuildContext context, GoRouterState state) {
return LoginTransitionPage(text: S.of(context)!.restoringSession);
}
}

View File

@@ -13,7 +13,7 @@ part 'settings_route.g.dart';
name: R.settings,
)
class SettingsRoute extends GoRouteData {
static final GlobalKey<NavigatorState> $parentNavigatorKey = rootNavigatorKey;
static final GlobalKey<NavigatorState> $parentNavigatorKey = outerShellNavigatorKey;
@override
Widget build(BuildContext context, GoRouterState state) {

View File

@@ -1,18 +0,0 @@
import 'package:flutter/widgets.dart';
import 'package:go_router/go_router.dart';
import 'package:paperless_mobile/features/settings/view/pages/switching_accounts_page.dart';
import 'package:paperless_mobile/routes/routes.dart';
part 'switching_accounts_route.g.dart';
@TypedGoRoute<SwitchingAccountsRoute>(
path: '/switching-accounts',
name: R.switchingAccounts,
)
class SwitchingAccountsRoute extends GoRouteData {
const SwitchingAccountsRoute();
@override
Widget build(BuildContext context, GoRouterState state) {
return const SwitchingAccountsPage();
}
}

View File

@@ -1,19 +0,0 @@
import 'package:go_router/go_router.dart';
import 'package:flutter/widgets.dart';
import 'package:paperless_mobile/features/home/view/widget/verify_identity_page.dart';
import 'package:paperless_mobile/routes/routes.dart';
part 'verify_identity_route.g.dart';
@TypedGoRoute<VerifyIdentityRoute>(
path: '/verify-identity',
name: R.verifyIdentity,
)
class VerifyIdentityRoute extends GoRouteData {
const VerifyIdentityRoute();
@override
Widget build(BuildContext context, GoRouterState state) {
return const VerifyIdentityPage();
}
}