diff --git a/packages/neon/neon/lib/src/blocs/accounts.dart b/packages/neon/neon/lib/src/blocs/accounts.dart index c3a5ef28..03e61d4b 100644 --- a/packages/neon/neon/lib/src/blocs/accounts.dart +++ b/packages/neon/neon/lib/src/blocs/accounts.dart @@ -207,6 +207,9 @@ class AccountsBloc extends Bloc implements AccountsBlocEvents, AccountsBlocState return aa; } + /// Whether accounts are logged in. + bool get hasAccounts => activeAccount.value != null; + /// The options for the [activeAccount]. /// /// Convenience method for [getOptionsFor] with the currently active account. diff --git a/packages/neon/neon/lib/src/pages/login.dart b/packages/neon/neon/lib/src/pages/login.dart index 84d4945a..3ad74bae 100644 --- a/packages/neon/neon/lib/src/pages/login.dart +++ b/packages/neon/neon/lib/src/pages/login.dart @@ -1,5 +1,3 @@ -import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:neon/l10n/localizations.dart'; import 'package:neon/src/platform/platform.dart'; @@ -12,12 +10,9 @@ import 'package:provider/provider.dart'; class LoginPage extends StatefulWidget { const LoginPage({ - this.serverURL, super.key, }); - final String? serverURL; - @override _LoginPageState createState() => _LoginPageState(); } @@ -29,12 +24,6 @@ class _LoginPageState extends State { @override void initState() { super.initState(); - - if (widget.serverURL != null) { - WidgetsBinding.instance.addPostFrameCallback((final _) async { - await _beginLoginFlow(widget.serverURL!); - }); - } } @override @@ -43,16 +32,6 @@ class _LoginPageState extends State { super.dispose(); } - Future _beginLoginFlow(final String serverURL) async { - final result = await LoginCheckServerStatusRoute(serverURL: serverURL).push(context); - if ((result ?? false) && mounted) { - // This needs be done, otherwise the context is dirty after returning from the previously pushed route - WidgetsBinding.instance.addPostFrameCallback((final _) async { - await LoginFlowRoute(serverURL: serverURL).push(context); - }); - } - } - @override Widget build(final BuildContext context) { final branding = Branding.of(context); @@ -61,7 +40,7 @@ class _LoginPageState extends State { return Scaffold( resizeToAvoidBottomInset: true, appBar: AppBar( - leading: Navigator.of(context).canPop() ? const CloseButton() : null, + leading: Navigator.canPop(context) ? const CloseButton() : null, ), body: Center( child: ConstrainedBox( @@ -102,7 +81,7 @@ class _LoginPageState extends State { Icons.qr_code_scanner, size: 50, ), - onPressed: () => unawaited(const LoginQrcodeRoute().push(context)), + onPressed: () => const LoginQrcodeRoute().go(context), ), const SizedBox( height: 20, @@ -121,11 +100,10 @@ class _LoginPageState extends State { hintText: 'https://...', ), keyboardType: TextInputType.url, - initialValue: widget.serverURL, validator: (final input) => validateHttpUrl(context, input), - onFieldSubmitted: (final input) async { + onFieldSubmitted: (final input) { if (_formKey.currentState!.validate()) { - await _beginLoginFlow(input); + LoginCheckServerStatusRoute(serverUrl: input).go(context); } else { _focusNode.requestFocus(); } diff --git a/packages/neon/neon/lib/src/pages/login_check_server_status.dart b/packages/neon/neon/lib/src/pages/login_check_server_status.dart index 1fd94472..48432fc0 100644 --- a/packages/neon/neon/lib/src/pages/login_check_server_status.dart +++ b/packages/neon/neon/lib/src/pages/login_check_server_status.dart @@ -3,6 +3,7 @@ import 'package:neon/l10n/localizations.dart'; import 'package:neon/src/bloc/result.dart'; import 'package:neon/src/bloc/result_builder.dart'; import 'package:neon/src/blocs/login_check_server_status.dart'; +import 'package:neon/src/router.dart'; import 'package:neon/src/theme/dialog.dart'; import 'package:neon/src/widgets/exception.dart'; import 'package:neon/src/widgets/linear_progress_indicator.dart'; @@ -13,9 +14,19 @@ class LoginCheckServerStatusPage extends StatefulWidget { const LoginCheckServerStatusPage({ required this.serverURL, super.key, + }) : loginName = null, + password = null; + + const LoginCheckServerStatusPage.withCredentials({ + required this.serverURL, + required String this.loginName, + required String this.password, + super.key, }); final String serverURL; + final String? loginName; + final String? password; @override State createState() => _LoginCheckServerStatusPageState(); @@ -47,35 +58,49 @@ class _LoginCheckServerStatusPageState extends State constraints: NeonDialogTheme.of(context).constraints, child: ResultBuilder.behaviorSubject( stream: bloc.state, - builder: (final context, final state) => Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - NeonLinearProgressIndicator( - visible: state.isLoading, - ), - NeonException( - state.error, - onRetry: bloc.refresh, - ), - _buildServerVersionTile(state), - _buildMaintenanceModeTile(state), - Align( - alignment: Alignment.bottomRight, - child: ElevatedButton( - onPressed: state.hasData && state.requireData.isSupported && !state.requireData.maintenance - ? () => Navigator.of(context).pop(true) - : null, - child: Text(AppLocalizations.of(context).actionContinue), + builder: (final context, final state) { + final success = state.hasData && state.requireData.isSupported && !state.requireData.maintenance; + + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + NeonLinearProgressIndicator( + visible: state.isLoading, + ), + NeonException( + state.error, + onRetry: bloc.refresh, ), - ), - ], - ), + _buildServerVersionTile(state), + _buildMaintenanceModeTile(state), + Align( + alignment: Alignment.bottomRight, + child: ElevatedButton( + onPressed: success ? _onContinue : null, + child: Text(AppLocalizations.of(context).actionContinue), + ), + ), + ], + ); + }, ), ), ), ), ); + void _onContinue() { + if (widget.loginName != null) { + LoginCheckAccountRoute( + serverUrl: widget.serverURL, + loginName: widget.loginName!, + password: widget.password!, + ).pushReplacement(context); + } else { + LoginFlowRoute(serverUrl: widget.serverURL).pushReplacement(context); + } + } + Widget _buildServerVersionTile(final Result result) { if (!result.hasData) { return NeonValidationTile( diff --git a/packages/neon/neon/lib/src/pages/login_flow.dart b/packages/neon/neon/lib/src/pages/login_flow.dart index c1cc8b52..7931e2a3 100644 --- a/packages/neon/neon/lib/src/pages/login_flow.dart +++ b/packages/neon/neon/lib/src/pages/login_flow.dart @@ -39,7 +39,7 @@ class _LoginFlowPageState extends State { bloc.result.listen((final result) { LoginCheckAccountRoute( - serverURL: result.server, + serverUrl: result.server, loginName: result.loginName, password: result.appPassword, ).pushReplacement(context); @@ -56,29 +56,32 @@ class _LoginFlowPageState extends State { Widget build(final BuildContext context) => Scaffold( appBar: AppBar(), body: Center( - child: ResultBuilder.behaviorSubject( - stream: bloc.init, - builder: (final context, final init) => Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - NeonLinearProgressIndicator( - visible: init.isLoading, - ), - NeonException( - init.error, - onRetry: bloc.refresh, - ), - if (init.hasData) ...[ - Text(AppLocalizations.of(context).loginSwitchToBrowserWindow), - const SizedBox( - height: 10, + child: Padding( + padding: const EdgeInsets.all(24), + child: ResultBuilder.behaviorSubject( + stream: bloc.init, + builder: (final context, final init) => Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + NeonLinearProgressIndicator( + visible: init.isLoading, ), - ElevatedButton( - onPressed: bloc.refresh, - child: Text(AppLocalizations.of(context).loginOpenAgain), + NeonException( + init.error, + onRetry: bloc.refresh, ), + if (init.hasData) ...[ + Text(AppLocalizations.of(context).loginSwitchToBrowserWindow), + const SizedBox( + height: 10, + ), + ElevatedButton( + onPressed: bloc.refresh, + child: Text(AppLocalizations.of(context).loginOpenAgain), + ), + ], ], - ], + ), ), ), ), diff --git a/packages/neon/neon/lib/src/pages/login_qrcode.dart b/packages/neon/neon/lib/src/pages/login_qrcode.dart index 08797c14..5c1086f2 100644 --- a/packages/neon/neon/lib/src/pages/login_qrcode.dart +++ b/packages/neon/neon/lib/src/pages/login_qrcode.dart @@ -1,5 +1,3 @@ -import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:flutter_zxing/flutter_zxing.dart'; import 'package:neon/src/router.dart'; @@ -41,7 +39,12 @@ class _LoginQrcodePageState extends State { if (match == null) { throw InvalidQrcodeException(); } - await processLoginQrcode(context, match); + + LoginCheckServerStatusRoute.withCredentials( + serverUrl: match.server, + loginName: match.user, + password: match.password, + ).pushReplacement(context); } catch (e, s) { if (_lastErrorURL != url) { debugPrint(e.toString()); @@ -55,52 +58,3 @@ class _LoginQrcodePageState extends State { ), ); } - -class LoginQrcodeIntermediatePage extends StatefulWidget { - const LoginQrcodeIntermediatePage({ - required this.serverURL, - required this.loginName, - required this.password, - super.key, - }); - - final String serverURL; - final String loginName; - final String password; - - @override - State createState() => _LoginQrcodeIntermediatePageState(); -} - -class _LoginQrcodeIntermediatePageState extends State { - @override - void initState() { - super.initState(); - WidgetsBinding.instance.addPostFrameCallback((final _) { - unawaited( - processLoginQrcode( - context, - LoginQrcode( - server: widget.serverURL, - user: widget.loginName, - password: widget.password, - ), - ), - ); - }); - } - - @override - Widget build(final BuildContext context) => const SizedBox(); -} - -Future processLoginQrcode(final BuildContext context, final LoginQrcode qrcode) async { - final result = await LoginCheckServerStatusRoute(serverURL: qrcode.server).push(context); - if ((result ?? false) && context.mounted) { - LoginCheckAccountRoute( - serverURL: qrcode.server, - loginName: qrcode.user, - password: qrcode.password, - ).pushReplacement(context); - } -} diff --git a/packages/neon/neon/lib/src/pages/settings.dart b/packages/neon/neon/lib/src/pages/settings.dart index 80d0e06f..69ace82c 100644 --- a/packages/neon/neon/lib/src/pages/settings.dart +++ b/packages/neon/neon/lib/src/pages/settings.dart @@ -208,9 +208,7 @@ class _SettingsPageState extends State { ], CustomSettingsTile( title: ElevatedButton.icon( - onPressed: () { - const AddAccountRoute().go(context); - }, + onPressed: () async => const LoginRoute().push(context), icon: Icon(MdiIcons.accountPlus), label: Text(AppLocalizations.of(context).globalOptionsAccountsAdd), ), diff --git a/packages/neon/neon/lib/src/router.dart b/packages/neon/neon/lib/src/router.dart index 1a453365..708e5b46 100644 --- a/packages/neon/neon/lib/src/router.dart +++ b/packages/neon/neon/lib/src/router.dart @@ -1,3 +1,7 @@ +// ignore_for_file: unnecessary_overrides + +import 'dart:async'; + import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:go_router/go_router.dart'; @@ -29,19 +33,17 @@ class AppRouter extends GoRouter { navigatorKey: navigatorKey, initialLocation: const HomeRoute().location, redirect: (final context, final state) { - final account = accountsBloc.activeAccount.valueOrNull; - final loginQrcode = LoginQrcode.tryParse(state.location); if (loginQrcode != null) { - return LoginQrcodeIntermediateRoute( - serverURL: loginQrcode.server, + return LoginCheckServerStatusRoute.withCredentials( + serverUrl: loginQrcode.server, loginName: loginQrcode.user, password: loginQrcode.password, ).location; } // redirect to loginscreen when no account is logged in - if (account == null && !state.location.startsWith(const LoginRoute().location)) { + if (!accountsBloc.hasAccounts && !state.location.startsWith(const LoginRoute().location)) { return const LoginRoute().location; } @@ -83,9 +85,23 @@ class AccountSettingsRoute extends GoRouteData { path: 'apps/:appid', name: 'NextcloudAppSettings', ), - TypedGoRoute( + TypedGoRoute<_AddAccountRoute>( path: 'account/add', name: 'addAccount', + routes: [ + TypedGoRoute<_AddAccountFlowRoute>( + path: 'flow', + ), + TypedGoRoute<_AddAccountQrcodeRoute>( + path: 'qrcode', + ), + TypedGoRoute<_AddAccountCheckServerStatusRoute>( + path: 'check/server', + ), + TypedGoRoute<_AddAccountCheckAccountRoute>( + path: 'check/account', + ), + ], ), TypedGoRoute( path: 'account/:accountid', @@ -113,47 +129,59 @@ class HomeRoute extends GoRouteData { name: 'login', routes: [ TypedGoRoute( - path: 'flow/:serverURL', - name: 'loginFlow', + path: 'flow', ), TypedGoRoute( path: 'qrcode', - name: 'loginQrcode', - ), - TypedGoRoute( - path: 'qrcode/intermediate/:serverURL/:loginName/:password', - name: 'loginQrcodeIntermediate', ), TypedGoRoute( - path: 'check/server/:serverURL', - name: 'checkServerStatus', + path: 'check/server', ), TypedGoRoute( - path: 'check/account/:serverURL/:loginName/:password', - name: 'checkAccount', + path: 'check/account', ), ], ) @immutable class LoginRoute extends GoRouteData { - const LoginRoute({this.serverURL}); + const LoginRoute(); - final String? serverURL; + @override + Widget build(final BuildContext context, final GoRouterState state) => const LoginPage(); @override - Widget build(final BuildContext context, final GoRouterState state) => LoginPage(serverURL: serverURL); + FutureOr redirect(final BuildContext context, final GoRouterState state) { + final hasAccounts = Provider.of(context, listen: false).hasAccounts; + + if (state.fullPath == location && hasAccounts) { + return const _AddAccountRoute().location; + } + + return null; + } } @immutable class LoginFlowRoute extends GoRouteData { const LoginFlowRoute({ - required this.serverURL, + required this.serverUrl, }); - final String serverURL; + final String serverUrl; @override - Widget build(final BuildContext context, final GoRouterState state) => LoginFlowPage(serverURL: serverURL); + Widget build(final BuildContext context, final GoRouterState state) => LoginFlowPage(serverURL: serverUrl); + + @override + FutureOr redirect(final BuildContext context, final GoRouterState state) { + final hasAccounts = Provider.of(context, listen: false).hasAccounts; + + if (state.fullPath == location && hasAccounts) { + return _AddAccountFlowRoute(serverUrl: serverUrl).location; + } + + return null; + } } @immutable @@ -162,68 +190,161 @@ class LoginQrcodeRoute extends GoRouteData { @override Widget build(final BuildContext context, final GoRouterState state) => const LoginQrcodePage(); -} -@immutable -class LoginQrcodeIntermediateRoute extends GoRouteData { - const LoginQrcodeIntermediateRoute({ - required this.serverURL, - required this.loginName, - required this.password, - }); + @override + FutureOr redirect(final BuildContext context, final GoRouterState state) { + final hasAccounts = Provider.of(context, listen: false).hasAccounts; - final String serverURL; - final String loginName; - final String password; + if (state.fullPath == location && hasAccounts) { + return const _AddAccountQrcodeRoute().location; + } - @override - Widget build(final BuildContext context, final GoRouterState state) => LoginQrcodeIntermediatePage( - serverURL: serverURL, - loginName: loginName, - password: password, - ); + return null; + } } @immutable class LoginCheckServerStatusRoute extends GoRouteData { const LoginCheckServerStatusRoute({ - required this.serverURL, - }); + required this.serverUrl, + }) : loginName = null, + password = null; - final String serverURL; + const LoginCheckServerStatusRoute.withCredentials({ + required this.serverUrl, + required String this.loginName, + required String this.password, + }) : assert(!kIsWeb, 'Might leak the password to the browser history'); + + final String serverUrl; + final String? loginName; + final String? password; @override - Widget build(final BuildContext context, final GoRouterState state) => LoginCheckServerStatusPage( - serverURL: serverURL, + Widget build(final BuildContext context, final GoRouterState state) { + if (loginName != null && password != null) { + return LoginCheckServerStatusPage.withCredentials( + serverURL: serverUrl, + loginName: loginName!, + password: password!, ); + } + + return LoginCheckServerStatusPage( + serverURL: serverUrl, + ); + } + + @override + FutureOr redirect(final BuildContext context, final GoRouterState state) { + final hasAccounts = Provider.of(context, listen: false).hasAccounts; + + if (state.fullPath == location && hasAccounts) { + if (loginName != null && password != null) { + return _AddAccountCheckServerStatusRoute.withCredentials( + serverUrl: serverUrl, + loginName: loginName!, + password: password!, + ).location; + } + + return _AddAccountCheckServerStatusRoute( + serverUrl: serverUrl, + ).location; + } + + return null; + } } @immutable class LoginCheckAccountRoute extends GoRouteData { const LoginCheckAccountRoute({ - required this.serverURL, + required this.serverUrl, required this.loginName, required this.password, - }); + }) : assert(!kIsWeb, 'Might leak the password to the browser history'); - final String serverURL; + final String serverUrl; final String loginName; final String password; @override Widget build(final BuildContext context, final GoRouterState state) => LoginCheckAccountPage( - serverURL: serverURL, + serverURL: serverUrl, loginName: loginName, password: password, ); + + @override + FutureOr redirect(final BuildContext context, final GoRouterState state) { + final hasAccounts = Provider.of(context, listen: false).hasAccounts; + + if (state.fullPath == location && hasAccounts) { + return _AddAccountCheckAccountRoute( + serverUrl: serverUrl, + loginName: loginName, + password: password, + ).location; + } + + return null; + } } @immutable -class AddAccountRoute extends GoRouteData { - const AddAccountRoute(); +class _AddAccountRoute extends LoginRoute { + const _AddAccountRoute(); +} +@immutable +class _AddAccountFlowRoute extends LoginFlowRoute { + const _AddAccountFlowRoute({ + required super.serverUrl, + }); @override - Widget build(final BuildContext context, final GoRouterState state) => const LoginPage(); + String get serverUrl => super.serverUrl; +} + +@immutable +class _AddAccountQrcodeRoute extends LoginQrcodeRoute { + const _AddAccountQrcodeRoute(); +} + +@immutable +class _AddAccountCheckServerStatusRoute extends LoginCheckServerStatusRoute { + const _AddAccountCheckServerStatusRoute({ + required super.serverUrl, + }); + + const _AddAccountCheckServerStatusRoute.withCredentials({ + required super.serverUrl, + required super.loginName, + required super.password, + }) : super.withCredentials(); + + @override + String get serverUrl => super.serverUrl; + @override + String? get loginName => super.loginName; + @override + String? get password => super.password; +} + +@immutable +class _AddAccountCheckAccountRoute extends LoginCheckAccountRoute { + const _AddAccountCheckAccountRoute({ + required super.serverUrl, + required super.loginName, + required super.password, + }); + + @override + String get serverUrl => super.serverUrl; + @override + String get loginName => super.loginName; + @override + String get password => super.password; } @immutable diff --git a/packages/neon/neon/lib/src/router.g.dart b/packages/neon/neon/lib/src/router.g.dart index c1730833..be315b41 100644 --- a/packages/neon/neon/lib/src/router.g.dart +++ b/packages/neon/neon/lib/src/router.g.dart @@ -29,7 +29,25 @@ RouteBase get $homeRoute => GoRouteData.$route( GoRouteData.$route( path: 'account/add', name: 'addAccount', - factory: $AddAccountRouteExtension._fromState, + factory: $_AddAccountRouteExtension._fromState, + routes: [ + GoRouteData.$route( + path: 'flow', + factory: $_AddAccountFlowRouteExtension._fromState, + ), + GoRouteData.$route( + path: 'qrcode', + factory: $_AddAccountQrcodeRouteExtension._fromState, + ), + GoRouteData.$route( + path: 'check/server', + factory: $_AddAccountCheckServerStatusRouteExtension._fromState, + ), + GoRouteData.$route( + path: 'check/account', + factory: $_AddAccountCheckAccountRouteExtension._fromState, + ), + ], ), GoRouteData.$route( path: 'account/:accountid', @@ -85,8 +103,8 @@ extension $NextcloudAppSettingsRouteExtension on NextcloudAppSettingsRoute { void pushReplacement(BuildContext context) => context.pushReplacement(location); } -extension $AddAccountRouteExtension on AddAccountRoute { - static AddAccountRoute _fromState(GoRouterState state) => const AddAccountRoute(); +extension $_AddAccountRouteExtension on _AddAccountRoute { + static _AddAccountRoute _fromState(GoRouterState state) => const _AddAccountRoute(); String get location => GoRouteData.$location( '/settings/account/add', @@ -99,6 +117,81 @@ extension $AddAccountRouteExtension on AddAccountRoute { void pushReplacement(BuildContext context) => context.pushReplacement(location); } +extension $_AddAccountFlowRouteExtension on _AddAccountFlowRoute { + static _AddAccountFlowRoute _fromState(GoRouterState state) => _AddAccountFlowRoute( + serverUrl: state.queryParameters['server-url']!, + ); + + String get location => GoRouteData.$location( + '/settings/account/add/flow', + queryParams: { + 'server-url': serverUrl, + }, + ); + + void go(BuildContext context) => context.go(location); + + Future push(BuildContext context) => context.push(location); + + void pushReplacement(BuildContext context) => context.pushReplacement(location); +} + +extension $_AddAccountQrcodeRouteExtension on _AddAccountQrcodeRoute { + static _AddAccountQrcodeRoute _fromState(GoRouterState state) => const _AddAccountQrcodeRoute(); + + String get location => GoRouteData.$location( + '/settings/account/add/qrcode', + ); + + void go(BuildContext context) => context.go(location); + + Future push(BuildContext context) => context.push(location); + + void pushReplacement(BuildContext context) => context.pushReplacement(location); +} + +extension $_AddAccountCheckServerStatusRouteExtension on _AddAccountCheckServerStatusRoute { + static _AddAccountCheckServerStatusRoute _fromState(GoRouterState state) => _AddAccountCheckServerStatusRoute( + serverUrl: state.queryParameters['server-url']!, + ); + + String get location => GoRouteData.$location( + '/settings/account/add/check/server', + queryParams: { + 'server-url': serverUrl, + }, + ); + + void go(BuildContext context) => context.go(location); + + Future push(BuildContext context) => context.push(location); + + void pushReplacement(BuildContext context) => context.pushReplacement(location); +} + +extension $_AddAccountCheckAccountRouteExtension on _AddAccountCheckAccountRoute { + static _AddAccountCheckAccountRoute _fromState(GoRouterState state) => _AddAccountCheckAccountRoute( + serverUrl: state.queryParameters['server-url']!, + loginName: state.queryParameters['login-name']!, + password: state.queryParameters['password']!, + ); + + String get location => GoRouteData.$location( + '/settings/account/add/check/account', + queryParams: { + 'server-url': serverUrl, + 'login-name': loginName, + 'password': password, + }, + ); + + void go(BuildContext context) => context.go(location); + + Future push(BuildContext context) => context.push(location); + + void pushReplacement(BuildContext context) => context.pushReplacement(location); +} + extension $AccountSettingsRouteExtension on AccountSettingsRoute { static AccountSettingsRoute _fromState(GoRouterState state) => AccountSettingsRoute( accountid: state.pathParameters['accountid']!, @@ -121,43 +214,29 @@ RouteBase get $loginRoute => GoRouteData.$route( factory: $LoginRouteExtension._fromState, routes: [ GoRouteData.$route( - path: 'flow/:serverURL', - name: 'loginFlow', + path: 'flow', factory: $LoginFlowRouteExtension._fromState, ), GoRouteData.$route( path: 'qrcode', - name: 'loginQrcode', factory: $LoginQrcodeRouteExtension._fromState, ), GoRouteData.$route( - path: 'qrcode/intermediate/:serverURL/:loginName/:password', - name: 'loginQrcodeIntermediate', - factory: $LoginQrcodeIntermediateRouteExtension._fromState, - ), - GoRouteData.$route( - path: 'check/server/:serverURL', - name: 'checkServerStatus', + path: 'check/server', factory: $LoginCheckServerStatusRouteExtension._fromState, ), GoRouteData.$route( - path: 'check/account/:serverURL/:loginName/:password', - name: 'checkAccount', + path: 'check/account', factory: $LoginCheckAccountRouteExtension._fromState, ), ], ); extension $LoginRouteExtension on LoginRoute { - static LoginRoute _fromState(GoRouterState state) => LoginRoute( - serverURL: state.queryParameters['server-u-r-l'], - ); + static LoginRoute _fromState(GoRouterState state) => const LoginRoute(); String get location => GoRouteData.$location( '/login', - queryParams: { - if (serverURL != null) 'server-u-r-l': serverURL, - }, ); void go(BuildContext context) => context.go(location); @@ -169,11 +248,14 @@ extension $LoginRouteExtension on LoginRoute { extension $LoginFlowRouteExtension on LoginFlowRoute { static LoginFlowRoute _fromState(GoRouterState state) => LoginFlowRoute( - serverURL: state.pathParameters['serverURL']!, + serverUrl: state.queryParameters['server-url']!, ); String get location => GoRouteData.$location( - '/login/flow/${Uri.encodeComponent(serverURL)}', + '/login/flow', + queryParams: { + 'server-url': serverUrl, + }, ); void go(BuildContext context) => context.go(location); @@ -197,31 +279,16 @@ extension $LoginQrcodeRouteExtension on LoginQrcodeRoute { void pushReplacement(BuildContext context) => context.pushReplacement(location); } -extension $LoginQrcodeIntermediateRouteExtension on LoginQrcodeIntermediateRoute { - static LoginQrcodeIntermediateRoute _fromState(GoRouterState state) => LoginQrcodeIntermediateRoute( - serverURL: state.pathParameters['serverURL']!, - loginName: state.pathParameters['loginName']!, - password: state.pathParameters['password']!, - ); - - String get location => GoRouteData.$location( - '/login/qrcode/intermediate/${Uri.encodeComponent(serverURL)}/${Uri.encodeComponent(loginName)}/${Uri.encodeComponent(password)}', - ); - - void go(BuildContext context) => context.go(location); - - Future push(BuildContext context) => context.push(location); - - void pushReplacement(BuildContext context) => context.pushReplacement(location); -} - extension $LoginCheckServerStatusRouteExtension on LoginCheckServerStatusRoute { static LoginCheckServerStatusRoute _fromState(GoRouterState state) => LoginCheckServerStatusRoute( - serverURL: state.pathParameters['serverURL']!, + serverUrl: state.queryParameters['server-url']!, ); String get location => GoRouteData.$location( - '/login/check/server/${Uri.encodeComponent(serverURL)}', + '/login/check/server', + queryParams: { + 'server-url': serverUrl, + }, ); void go(BuildContext context) => context.go(location); @@ -233,13 +300,18 @@ extension $LoginCheckServerStatusRouteExtension on LoginCheckServerStatusRoute { extension $LoginCheckAccountRouteExtension on LoginCheckAccountRoute { static LoginCheckAccountRoute _fromState(GoRouterState state) => LoginCheckAccountRoute( - serverURL: state.pathParameters['serverURL']!, - loginName: state.pathParameters['loginName']!, - password: state.pathParameters['password']!, + serverUrl: state.queryParameters['server-url']!, + loginName: state.queryParameters['login-name']!, + password: state.queryParameters['password']!, ); String get location => GoRouteData.$location( - '/login/check/account/${Uri.encodeComponent(serverURL)}/${Uri.encodeComponent(loginName)}/${Uri.encodeComponent(password)}', + '/login/check/account', + queryParams: { + 'server-url': serverUrl, + 'login-name': loginName, + 'password': password, + }, ); void go(BuildContext context) => context.go(location); diff --git a/packages/neon/neon/lib/src/widgets/exception.dart b/packages/neon/neon/lib/src/widgets/exception.dart index aebf6816..db9f8db9 100644 --- a/packages/neon/neon/lib/src/widgets/exception.dart +++ b/packages/neon/neon/lib/src/widgets/exception.dart @@ -185,9 +185,11 @@ class NeonException extends StatelessWidget { } static void _openLoginPage(final BuildContext context) { - LoginRoute( - serverURL: Provider.of(context, listen: false).activeAccount.value!.serverURL, - ).go(context); + unawaited( + LoginCheckServerStatusRoute( + serverUrl: Provider.of(context, listen: false).activeAccount.value!.serverURL, + ).push(context), + ); } }