185 lines
5.3 KiB
Dart
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"),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
} |