1
0
forked from baron/baron-sso

fix userfront mobile approval close flow

This commit is contained in:
2026-05-21 18:14:31 +09:00
parent 66687a4c73
commit e54cc121c7
5 changed files with 100 additions and 30 deletions

View File

@@ -100,6 +100,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
_redirectUrl = widget.redirectUrl;
_passwordFocusNode.addListener(_handlePasswordFocusChange);
HardwareKeyboard.instance.addHandler(_handleHardwareKeyEvent);
_verificationOnly = _isVerificationOnlyUri(Uri.base);
WidgetsBinding.instance.addPostFrameCallback((_) async {
final uri = Uri.base;
@@ -127,8 +128,6 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
final hasVerificationToken =
widget.verificationToken != null || hasTokenParam;
final hasLoginCode = loginIdParam != null && codeParam != null;
_verificationOnly =
hasVerificationToken || hasLoginCode || hasShortCodePath;
final notice = uri.queryParameters['notice'];
if (hasShortCodePath) {
@@ -174,6 +173,15 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
});
}
bool _isVerificationOnlyUri(Uri uri) {
final loginIdParam = uri.queryParameters['loginId'];
final codeParam = uri.queryParameters['code'];
return widget.verificationToken != null ||
uri.queryParameters.containsKey('t') ||
(loginIdParam != null && codeParam != null) ||
extractLoginShortCode(uri) != null;
}
void _handlePasswordFocusChange() {
if (!mounted) {
return;
@@ -765,6 +773,12 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
_onVerificationAction?.call();
}
void _closeVerificationWindowIfPossible() {
if (webWindow.hasOpener()) {
webWindow.close();
}
}
Widget _buildVerificationResultView() {
return Center(
child: Padding(
@@ -802,7 +816,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
return;
}
if (_verificationOnly) {
webWindow.close();
_closeVerificationWindowIfPossible();
return;
}
final hasLocalSession =
@@ -827,6 +841,55 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
);
}
Widget _buildVerificationPendingView() {
return Center(
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
width: 48,
height: 48,
child: CircularProgressIndicator(strokeWidth: 4),
),
const SizedBox(height: 20),
Text(
tr('ui.userfront.login.verification.title_pending'),
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
Text(
tr('msg.userfront.login.verification.pending_remote'),
textAlign: TextAlign.center,
style: const TextStyle(color: Colors.black54),
),
],
),
),
);
}
Widget _buildVerificationOnlyScaffold() {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(_verificationPageTitle),
leading: _verificationApproved && _onVerificationAction != null
? IconButton(
icon: const Icon(Icons.close),
onPressed: _runVerificationExitAction,
)
: null,
actions: const [ThemeToggleButton(compact: true)],
),
body: _verificationApproved
? _buildVerificationResultView()
: _buildVerificationPendingView(),
);
}
Future<void> _verifyToken(String token) async {
debugPrint("[Auth] Starting verification for token: $token");
final approvedMessage = tr('msg.userfront.login.verification.approved');
@@ -858,7 +921,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
actionLabel: tr(
'ui.userfront.login.verification.action_label_close',
),
onAction: () => webWindow.close(),
onAction: _closeVerificationWindowIfPossible,
);
}
return;
@@ -894,7 +957,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
actionLabel: tr(
'ui.userfront.login.verification.action_label_close',
),
onAction: () => webWindow.close(),
onAction: _closeVerificationWindowIfPossible,
);
}
return;
@@ -951,7 +1014,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
actionLabel: tr(
'ui.userfront.login.verification.action_label_close',
),
onAction: () => webWindow.close(),
onAction: _closeVerificationWindowIfPossible,
);
}
return;
@@ -972,7 +1035,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
actionLabel: tr(
'ui.userfront.login.verification.action_label_close',
),
onAction: () => webWindow.close(),
onAction: _closeVerificationWindowIfPossible,
);
return;
}
@@ -985,7 +1048,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
remoteApprovedMessage,
title: tr('ui.userfront.login.verification.title_remote'),
actionLabel: tr('ui.userfront.login.verification.action_label_close'),
onAction: () => webWindow.close(),
onAction: _closeVerificationWindowIfPossible,
);
}
} catch (e) {
@@ -1005,7 +1068,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
actionLabel: tr(
'ui.userfront.login.verification.action_label_close',
),
onAction: () => webWindow.close(),
onAction: _closeVerificationWindowIfPossible,
);
}
return;
@@ -1053,7 +1116,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
actionLabel: tr(
'ui.userfront.login.verification.action_label_close',
),
onAction: () => webWindow.close(),
onAction: _closeVerificationWindowIfPossible,
);
}
return;
@@ -1074,7 +1137,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
actionLabel: tr(
'ui.userfront.login.verification.action_label_close',
),
onAction: () => webWindow.close(),
onAction: _closeVerificationWindowIfPossible,
);
return;
}
@@ -1087,7 +1150,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
remoteApprovedMessage,
title: tr('ui.userfront.login.verification.title_remote'),
actionLabel: tr('ui.userfront.login.verification.action_label_close'),
onAction: () => webWindow.close(),
onAction: _closeVerificationWindowIfPossible,
);
}
} catch (e) {
@@ -1105,7 +1168,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
actionLabel: tr(
'ui.userfront.login.verification.action_label_close',
),
onAction: () => webWindow.close(),
onAction: _closeVerificationWindowIfPossible,
);
}
return;
@@ -1609,21 +1672,8 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
),
);
if (_verificationOnly && _verificationApproved) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(_verificationPageTitle),
leading: _onVerificationAction == null
? null
: IconButton(
icon: const Icon(Icons.close),
onPressed: _runVerificationExitAction,
),
actions: const [ThemeToggleButton(compact: true)],
),
body: _buildVerificationResultView(),
);
if (_verificationOnly) {
return _buildVerificationOnlyScaffold();
}
return Scaffold(