feat: auto close login browser

This commit is contained in:
edde746
2025-10-25 16:31:36 +02:00
parent 127b3ba2e4
commit 3ad3876474
2 changed files with 43 additions and 3 deletions
+36 -2
View File
@@ -15,6 +15,7 @@ class _AuthScreenState extends State<AuthScreen> {
bool _isAuthenticating = false;
String? _errorMessage;
late PlexAuthService _authService;
bool _shouldCancelPolling = false;
@override
void initState() {
@@ -30,6 +31,7 @@ class _AuthScreenState extends State<AuthScreen> {
setState(() {
_isAuthenticating = true;
_errorMessage = null;
_shouldCancelPolling = false;
});
try {
@@ -49,8 +51,16 @@ class _AuthScreenState extends State<AuthScreen> {
throw Exception('Could not launch auth URL');
}
// Poll for authentication
final token = await _authService.pollPinUntilClaimed(pinId);
// Poll for authentication with cancellation support
final token = await _authService.pollPinUntilClaimed(
pinId,
shouldCancel: () => _shouldCancelPolling,
);
// If polling was cancelled, don't show error
if (_shouldCancelPolling) {
return;
}
if (token == null) {
setState(() {
@@ -60,6 +70,13 @@ class _AuthScreenState extends State<AuthScreen> {
return;
}
// Auto-close the in-app browser on mobile (no-op on desktop)
try {
await closeInAppWebView();
} catch (e) {
// Ignore errors - browser might already be closed or on desktop
}
// Store the token
final storage = await StorageService.getInstance();
await storage.savePlexToken(token);
@@ -84,6 +101,15 @@ class _AuthScreenState extends State<AuthScreen> {
}
}
void _retryAuthentication() {
setState(() {
_shouldCancelPolling = true;
_isAuthenticating = false;
});
// Start new authentication after a brief delay to ensure cleanup
Future.delayed(const Duration(milliseconds: 100), _startAuthentication);
}
@override
Widget build(BuildContext context) {
return Scaffold(
@@ -117,6 +143,14 @@ class _AuthScreenState extends State<AuthScreen> {
textAlign: TextAlign.center,
style: TextStyle(color: Colors.grey),
),
const SizedBox(height: 24),
OutlinedButton(
onPressed: _retryAuthentication,
style: OutlinedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 24),
),
child: const Text('Retry'),
),
] else ...[
ElevatedButton(
onPressed: _startAuthentication,
+7 -1
View File
@@ -109,11 +109,17 @@ class PlexAuthService {
/// Poll the PIN until it's claimed or timeout
Future<String?> pollPinUntilClaimed(
int pinId, {
Duration timeout = const Duration(minutes: 5),
Duration timeout = const Duration(minutes: 2),
bool Function()? shouldCancel,
}) async {
final endTime = DateTime.now().add(timeout);
while (DateTime.now().isBefore(endTime)) {
// Check if polling should be cancelled
if (shouldCancel != null && shouldCancel()) {
return null;
}
final token = await checkPin(pinId);
if (token != null) {
return token;