A
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:pshared/models/auth/state.dart';
|
||||
import 'package:pshared/provider/account.dart';
|
||||
|
||||
import 'package:pweb/app/router/pages.dart';
|
||||
@@ -12,57 +11,63 @@ import 'package:pweb/widgets/error/snackbar.dart';
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
|
||||
class AccountLoader extends StatelessWidget {
|
||||
class AccountLoader extends StatefulWidget {
|
||||
final Widget child;
|
||||
const AccountLoader({super.key, required this.child});
|
||||
|
||||
static final _logger = Logger('loader.account');
|
||||
@override
|
||||
State<AccountLoader> createState() => _AccountLoaderState();
|
||||
}
|
||||
|
||||
void _notifyErrorAndRedirect(BuildContext context, Object error) {
|
||||
class _AccountLoaderState extends State<AccountLoader> {
|
||||
AuthState? _handledState;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!context.mounted) return;
|
||||
postNotifyUserOfErrorX(
|
||||
context: context,
|
||||
errorSituation: AppLocalizations.of(context)!.errorLogin,
|
||||
exception: error,
|
||||
);
|
||||
navigateAndReplace(context, Pages.login);
|
||||
if (!mounted) return;
|
||||
Provider.of<AccountProvider>(context, listen: false).restoreIfPossible();
|
||||
});
|
||||
}
|
||||
|
||||
void _restoreAndHandleResult(BuildContext context, AccountProvider provider) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
try {
|
||||
await provider.restoreIfPossible();
|
||||
} catch (error, stack) {
|
||||
_logger.warning('Account restore failed: $error', error, stack);
|
||||
}
|
||||
if (!context.mounted) return;
|
||||
final latest = Provider.of<AccountProvider>(context, listen: false);
|
||||
if (latest.account != null) return;
|
||||
if (latest.error != null) {
|
||||
_notifyErrorAndRedirect(context, latest.error!);
|
||||
return;
|
||||
}
|
||||
if (!latest.isLoading) {
|
||||
navigateAndReplace(context, Pages.login);
|
||||
}
|
||||
});
|
||||
void _handleSideEffects(AccountProvider provider) {
|
||||
if (_handledState == provider.authState) return;
|
||||
_handledState = provider.authState;
|
||||
|
||||
void goToLogin() {
|
||||
if (!mounted) return;
|
||||
navigateAndReplace(context, Pages.login);
|
||||
}
|
||||
|
||||
switch (provider.authState) {
|
||||
case AuthState.error:
|
||||
final error = provider.error ?? Exception('Authorization failed');
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) return;
|
||||
postNotifyUserOfErrorX(
|
||||
context: context,
|
||||
errorSituation: AppLocalizations.of(context)!.errorLogin,
|
||||
exception: error,
|
||||
);
|
||||
goToLogin();
|
||||
});
|
||||
break;
|
||||
case AuthState.empty:
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => goToLogin());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<AccountProvider>(builder: (context, provider, _) {
|
||||
if (provider.account != null) return child;
|
||||
if (provider.error != null) {
|
||||
_notifyErrorAndRedirect(context, provider.error!);
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
_handleSideEffects(provider);
|
||||
if (provider.authState == AuthState.ready && provider.account != null) {
|
||||
return widget.child;
|
||||
}
|
||||
if (!provider.isLoading) {
|
||||
_restoreAndHandleResult(context, provider);
|
||||
}
|
||||
if (provider.isLoading) return const Center(child: CircularProgressIndicator());
|
||||
// In case of error or missing account we show loader while side effects handle navigation.
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,9 +4,6 @@ import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:pshared/provider/organizations.dart';
|
||||
|
||||
import 'package:pweb/app/router/pages.dart';
|
||||
import 'package:pweb/widgets/error/snackbar.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
|
||||
@@ -19,12 +16,20 @@ class OrganizationLoader extends StatelessWidget {
|
||||
Widget build(BuildContext context) => Consumer<OrganizationsProvider>(builder: (context, provider, _) {
|
||||
if (provider.isLoading) return const Center(child: CircularProgressIndicator());
|
||||
if (provider.error != null) {
|
||||
postNotifyUserOfErrorX(
|
||||
context: context,
|
||||
errorSituation: AppLocalizations.of(context)!.errorLogin,
|
||||
exception: provider.error!,
|
||||
final loc = AppLocalizations.of(context)!;
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(loc.errorLogin),
|
||||
const SizedBox(height: 12),
|
||||
ElevatedButton(
|
||||
onPressed: provider.load,
|
||||
child: Text(loc.retry),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
navigateAndReplace(context, Pages.login);
|
||||
}
|
||||
if ((provider.error == null) && (!provider.isOrganizationSet)) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
|
||||
@@ -5,9 +5,6 @@ import 'package:provider/provider.dart';
|
||||
import 'package:pshared/provider/account.dart';
|
||||
import 'package:pshared/provider/permissions.dart';
|
||||
|
||||
import 'package:pweb/app/router/pages.dart';
|
||||
import 'package:pweb/widgets/error/snackbar.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
|
||||
@@ -15,26 +12,38 @@ class PermissionsLoader extends StatelessWidget {
|
||||
final Widget child;
|
||||
const PermissionsLoader({super.key, required this.child});
|
||||
|
||||
void _notifyError(BuildContext context, Exception exception) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
postNotifyUserOfErrorX(
|
||||
context: context,
|
||||
errorSituation: AppLocalizations.of(context)!.errorLogin,
|
||||
exception: exception,
|
||||
);
|
||||
navigateAndReplace(context, Pages.login);
|
||||
});
|
||||
void _triggerLoadIfNeeded(PermissionsProvider provider) {
|
||||
if (!provider.isLoading && !provider.isReady) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!provider.isLoading && !provider.isReady) {
|
||||
provider.load();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer2<PermissionsProvider, AccountProvider>(
|
||||
builder: (context, provider, accountProvider, _) {
|
||||
if (provider.isLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
builder: (context, provider, _accountProvider, _) {
|
||||
if (provider.error != null) {
|
||||
_notifyError(context, provider.error!);
|
||||
final loc = AppLocalizations.of(context)!;
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(loc.errorLogin),
|
||||
const SizedBox(height: 12),
|
||||
ElevatedButton(
|
||||
onPressed: provider.load,
|
||||
child: Text(loc.retry),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
_triggerLoadIfNeeded(provider);
|
||||
if (provider.isLoading || !provider.isReady) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
return child;
|
||||
|
||||
Reference in New Issue
Block a user