1
0
forked from baron/baron-sso

Merge branch 'dev/qr'

This commit is contained in:
2026-01-20 15:38:16 +09:00
14 changed files with 186 additions and 71 deletions

View File

@@ -67,7 +67,7 @@ class _CreateUserScreenState extends State<CreateUserScreen> {
// If cancelled or empty
if (inputPassword == null || inputPassword.isEmpty) {
if (mounted) context.go('/dashboard'); // Kick out
if (mounted) context.go('/'); // Kick out
return;
}
@@ -88,7 +88,7 @@ class _CreateUserScreenState extends State<CreateUserScreen> {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Invalid Password. Access Denied.'), backgroundColor: Colors.red),
);
context.go('/dashboard'); // Kick out
context.go('/'); // Kick out
}
}
}
@@ -152,7 +152,7 @@ class _CreateUserScreenState extends State<CreateUserScreen> {
title: const Text('Create User'),
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () => context.go('/dashboard'),
onPressed: () => context.go('/'),
),
),
body: Center(

View File

@@ -78,7 +78,7 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
);
if (inputPassword == null || inputPassword.isEmpty) {
if (mounted) context.go('/dashboard');
if (mounted) context.go('/');
return;
}
@@ -97,7 +97,7 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
} else {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Invalid Password'), backgroundColor: Colors.red));
context.go('/dashboard');
context.go('/');
}
}
}
@@ -277,7 +277,7 @@ class _UserManagementScreenState extends State<UserManagementScreen> with Single
title: const Text('User Management'),
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () => context.go('/dashboard'),
onPressed: () => context.go('/'),
),
bottom: TabBar(
controller: _tabController,

View File

@@ -22,7 +22,7 @@ class _ApproveQrScreenState extends State<ApproveQrScreen> {
final session = Descope.sessionManager.session;
if (session == null || session.refreshToken.isExpired) {
setState(() => _message = "Please log in on your phone first.");
context.go('/'); // Redirect to login
context.go('/login'); // Redirect to login
return;
}
@@ -43,7 +43,7 @@ class _ApproveQrScreenState extends State<ApproveQrScreen> {
// Automatically go to dashboard after a short delay
Future.delayed(const Duration(seconds: 1), () {
if (mounted) context.go('/dashboard');
if (mounted) context.go('/');
});
} catch (e) {
setState(() => _message = "Error: $e");
@@ -103,14 +103,14 @@ class _ApproveQrScreenState extends State<ApproveQrScreen> {
Padding(
padding: const EdgeInsets.only(top: 16),
child: TextButton(
onPressed: () => context.go('/'),
onPressed: () => context.go('/login'),
child: const Text("Login on this device first"),
),
),
if (_success)
FilledButton(
onPressed: () => context.go('/dashboard'),
onPressed: () => context.go('/'),
child: const Text("Go to My Dashboard"),
),
],

View File

@@ -449,25 +449,30 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
details: "User logged in via Baron SSO",
);
// 1. Handle Redirect Flow (Redirect to another app)
if (_redirectUrl != null && _redirectUrl!.isNotEmpty) {
final target = "$_redirectUrl?token=$token";
launchUrlString(target, webOnlyWindowName: '_self');
return;
// 1. Handle Popup Flow (Highest Priority for child windows)
// If opened as a popup (has opener), we notify and try to close.
if (WebAuthIntegration.isPopup()) {
debugPrint("[Auth] Popup detected. Notifying opener and attempting to close.");
WebAuthIntegration.sendLoginSuccess(token);
// We don't 'return' here to allow a fallback if window.close() is blocked,
// but in most cases WebAuthIntegration.sendLoginSuccess will close the window.
} else {
// 2. Handle Redirect Flow (Only if NOT a popup)
if (_redirectUrl != null && _redirectUrl!.isNotEmpty) {
debugPrint("[Auth] Redirecting standalone window to: $_redirectUrl");
final target = "$_redirectUrl?token=$token";
launchUrlString(target, webOnlyWindowName: '_self');
return;
}
}
// 2. Handle Popup Flow (Send message to opener)
if (WebAuthIntegration.isPopup()) {
WebAuthIntegration.sendLoginSuccess(token);
// If this window was truly a popup for another app, it should close now.
// If it's still here, we allow it to fall through to the dashboard.
}
// 3. Standalone mode: Go to dashboard
// We call notify() to update the router's state, and go() to ensure navigation.
// 3. Standalone mode / Fallback
// If it's a standard login, or if a popup's window.close() was blocked by the browser.
debugPrint("[Auth] Login success. Navigating to root.");
AuthNotifier.instance.notify();
if (mounted) {
context.go('/dashboard');
context.go('/');
}
}

View File

@@ -34,7 +34,7 @@ class LoginSuccessScreen extends StatelessWidget {
// 이 버튼이 QR 카메라를 켜는 버튼입니다.
FilledButton.icon(
onPressed: () {
context.push('/qr-scan');
context.push('/scan');
},
icon: const Icon(Icons.camera_alt, size: 28),
label: const Text("QR 인증 (카메라 켜기)"),
@@ -50,7 +50,7 @@ class LoginSuccessScreen extends StatelessWidget {
const SizedBox(height: 24),
TextButton(
onPressed: () {
context.go('/dashboard');
context.go('/');
},
child: const Text("나중에 하기 (대시보드로 이동)", style: TextStyle(color: Colors.grey)),
),

View File

@@ -25,7 +25,7 @@ class DashboardScreen extends StatelessWidget {
return Scaffold(
backgroundColor: Colors.grey[50],
appBar: AppBar(
title: Text('Baron Launcher', style: GoogleFonts.outfit(fontWeight: FontWeight.bold)),
title: Text('Baron SSO', style: GoogleFonts.outfit(fontWeight: FontWeight.bold)),
elevation: 0,
backgroundColor: Colors.white,
foregroundColor: Colors.black,