Files
Holzleitner-Lieferservice-App/lib/feature/authentication/presentation/login_page.dart
2025-11-04 16:52:39 +01:00

185 lines
5.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:app_links/app_links.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hl_lieferservice/feature/authentication/bloc/auth_bloc.dart';
import 'package:hl_lieferservice/feature/authentication/bloc/auth_event.dart';
import 'package:url_launcher/url_launcher.dart';
import 'dart:async';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
State<StatefulWidget> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final _loginFormKey = GlobalKey<FormState>();
bool _isLoading = false;
late AppLinks _appLinks;
StreamSubscription<Uri>? _linkSubscription;
@override
void initState() {
super.initState();
_appLinks = AppLinks();
}
@override
void dispose() {
_linkSubscription?.cancel();
super.dispose();
}
void _onPressLogin() async {
setState(() => _isLoading = true);
try {
debugPrint("🔵 Setting up deep link listener...");
final completer = Completer<Uri>();
// Listen for deep links BEFORE opening browser
_linkSubscription = _appLinks.uriLinkStream.listen(
(Uri uri) {
debugPrint("🟢 Deep link received: $uri");
if (uri.scheme == 'myapp' && !completer.isCompleted) {
completer.complete(uri);
}
},
onError: (err) {
debugPrint("🔴 Deep link error: $err");
if (!completer.isCompleted) {
completer.completeError(err);
}
},
);
// Small delay to ensure listener is ready
await Future.delayed(const Duration(milliseconds: 500));
debugPrint("🔵 Opening browser to: http://localhost:3000/login");
final loginUrl = Uri.parse('http://192.168.1.9:3000/login');
final launched = await launchUrl(
loginUrl,
mode: LaunchMode.externalApplication,
);
if (!launched) {
throw Exception('Could not launch browser');
}
debugPrint("🔵 Browser opened. Waiting for callback...");
// Wait for the deep link callback
final callbackUri = await completer.future.timeout(
const Duration(minutes: 5),
onTimeout: () {
debugPrint("⏱️ Timeout - no callback received");
throw TimeoutException('Login timeout');
},
);
final sessionId = callbackUri.queryParameters['session_id']!;
debugPrint("✅ Success! Callback: $callbackUri");
debugPrint("✅ Session ID: $sessionId");
await _linkSubscription?.cancel();
_linkSubscription = null;
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Login erfolgreich!'),
backgroundColor: Colors.green,
),
);
context.read<AuthBloc>().add(SetAuthenticatedEvent(sessionId: sessionId));
}
} on TimeoutException {
debugPrint("❌ Timeout");
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Login Timeout')),
);
}
} catch (e) {
debugPrint("❌ Error: $e");
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Fehler: $e')),
);
}
} finally {
await _linkSubscription?.cancel();
_linkSubscription = null;
if (mounted) {
setState(() => _isLoading = false);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(50),
child: Column(
children: [
Image.asset(
"assets/holzleitner_Logo_2017_RZ_transparent.png",
),
const Padding(
padding: EdgeInsets.only(top: 20),
child: Text(
"Auslieferservice",
style: TextStyle(
fontWeight: FontWeight.w400,
fontSize: 20,
),
),
),
],
),
),
Form(
key: _loginFormKey,
child: FractionallySizedBox(
widthFactor: 0.8,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(top: 15, bottom: 15),
child: _isLoading
? const Column(
children: [
CircularProgressIndicator(),
SizedBox(height: 16),
Text('Warte auf Login...'),
],
)
: OutlinedButton(
onPressed: _onPressLogin,
child: const Text("Anmelden mit Holzleitner Login"),
),
),
],
),
),
),
],
),
),
);
}
}