chore: only show SSO login redirect dialog while fetching login token

This commit is contained in:
ggurdin 2026-01-19 12:33:52 -05:00
parent 768680178a
commit 765a83084c
No known key found for this signature in database
GPG key ID: A01CB41737CBB478
2 changed files with 61 additions and 69 deletions

View file

@ -9,12 +9,12 @@ import 'package:matrix/matrix.dart';
import 'package:universal_html/html.dart' as html;
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pages/homeserver_picker/homeserver_picker.dart';
import 'package:fluffychat/pangea/common/utils/firebase_analytics.dart';
import 'package:fluffychat/pangea/login/sso_provider_enum.dart';
import 'package:fluffychat/pangea/login/widgets/p_sso_dialog.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/fluffy_chat_app.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
import 'package:fluffychat/widgets/matrix.dart';
class PangeaSsoButton extends StatelessWidget {
@ -27,23 +27,25 @@ class PangeaSsoButton extends StatelessWidget {
super.key,
});
Future<void> _runSSOLogin(BuildContext context) => showAdaptiveDialog(
context: context,
builder: (context) => SSODialog(
future: () => _ssoAction(
IdentityProvider(
id: provider.id,
name: provider.name,
),
context,
),
),
);
Future<void> _runSSOLogin(BuildContext context) async {
final token = await showAdaptiveDialog<String?>(
context: context,
builder: (context) => SSODialog(
future: () => _getSSOToken(context),
),
);
Future<void> _ssoAction(
IdentityProvider provider,
BuildContext context,
) async {
if (token == null || token.isEmpty) {
return;
}
await showFutureLoadingDialog(
context: context,
future: () => _ssoAction(token, context),
);
}
Future<String?> _getSSOToken(BuildContext context) async {
final bool isDefaultPlatform = (PlatformInfos.isMobile ||
PlatformInfos.isWeb ||
PlatformInfos.isMacOS);
@ -58,7 +60,7 @@ class PangeaSsoButton extends StatelessWidget {
: 'http://localhost:3001//login';
final client = await Matrix.of(context).getLoginClient();
final url = client.homeserver!.replace(
path: '/_matrix/client/v3/login/sso/redirect/${provider.id ?? ''}',
path: '/_matrix/client/v3/login/sso/redirect/${provider.id}',
queryParameters: {'redirectUrl': redirectUrl},
);
@ -74,13 +76,20 @@ class PangeaSsoButton extends StatelessWidget {
} catch (err) {
if (err is PlatformException && err.code == 'CANCELED') {
debugPrint("user cancelled SSO login");
return;
return null;
}
rethrow;
}
final token = Uri.parse(result).queryParameters['loginToken'];
if (token?.isEmpty ?? false) return;
if (token?.isEmpty ?? false) return null;
return token;
}
Future<void> _ssoAction(
String token,
BuildContext context,
) async {
final client = Matrix.of(context).client;
final redirect = client.onLoginStateChanged.stream
.where((state) => state == LoginState.loggedIn)
.first
@ -110,7 +119,7 @@ class PangeaSsoButton extends StatelessWidget {
await redirect;
}
GoogleAnalytics.login(provider.name!, loginRes.userId);
GoogleAnalytics.login(provider.name, loginRes.userId);
}
@override

View file

@ -5,11 +5,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_linkify/flutter_linkify.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/utils/url_launcher.dart';
class SSODialog extends StatefulWidget {
final Future<void> Function() future;
final Future<String?> Function() future;
const SSODialog({
super.key,
required this.future,
@ -22,7 +21,6 @@ class SSODialog extends StatefulWidget {
class SSODialogState extends State<SSODialog> {
Timer? _hintTimer;
bool _showHint = false;
Object? _error;
@override
void initState() {
@ -43,9 +41,10 @@ class SSODialogState extends State<SSODialog> {
Future<void> _runFuture() async {
try {
await widget.future();
final token = await widget.future();
Navigator.of(context).pop(token);
} catch (e) {
setState(() => _error = e);
Navigator.of(context).pop();
}
}
@ -69,17 +68,11 @@ class SSODialogState extends State<SSODialog> {
icon: const Icon(Icons.close),
),
),
_error == null
? Text(
L10n.of(context).ssoDialogTitle,
style: Theme.of(context).textTheme.headlineMedium,
textAlign: TextAlign.center,
)
: Icon(
Icons.error_outline_outlined,
color: Theme.of(context).colorScheme.error,
size: 48,
),
Text(
L10n.of(context).ssoDialogTitle,
style: Theme.of(context).textTheme.headlineMedium,
textAlign: TextAlign.center,
),
Container(
alignment: Alignment.center,
constraints: const BoxConstraints(minHeight: 150),
@ -88,39 +81,29 @@ class SSODialogState extends State<SSODialog> {
spacing: 16.0,
mainAxisSize: MainAxisSize.min,
children: [
if (_error != null)
Text(
_error!.toLocalizedString(context),
style: Theme.of(context).textTheme.titleMedium,
textAlign: TextAlign.center,
)
else ...[
SelectableLinkify(
text: L10n.of(context).ssoDialogDesc,
textScaleFactor:
MediaQuery.textScalerOf(context).scale(1),
linkStyle: TextStyle(
color: Theme.of(context).colorScheme.primary,
decorationColor: Theme.of(context).colorScheme.primary,
),
options: const LinkifyOptions(humanize: false),
onOpen: (url) =>
UrlLauncher(context, url.url).launchUrl(),
style: Theme.of(context).textTheme.bodyLarge,
textAlign: TextAlign.center,
SelectableLinkify(
text: L10n.of(context).ssoDialogDesc,
textScaleFactor: MediaQuery.textScalerOf(context).scale(1),
linkStyle: TextStyle(
color: Theme.of(context).colorScheme.primary,
decorationColor: Theme.of(context).colorScheme.primary,
),
_showHint
? Text(
L10n.of(context).ssoDialogHelpText,
style: Theme.of(context).textTheme.bodyLarge,
textAlign: TextAlign.center,
)
: const SizedBox(
height: 16.0,
width: 16.0,
child: CircularProgressIndicator.adaptive(),
),
],
options: const LinkifyOptions(humanize: false),
onOpen: (url) => UrlLauncher(context, url.url).launchUrl(),
style: Theme.of(context).textTheme.bodyLarge,
textAlign: TextAlign.center,
),
_showHint
? Text(
L10n.of(context).ssoDialogHelpText,
style: Theme.of(context).textTheme.bodyLarge,
textAlign: TextAlign.center,
)
: const SizedBox(
height: 16.0,
width: 16.0,
child: CircularProgressIndicator.adaptive(),
),
],
),
),