import 'dart:convert'; import 'package:convert/convert.dart'; import 'package:crypto/crypto.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:geolocator/geolocator.dart'; import 'package:provider/provider.dart'; import '../config/api.dart'; import '../providers/auth_provider.dart'; import '../services/settings_service.dart'; class LoginScreen extends StatefulWidget { const LoginScreen({super.key}); @override State createState() => _LoginScreenState(); } class _LoginScreenState extends State with SingleTickerProviderStateMixin { late TabController _tabController; final TextEditingController _loginController = TextEditingController(); final TextEditingController _passwordController = TextEditingController(); final TextEditingController _secretKeyController = TextEditingController(); final TextEditingController _serverUrlController = TextEditingController(); @override void initState() { super.initState(); _tabController = TabController(length: 2, vsync: this); _tabController.addListener(() { setState(() {}); }); final settings = context.read(); _serverUrlController.text = settings.baseUrl; } @override void dispose() { _tabController.dispose(); _loginController.dispose(); _passwordController.dispose(); _secretKeyController.dispose(); _serverUrlController.dispose(); super.dispose(); } static const String _secretKey = 'FtracKer*1405.'; @override Widget build(BuildContext context) { final authProvider = context.watch(); final settings = context.read(); return Scaffold( resizeToAvoidBottomInset: true, body: SingleChildScrollView( child: Center( child: Card( margin: const EdgeInsets.all(24), child: Padding( padding: const EdgeInsets.all(24), child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 400), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const Text( 'Family Safety', textAlign: TextAlign.center, style: TextStyle( fontSize: 32, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 24), if (!kIsWeb) ...[ TextField( controller: _serverUrlController, decoration: const InputDecoration( labelText: 'Server URL', hintText: 'https://example.com/api', border: OutlineInputBorder(), prefixIcon: Icon(Icons.cloud_outlined), ), keyboardType: TextInputType.url, ), const SizedBox(height: 16), ], TabBar( controller: _tabController, tabs: const [ Tab(text: 'Login'), Tab(text: 'Register'), ], ), const SizedBox(height: 24), TextField( controller: _loginController, decoration: const InputDecoration( labelText: 'Login', border: OutlineInputBorder(), ), ), const SizedBox(height: 16), TextField( controller: _passwordController, decoration: const InputDecoration( labelText: 'Password', border: OutlineInputBorder(), ), obscureText: true, ), if (_tabController.index == 1) ...[ const SizedBox(height: 16), TextField( controller: _secretKeyController, decoration: const InputDecoration( labelText: 'Secret Key', border: OutlineInputBorder(), ), obscureText: true, ), ], const SizedBox(height: 16), if (authProvider.error.isNotEmpty) Text( authProvider.error, style: const TextStyle(color: Colors.red), ), const SizedBox(height: 16), ElevatedButton( onPressed: authProvider.isLoading ? null : () async { if (!kIsWeb) { final status = await Geolocator.checkPermission(); if (status == LocationPermission.denied) { final requested = await Geolocator.requestPermission(); if (requested == LocationPermission.denied) { authProvider.setError( 'Location permission denied', ); return; } } if (status == LocationPermission.deniedForever) { authProvider.setError( 'Location permission permanently denied. Please enable it in settings.', ); return; } } if (!kIsWeb) { final newUrl = _serverUrlController.text.trim(); if (newUrl.isNotEmpty && newUrl != settings.baseUrl) { ApiConfig.setBaseUrl(newUrl); await settings.setBaseUrl(newUrl); } } if (_tabController.index == 0) { try { await authProvider.login( _loginController.text, _passwordController.text, ); if (!context.mounted) return; Navigator.of( context, ).pushReplacementNamed('/map'); } catch (e) { // Error is handled by provider } } else { if (_secretKeyController.text != _secretKey) { authProvider.setError('Invalid secret key'); return; } Digest digest = md5.convert( utf8.encode(_secretKeyController.text), ); String secretKeyHash = hex.encode(digest.bytes); try { await authProvider.register( _loginController.text, _passwordController.text, secretKeyHash, ); } catch (e) { // Error is handled by provider } } }, child: authProvider.isLoading ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator(strokeWidth: 2), ) : Text( _tabController.index == 0 ? 'Login' : 'Register', ), ), ], ), ), ), ), ), ), ); } }