chore: only show SSO login redirect dialog while fetching login token
This commit is contained in:
parent
768680178a
commit
765a83084c
2 changed files with 61 additions and 69 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue