import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:google_sign_in/google_sign_in.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; import 'login_screen.dart'; import 'register_screen.dart'; import '../services/auth_service.dart'; import 'dart:io' show Platform; class AuthScreen extends StatefulWidget { const AuthScreen({super.key}); @override State createState() => _AuthScreenState(); } class _AuthScreenState extends State with SingleTickerProviderStateMixin { final SupabaseClient supabase = Supabase.instance.client; final AuthService _authService = AuthService(); late TabController _tabController; bool _isLoading = true; @override void initState() { super.initState(); debugPrint('AuthScreen initState started'); _tabController = TabController(length: 2, vsync: this); _setupAuthListener(); _checkAutoLogin(); debugPrint('AuthScreen initState completed'); } @override void dispose() { _tabController.dispose(); super.dispose(); } void _setupAuthListener() { supabase.auth.onAuthStateChange.listen((data) { final event = data.event; if (event == AuthChangeEvent.signedIn) { setState(() { _isLoading = false; }); // Navigate to home screen if (mounted) { Navigator.of(context).pushReplacementNamed('/home'); } } else if (event == AuthChangeEvent.signedOut) { setState(() { _isLoading = false; }); } }); } Future _checkAutoLogin() async { debugPrint('_checkAutoLogin started'); try { // Add timeout to prevent hanging await Future.any([ _performAutoLogin(), Future.delayed(const Duration(seconds: 10)), ]); debugPrint('_checkAutoLogin completed'); } catch (e) { debugPrint('_checkAutoLogin error: $e'); setState(() { _isLoading = false; }); } } Future _performAutoLogin() async { debugPrint('_performAutoLogin started'); // Check if user is already authenticated if (_authService.isAuthenticated) { debugPrint('User already authenticated, navigating to home'); setState(() { _isLoading = false; }); // Navigate to home screen immediately if (mounted) { Navigator.of(context).pushReplacementNamed('/home'); } return; } debugPrint('Attempting auto-login with saved credentials'); // Try auto-login with saved credentials final success = await _authService.autoLogin(); debugPrint('Auto-login result: $success'); setState(() { _isLoading = false; }); // Let the auth listener handle navigation if successful } Future googleSignInNative() async { /// TODO: update the Web client ID with your own. /// /// Web Client ID that you registered with Google Cloud. const webClientId = '311478513323-4vj6v6d254jbs8tt334u4874see8i4vj.apps.googleusercontent.com'; /// TODO: update the iOS client ID with your own. /// /// iOS Client ID that you registered with Google Cloud. const iosClientId = '311478513323-8j9q5oe77hnmcmn7i6qsq5r7t0krrlb1.apps.googleusercontent.com'; // Google sign in on Android will work without providing the Android // Client ID registered on Google Cloud. final GoogleSignIn signIn = GoogleSignIn( clientId: iosClientId, serverClientId: webClientId, ); final googleUser = await signIn.signIn(); if (googleUser == null) { throw Exception('Google sign-in was cancelled'); } final googleAuth = await googleUser.authentication; final accessToken = googleAuth.accessToken; final idToken = googleAuth.idToken; if(accessToken == null){ throw Exception('No access token found'); } if(idToken == null){ throw Exception('No id token found'); } final response = await supabase.auth.signInWithIdToken( provider: OAuthProvider.google, idToken: idToken, accessToken: accessToken, ); // Save user information after successful OAuth login final user = response.user; if (user != null) { final userName = googleUser.displayName ?? user.userMetadata?['name'] ?? 'User'; final userEmail = googleUser.email; await _authService.saveUserInfo( name: userName, email: userEmail, ); } return response; } Future oauthLoginWeb(OAuthProvider provider) async { await supabase.auth.signInWithOAuth( provider, redirectTo: kIsWeb ? null : 'com.Xperience.TaskTracker.tasktracker://callback', ); } Future login(String email, String password, bool rememberMe) async { await _authService.loginWithPassword( email: email, password: password, rememberMe: rememberMe, ); } Future register(String email, String password, String name, bool rememberMe) async { await _authService.registerUser( email: email, password: password, name: name, rememberMe: rememberMe, ); } Future logout() async { await _authService.logout(); } Future oAuthLogin(OAuthProvider provider) async { try { if(Platform.isAndroid && provider == OAuthProvider.google){ await googleSignInNative(); } else { await oauthLoginWeb(provider); } } catch (e) { // Handle OAuth login errors if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('OAuth login failed: ${e.toString()}'), backgroundColor: Colors.red, ), ); } } } @override Widget build(BuildContext context) { final screenHeight = MediaQuery.of(context).size.height; // Show loading screen while checking authentication if (_isLoading) { return Scaffold( backgroundColor: Colors.grey[50], body: const Center( child: CircularProgressIndicator(), ), ); } return Scaffold( backgroundColor: Colors.grey[50], body: SafeArea( child: SingleChildScrollView( child: Column( children: [ // Header Section Container( width: double.infinity, padding: const EdgeInsets.all(32.0), child: Column( children: [ const SizedBox(height: 40), // App Logo/Icon Container( width: 80, height: 80, decoration: BoxDecoration( color: Theme.of(context).primaryColor, borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Theme.of(context).primaryColor.withValues(alpha: 0.3), blurRadius: 20, offset: const Offset(0, 10), ), ], ), child: const Icon( Icons.task_alt, color: Colors.white, size: 40, ), ), const SizedBox(height: 24), Text( 'TaskTracker', style: GoogleFonts.poppins( fontSize: 32, fontWeight: FontWeight.bold, color: Colors.grey[800], ), ), const SizedBox(height: 8), Text( 'Manage your tasks efficiently', style: GoogleFonts.poppins( fontSize: 16, color: Colors.grey[600], ), ), ], ), ), // Tab Bar Container( margin: const EdgeInsets.symmetric(horizontal: 24), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.grey.withValues(alpha: 0.1), blurRadius: 10, offset: const Offset(0, 5), ), ], ), child: TabBar( controller: _tabController, indicator: BoxDecoration( borderRadius: BorderRadius.circular(20), color: Theme.of(context).primaryColor, ), indicatorSize: TabBarIndicatorSize.tab, // Make indicator fill the tab labelColor: Colors.white, unselectedLabelColor: Colors.grey[600], labelStyle: GoogleFonts.poppins( fontWeight: FontWeight.w600, fontSize: 16, ), unselectedLabelStyle: GoogleFonts.poppins( fontWeight: FontWeight.w500, fontSize: 16, ), tabs: const [ Tab(text: 'Login'), Tab(text: 'Register'), ], ), ), const SizedBox(height: 24), // Tab Views SizedBox( height: screenHeight * 0.8, child: TabBarView( controller: _tabController, children: [ LoginScreen( onLogin: login, onOAuthLogin: (provider) => oAuthLogin(provider), ), RegisterScreen( onRegister: register, onOAuthRegister: (provider) => oAuthLogin(provider), ), ], ), ), ], ), ), ), ); } }