diff --git a/lib/constants/app_strings.dart b/lib/constants/app_strings.dart index 1aed80a..3cd0c19 100644 --- a/lib/constants/app_strings.dart +++ b/lib/constants/app_strings.dart @@ -1,19 +1,31 @@ +import 'package:flutter/material.dart'; + enum AppLanguage { pt, en, es } class AppStrings { - static AppLanguage _currentLanguage = AppLanguage.pt; + static final ValueNotifier languageNotifier = ValueNotifier(AppLanguage.pt); + + static AppLanguage get currentLanguage => languageNotifier.value; static void setLanguage(String language) { if (language == 'English') { - _currentLanguage = AppLanguage.en; + languageNotifier.value = AppLanguage.en; } else if (language == 'Español') { - _currentLanguage = AppLanguage.es; + languageNotifier.value = AppLanguage.es; } else { - _currentLanguage = AppLanguage.pt; + languageNotifier.value = AppLanguage.pt; } } - static String get _lang => _currentLanguage.name; + static String get currentLanguageName { + switch (languageNotifier.value) { + case AppLanguage.en: return 'English'; + case AppLanguage.es: return 'Español'; + case AppLanguage.pt: return 'Português'; + } + } + + static String get _lang => languageNotifier.value.name; static String _get(Map values) => values[_lang] ?? values['pt']!; @@ -162,6 +174,7 @@ class AppStrings { static String get btnOk => _get({'pt': "OK", 'en': "OK", 'es': "OK"}); static String get btnCancel => _get({'pt': "Cancelar", 'en': "Cancel", 'es': "Cancelar"}); static String get btnDefine => _get({'pt': "DEFINIR", 'en': "DEFINE", 'es': "DEFINIR"}); + static String get profileUpdated => _get({'pt': "Perfil atualizado!", 'en': "Profile updated!", 'es': "¡Perfil actualizado!"}); // Logado Screen static String get defineDailyGoal => _get({'pt': "Definir Meta Diária", 'en': "Set Daily Goal", 'es': "Definir Meta Diaria"}); diff --git a/lib/main.dart b/lib/main.dart index 0baca23..d457037 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -15,33 +15,22 @@ void main() async { class MyApp extends StatelessWidget { const MyApp({super.key}); - // This widget is the root of your application. @override Widget build(BuildContext context) { - return MaterialApp( - title: AppStrings.appTitle, - debugShowCheckedModeBanner: false, - theme: ThemeData( - // This is the theme of your application. - // - // TRY THIS: Try running your application with "flutter run". You'll see - // the application has a purple toolbar. Then, without quitting the app, - // try changing the seedColor in the colorScheme below to Colors.green - // and then invoke "hot reload" (save your changes or press the "hot - // reload" button in a Flutter-supported IDE, or press "r" if you used - // the command line to start the app). - // - // Notice that the counter didn't reset back to zero; the application - // state is not lost during the reload. To reset the state, use hot - // restart instead. - // - // This works for code too, not just values: Most code changes can be - // tested with just a hot reload. - colorScheme: ColorScheme.fromSeed( - seedColor: Colors.white.withValues(alpha: 0.1), - ), - ), - home: const InicialScreen(), + return ValueListenableBuilder( + valueListenable: AppStrings.languageNotifier, + builder: (context, language, child) { + return MaterialApp( + title: AppStrings.appTitle, + debugShowCheckedModeBanner: false, + theme: ThemeData( + colorScheme: ColorScheme.fromSeed( + seedColor: Colors.white.withValues(alpha: 0.1), + ), + ), + home: const InicialScreen(), + ); + }, ); } } diff --git a/lib/screens/logado_screen.dart b/lib/screens/logado_screen.dart index ef6685f..abd4dc9 100644 --- a/lib/screens/logado_screen.dart +++ b/lib/screens/logado_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import '../constants/app_colors.dart'; import '../constants/app_strings.dart'; import '../services/supabase_service.dart'; @@ -16,10 +17,10 @@ class LogadoScreen extends StatefulWidget { class _LogadoScreenState extends State { // Estado dinâmico do utilizador - double _dailyGoal = 0.0; // 0.0 significa que ainda não foi definida + double _dailyGoal = 0.0; double _currentDistance = 0.0; - double _bestDistance = 12.4; // Exemplo de recorde - double _bestSpeed = 16.8; // Exemplo de recorde + double _bestDistance = 12.4; + double _bestSpeed = 16.8; int _steps = 0; int _totalTimeMinutes = 0; @@ -32,15 +33,38 @@ class _LogadoScreenState extends State { } Future _loadUserData() async { - // No futuro, aqui buscaríamos os dados reais do Supabase ou Local Storage + final prefs = await SharedPreferences.getInstance(); + final lastGoalDate = prefs.getString('last_goal_date'); + final today = DateTime.now().toIso8601String().split('T')[0]; + setState(() { - // Simulação de dados carregados - _currentDistance = 0.0; // Começa o dia a zero + // Reset meta se o dia mudou + if (lastGoalDate != today) { + _dailyGoal = 0.0; + prefs.remove('daily_goal'); + } else { + _dailyGoal = prefs.getDouble('daily_goal') ?? 0.0; + } + + // No futuro, estes viriam do Supabase ou histórico local + _currentDistance = 0.0; _steps = 0; _totalTimeMinutes = 0; }); } + Future _saveGoal(double goal) async { + final prefs = await SharedPreferences.getInstance(); + final today = DateTime.now().toIso8601String().split('T')[0]; + + await prefs.setDouble('daily_goal', goal); + await prefs.setString('last_goal_date', today); + + setState(() { + _dailyGoal = goal; + }); + } + void _showGoalDialog() { showDialog( context: context, @@ -54,9 +78,7 @@ class _LogadoScreenState extends State { ...[5, 10, 15, 20].map((km) => ListTile( title: Text("$km ${AppStrings.kmUnit}", style: const TextStyle(color: Colors.white)), onTap: () { - setState(() { - _dailyGoal = km.toDouble(); - }); + _saveGoal(km.toDouble()); Navigator.pop(context); }, )), @@ -107,9 +129,7 @@ class _LogadoScreenState extends State { onPressed: () { final value = double.tryParse(controller.text); if (value != null && value > 0) { - setState(() { - _dailyGoal = value; - }); + _saveGoal(value); Navigator.pop(context); } }, @@ -126,194 +146,187 @@ class _LogadoScreenState extends State { @override Widget build(BuildContext context) { - final user = SupabaseService.currentUser; - final userName = user?.userMetadata?['name'] ?? user?.email?.split('@')[0] ?? AppStrings.userPlaceholder; + return ValueListenableBuilder( + valueListenable: AppStrings.languageNotifier, + builder: (context, language, child) { + final user = SupabaseService.currentUser; + final userName = user?.userMetadata?['name'] ?? user?.email?.split('@')[0] ?? AppStrings.userPlaceholder; - return Scaffold( - backgroundColor: AppColors.background, - body: Stack( - children: [ - // Background Gradient - Positioned.fill( - child: Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [Color(0xFF2D2D31), AppColors.background], - ), - ), - ), - ), - - SafeArea( - child: Column( - children: [ - // Header Bar - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - AppStrings.welcome.toUpperCase(), - style: const TextStyle( - color: Colors.white38, - fontSize: 10, - fontWeight: FontWeight.w900, - letterSpacing: 2, - ), - ), - Text( - userName, - style: const TextStyle( - color: Colors.white, - fontSize: 24, - fontWeight: FontWeight.w900, - letterSpacing: -0.5, - ), - ), - ], - ), - Row( - children: [ - _buildIconButton( - Icons.bluetooth_audio_rounded, - () => Navigator.push(context, MaterialPageRoute(builder: (context) => const BluetoothConnectionScreen())), - ), - const SizedBox(width: 12), - _buildIconButton( - Icons.settings_rounded, - () => Navigator.push(context, MaterialPageRoute(builder: (context) => const SettingsScreen())), - ), - ], - ), - ], - ), - ), - - Expanded( - child: SingleChildScrollView( - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 20), - - // Main Tracking Card (Meta Diária) - _buildMainTrackingCard(), - - const SizedBox(height: 30), - - // Personal Bests Section - Text( - AppStrings.personalRecords, - style: const TextStyle( - color: Colors.white38, - fontSize: 11, - fontWeight: FontWeight.w900, - letterSpacing: 1.5, - ), - ), - const SizedBox(height: 15), - Row( - children: [ - Expanded( - child: _buildRecordCard( - AppStrings.bestDistance, - _bestDistance.toStringAsFixed(1), - AppStrings.kmUnit, - Icons.auto_graph_rounded, - AppColors.coral, - ), - ), - const SizedBox(width: 15), - Expanded( - child: _buildRecordCard( - AppStrings.bestSpeed, - _bestSpeed.toStringAsFixed(1), - AppStrings.kmhUnit, - Icons.speed_rounded, - Colors.cyanAccent, - ), - ), - ], - ), - - const SizedBox(height: 25), - - // Steps Section (Atividade Geral) - Text( - AppStrings.generalActivity, - style: const TextStyle( - color: Colors.white38, - fontSize: 11, - fontWeight: FontWeight.w900, - letterSpacing: 1.5, - ), - ), - const SizedBox(height: 15), - _buildWideRecordCard( - AppStrings.steps, - _steps.toString(), - AppStrings.stepsToday, - Icons.directions_walk_rounded, - AppColors.success, - ), - - const SizedBox(height: 120), // Espaço para o botão inferior - ], + return Scaffold( + backgroundColor: AppColors.background, + body: Stack( + children: [ + Positioned.fill( + child: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [Color(0xFF2D2D31), AppColors.background], ), ), ), - ], - ), - ), - - // Bottom Action Button - Positioned( - bottom: 30, - left: 50, - right: 50, - child: Container( - height: 70, - decoration: BoxDecoration( - boxShadow: [ - BoxShadow( - color: AppColors.coral.withValues(alpha: 0.3), - blurRadius: 25, - spreadRadius: -5, - ) - ], ), - child: ElevatedButton( - onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (context) => const GoogleMapScreen())), - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.coral, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)), - elevation: 0, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, + + SafeArea( + child: Column( children: [ - const Icon(Icons.play_arrow_rounded, size: 30), - const SizedBox(width: 10), - Text( - AppStrings.startTraining, - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w900, letterSpacing: 1.5), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + AppStrings.welcome.toUpperCase(), + style: const TextStyle( + color: Colors.white38, + fontSize: 10, + fontWeight: FontWeight.w900, + letterSpacing: 2, + ), + ), + Text( + userName, + style: const TextStyle( + color: Colors.white, + fontSize: 24, + fontWeight: FontWeight.w900, + letterSpacing: -0.5, + ), + ), + ], + ), + Row( + children: [ + _buildIconButton( + Icons.bluetooth_audio_rounded, + () => Navigator.push(context, MaterialPageRoute(builder: (context) => const BluetoothConnectionScreen())), + ), + const SizedBox(width: 12), + _buildIconButton( + Icons.settings_rounded, + () => Navigator.push(context, MaterialPageRoute(builder: (context) => const SettingsScreen())), + ), + ], + ), + ], + ), + ), + + Expanded( + child: SingleChildScrollView( + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + _buildMainTrackingCard(), + const SizedBox(height: 30), + Text( + AppStrings.personalRecords, + style: const TextStyle( + color: Colors.white38, + fontSize: 11, + fontWeight: FontWeight.w900, + letterSpacing: 1.5, + ), + ), + const SizedBox(height: 15), + Row( + children: [ + Expanded( + child: _buildRecordCard( + AppStrings.bestDistance, + _bestDistance.toStringAsFixed(1), + AppStrings.kmUnit, + Icons.auto_graph_rounded, + AppColors.coral, + ), + ), + const SizedBox(width: 15), + Expanded( + child: _buildRecordCard( + AppStrings.bestSpeed, + _bestSpeed.toStringAsFixed(1), + AppStrings.kmhUnit, + Icons.speed_rounded, + Colors.cyanAccent, + ), + ), + ], + ), + const SizedBox(height: 25), + Text( + AppStrings.generalActivity, + style: const TextStyle( + color: Colors.white38, + fontSize: 11, + fontWeight: FontWeight.w900, + letterSpacing: 1.5, + ), + ), + const SizedBox(height: 15), + _buildWideRecordCard( + AppStrings.steps, + _steps.toString(), + AppStrings.stepsToday, + Icons.directions_walk_rounded, + AppColors.success, + ), + const SizedBox(height: 120), + ], + ), + ), ), ], ), ), - ), + + Positioned( + bottom: 30, + left: 50, + right: 50, + child: Container( + height: 70, + decoration: BoxDecoration( + boxShadow: [ + BoxShadow( + color: AppColors.coral.withValues(alpha: 0.3), + blurRadius: 25, + spreadRadius: -5, + ) + ], + ), + child: ElevatedButton( + onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (context) => const GoogleMapScreen())), + style: ElevatedButton.styleFrom( + backgroundColor: AppColors.coral, + foregroundColor: Colors.white, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)), + elevation: 0, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.play_arrow_rounded, size: 30), + const SizedBox(width: 10), + Text( + AppStrings.startTraining, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w900, letterSpacing: 1.5), + ), + ], + ), + ), + ), + ), + ], ), - ], - ), + ); + }, ); } @@ -352,9 +365,25 @@ class _LogadoScreenState extends State { style: const TextStyle(color: Colors.white54, fontWeight: FontWeight.bold, letterSpacing: 1), ), if (_dailyGoal > 0) - Text( - "${(_progress * 100).toInt()}%", - style: const TextStyle(color: AppColors.coral, fontWeight: FontWeight.w900), + GestureDetector( + onTap: _showGoalDialog, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), + decoration: BoxDecoration( + color: AppColors.coral.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(10), + ), + child: Row( + children: [ + Text( + "${(_progress * 100).toInt()}%", + style: const TextStyle(color: AppColors.coral, fontWeight: FontWeight.w900), + ), + const SizedBox(width: 5), + const Icon(Icons.edit_rounded, color: AppColors.coral, size: 14), + ], + ), + ), ), ], ), diff --git a/lib/screens/setting_screen.dart b/lib/screens/setting_screen.dart index 3c4f95a..85fc897 100644 --- a/lib/screens/setting_screen.dart +++ b/lib/screens/setting_screen.dart @@ -11,9 +11,13 @@ class SettingsScreen extends StatefulWidget { } class _SettingsScreenState extends State { - bool _isNightMode = true; - bool _notificationsEnabled = true; - String _selectedLanguage = 'Português'; + late String _selectedLanguage; + + @override + void initState() { + super.initState(); + _selectedLanguage = AppStrings.currentLanguageName; + } @override Widget build(BuildContext context) { @@ -93,12 +97,7 @@ class _SettingsScreenState extends State { IconButton( icon: const Icon(Icons.edit, color: AppColors.buttonColor), onPressed: () { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(AppStrings.editProfile), - backgroundColor: AppColors.buttonColor, - ), - ); + _showEditProfileDialog(context, userName, userEmail); }, ), ], @@ -115,28 +114,6 @@ class _SettingsScreenState extends State { ), child: Column( children: [ - _buildSettingsItem( - icon: Icons.schedule, - title: AppStrings.adjustDateTime, - onTap: () { - _showDatePicker(context); - }, - ), - _buildDivider(), - _buildSettingsItem( - icon: Icons.dark_mode, - title: AppStrings.nightMode, - trailing: Switch( - value: _isNightMode, - activeThumbColor: AppColors.buttonColor, - onChanged: (value) { - setState(() { - _isNightMode = value; - }); - }, - ), - ), - _buildDivider(), _buildSettingsItem( icon: Icons.language, title: AppStrings.language, @@ -152,59 +129,6 @@ class _SettingsScreenState extends State { }, ), _buildDivider(), - _buildSettingsItem( - icon: Icons.accessibility, - title: AppStrings.accessibility, - onTap: () { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(AppStrings.accessibility), - backgroundColor: AppColors.buttonColor, - ), - ); - }, - ), - _buildDivider(), - _buildSettingsItem( - icon: Icons.notifications, - title: AppStrings.notifications, - trailing: Switch( - value: _notificationsEnabled, - onChanged: (value) { - setState(() { - _notificationsEnabled = value; - }); - }, - activeThumbColor: AppColors.buttonColor, - ), - ), - _buildDivider(), - _buildSettingsItem( - icon: Icons.privacy_tip, - title: AppStrings.privacySecurity, - onTap: () { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(AppStrings.privacySecurity), - backgroundColor: AppColors.buttonColor, - ), - ); - }, - ), - _buildDivider(), - _buildSettingsItem( - icon: Icons.description, - title: AppStrings.termsOfUse, - onTap: () { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(AppStrings.termsOfUse), - backgroundColor: AppColors.buttonColor, - ), - ); - }, - ), - _buildDivider(), _buildSettingsItem( icon: Icons.info, title: AppStrings.about, @@ -278,39 +202,42 @@ class _SettingsScreenState extends State { ); } - void _showDatePicker(BuildContext context) { - showDatePicker( - context: context, - initialDate: DateTime.now(), - firstDate: DateTime(2020), - lastDate: DateTime(2025), - ).then((date) { - if (date != null && mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('${AppStrings.dateSelected}: ${date.toString().split(' ')[0]}'), - backgroundColor: AppColors.buttonColor, - ), - ); - } - }); - } + void _showEditProfileDialog(BuildContext context, String currentName, String currentEmail) { + final nameController = TextEditingController(text: currentName); + final emailController = TextEditingController(text: currentEmail); - void _showLanguageSelector(BuildContext context) { showDialog( context: context, builder: (context) => AlertDialog( backgroundColor: AppColors.backgroundGrey, title: Text( - AppStrings.selectLanguage, + AppStrings.editProfile, style: const TextStyle(color: Colors.white), ), content: Column( mainAxisSize: MainAxisSize.min, children: [ - _buildLanguageOption('Português'), - _buildLanguageOption('English'), - _buildLanguageOption('Español'), + TextField( + controller: nameController, + style: const TextStyle(color: Colors.white), + decoration: InputDecoration( + labelText: AppStrings.labelName, + labelStyle: const TextStyle(color: Colors.white70), + enabledBorder: const UnderlineInputBorder(borderSide: BorderSide(color: Colors.white24)), + focusedBorder: const UnderlineInputBorder(borderSide: BorderSide(color: AppColors.buttonColor)), + ), + ), + const SizedBox(height: 16), + TextField( + controller: emailController, + style: const TextStyle(color: Colors.white), + decoration: InputDecoration( + labelText: AppStrings.labelEmail, + labelStyle: const TextStyle(color: Colors.white70), + enabledBorder: const UnderlineInputBorder(borderSide: BorderSide(color: Colors.white24)), + focusedBorder: const UnderlineInputBorder(borderSide: BorderSide(color: AppColors.buttonColor)), + ), + ), ], ), actions: [ @@ -318,15 +245,74 @@ class _SettingsScreenState extends State { onPressed: () => Navigator.pop(context), child: Text( AppStrings.btnCancel, - style: const TextStyle(color: AppColors.buttonColor), + style: const TextStyle(color: Colors.white54), ), ), + ElevatedButton( + onPressed: () async { + try { + await SupabaseService.updateProfile( + name: nameController.text.trim(), + email: emailController.text.trim(), + ); + if (context.mounted) { + Navigator.pop(context); + setState(() {}); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Perfil atualizado!'), backgroundColor: Colors.green), + ); + } + } catch (e) { + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(e.toString()), backgroundColor: Colors.red), + ); + } + } + }, + style: ElevatedButton.styleFrom(backgroundColor: AppColors.buttonColor), + child: Text(AppStrings.btnDefine), + ), ], ), ); } - Widget _buildLanguageOption(String language) { + void _showLanguageSelector(BuildContext context) { + showDialog( + context: context, + builder: (context) => StatefulBuilder( + builder: (context, setDialogState) { + return AlertDialog( + backgroundColor: AppColors.backgroundGrey, + title: Text( + AppStrings.selectLanguage, + style: const TextStyle(color: Colors.white), + ), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + _buildLanguageOption(context, setDialogState, 'Português'), + _buildLanguageOption(context, setDialogState, 'English'), + _buildLanguageOption(context, setDialogState, 'Español'), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text( + AppStrings.btnCancel, + style: const TextStyle(color: AppColors.buttonColor), + ), + ), + ], + ); + } + ), + ); + } + + Widget _buildLanguageOption(BuildContext context, StateSetter setDialogState, String language) { return ListTile( title: Text(language, style: const TextStyle(color: Colors.white)), trailing: Radio( @@ -334,28 +320,26 @@ class _SettingsScreenState extends State { groupValue: _selectedLanguage, onChanged: (value) { if (value != null) { - setState(() { - _selectedLanguage = value; - AppStrings.setLanguage(value); - }); + _updateLanguage(value); Navigator.pop(context); - // Force rebuild of current screen to apply changes - setState(() {}); } }, fillColor: WidgetStateProperty.all(AppColors.buttonColor), ), onTap: () { - setState(() { - _selectedLanguage = language; - AppStrings.setLanguage(language); - }); + _updateLanguage(language); Navigator.pop(context); - setState(() {}); }, ); } + void _updateLanguage(String language) { + setState(() { + _selectedLanguage = language; + AppStrings.setLanguage(language); + }); + } + void _showAboutDialog(BuildContext context) { showDialog( context: context, diff --git a/lib/services/supabase_service.dart b/lib/services/supabase_service.dart index 16a4f1b..941c6cf 100644 --- a/lib/services/supabase_service.dart +++ b/lib/services/supabase_service.dart @@ -2,27 +2,19 @@ import 'package:supabase_flutter/supabase_flutter.dart'; import '../constants/app_constants.dart'; class SupabaseService { - static final SupabaseClient _supabase = Supabase.instance.client; + static SupabaseClient get _supabase => Supabase.instance.client; // Initialize Supabase static Future initialize() async { try { print('DEBUG: Inicializando Supabase...'); - print('DEBUG: URL: ${AppConstants.supabaseUrl}'); - print( - 'DEBUG: AnonKey: ${AppConstants.supabaseAnonKey.substring(0, 10)}...', - ); - + await Supabase.initialize( url: AppConstants.supabaseUrl, anonKey: AppConstants.supabaseAnonKey, ); print('DEBUG: Supabase inicializado com sucesso!'); - - // Test connection - final currentUser = _supabase.auth.currentUser; - print('DEBUG: Usuário atual: ${currentUser?.email ?? 'null'}'); } catch (e) { print('DEBUG: Erro ao inicializar Supabase: $e'); rethrow; @@ -39,26 +31,18 @@ class SupabaseService { required String name, }) async { try { - print('DEBUG: Criando conta - Email: $email, Name: $name'); - final response = await _supabase.auth.signUp( email: email, password: password, data: {'name': name}, ); - print('DEBUG: Conta criada! User ID: ${response.user?.id}'); - - // Check if user was created successfully if (response.user != null) { - print('DEBUG: Usuário criado com sucesso!'); return response; } else { - print('DEBUG: Falha ao criar usuário - response.user é null'); - throw Exception('Falha ao criar usuário. Tente novamente.'); + throw Exception('Falha ao criar usuário.'); } } catch (e) { - print('DEBUG: Erro no signUp: $e'); throw Exception('Erro ao criar conta: $e'); } } @@ -69,17 +53,11 @@ class SupabaseService { required String password, }) async { try { - print('DEBUG: Fazendo login - Email: $email'); - - final response = await _supabase.auth.signInWithPassword( + return await _supabase.auth.signInWithPassword( email: email, password: password, ); - - print('DEBUG: Login realizado! User ID: ${response.user?.id}'); - return response; } catch (e) { - print('DEBUG: Erro no signIn: $e'); throw Exception('Erro ao fazer login: $e'); } } @@ -88,9 +66,7 @@ class SupabaseService { static Future signOut() async { try { await _supabase.auth.signOut(); - print('DEBUG: Logout realizado'); } catch (e) { - print('DEBUG: Erro no signOut: $e'); throw Exception('Erro ao sair: $e'); } } @@ -99,27 +75,34 @@ class SupabaseService { static Future resetPassword(String email) async { try { await _supabase.auth.resetPasswordForEmail(email); - print('DEBUG: Email de reset enviado para: $email'); } catch (e) { - print('DEBUG: Erro no resetPassword: $e'); throw Exception('Erro ao redefinir senha: $e'); } } + // Update user profile + static Future updateProfile({String? name, String? email}) async { + try { + final updates = {}; + if (name != null) updates['name'] = name; + + final userAttributes = UserAttributes( + data: updates.isNotEmpty ? updates : null, + email: email, + ); + + await _supabase.auth.updateUser(userAttributes); + } catch (e) { + throw Exception('Erro ao atualizar perfil: $e'); + } + } + // Test connection to Supabase static Future testConnection() async { try { - print('DEBUG: Testando conexão com Supabase...'); - - // Test with auth service instead of database final session = _supabase.auth.currentSession; - print('DEBUG: Sessão atual: ${session != null ? 'ativa' : 'null'}'); - - // Try to get auth settings (this should work even without tables) - print('DEBUG: Conexão básica funcionando!'); return true; } catch (e) { - print('DEBUG: Erro na conexão: $e'); return false; } } diff --git a/lib/sheets/entrar_sheet.dart b/lib/sheets/entrar_sheet.dart index 88b0e50..1e03daf 100644 --- a/lib/sheets/entrar_sheet.dart +++ b/lib/sheets/entrar_sheet.dart @@ -33,7 +33,7 @@ class _EntrarSheetState extends State { // Show success message above the sheet ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( + SnackBar( content: Text(AppStrings.loginSuccess), backgroundColor: Colors.green, ), @@ -66,7 +66,7 @@ class _EntrarSheetState extends State { final email = _emailController.text.trim(); if (email.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( + SnackBar( content: Text(AppStrings.validatorEmailEmpty), backgroundColor: Colors.orange, ), @@ -82,7 +82,7 @@ class _EntrarSheetState extends State { // Show success message above the sheet ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( + SnackBar( content: Text(AppStrings.resetPasswordEmailSent), backgroundColor: Colors.green, ), @@ -115,7 +115,7 @@ class _EntrarSheetState extends State { minChildSize: 0.4, // 40% minimum maxChildSize: 0.9, // 90% maximum snap: true, // Enable snap points - snapSizes: [0.6, 0.9], // Snap to 60% or 90% + snapSizes: const [0.6, 0.9], // Snap to 60% or 90% builder: (context, scrollController) { return Container( decoration: BoxDecoration( @@ -151,9 +151,9 @@ class _EntrarSheetState extends State { const SizedBox(height: 24), // Title - const Text( + Text( AppStrings.loginTitle, - style: TextStyle( + style: const TextStyle( fontSize: 28, fontWeight: FontWeight.bold, color: Colors.white, @@ -162,9 +162,9 @@ class _EntrarSheetState extends State { const SizedBox(height: 32), // Email field - const Text( + Text( AppStrings.labelEmail, - style: TextStyle(fontSize: 16, color: Colors.white70), + style: const TextStyle(fontSize: 16, color: Colors.white70), ), const SizedBox(height: 8), Form( @@ -196,9 +196,9 @@ class _EntrarSheetState extends State { const SizedBox(height: 20), // Password field - const Text( + Text( AppStrings.labelPassword, - style: TextStyle(fontSize: 16, color: Colors.white70), + style: const TextStyle(fontSize: 16, color: Colors.white70), ), const SizedBox(height: 8), TextFormField( @@ -245,9 +245,9 @@ class _EntrarSheetState extends State { ? const CircularProgressIndicator( color: Colors.white, ) - : const Text( + : Text( AppStrings.btnLogin, - style: TextStyle( + style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w600, ), @@ -260,9 +260,9 @@ class _EntrarSheetState extends State { Center( child: TextButton( onPressed: _handlePasswordReset, - child: const Text( + child: Text( AppStrings.forgotPassword, - style: TextStyle(color: Colors.white70, fontSize: 16), + style: const TextStyle(color: Colors.white70, fontSize: 16), ), ), ), diff --git a/pubspec.lock b/pubspec.lock index 396dc00..889f011 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -85,10 +85,10 @@ packages: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" clock: dependency: transitive description: @@ -548,18 +548,18 @@ packages: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.19" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" url: "https://pub.dev" source: hosted - version: "0.11.1" + version: "0.13.0" meta: dependency: transitive description: @@ -945,10 +945,10 @@ packages: dependency: transitive description: name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" url: "https://pub.dev" source: hosted - version: "0.7.7" + version: "0.7.10" typed_data: dependency: transitive description: