diff --git a/lib/main.dart b/lib/main.dart index dd51bf1..aa743b6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,7 @@ import 'package:aranduapp/config/ThemeApp.dart'; import 'package:aranduapp/ui/login/view/LoginView.dart'; +import 'package:aranduapp/ui/navbar/view/navBarView.dart'; +import 'package:aranduapp/ui/profile/view/ProfileView.dart'; import 'package:aranduapp/ui/welcome/view/WelcomeView.dart'; import 'package:flutter/material.dart'; diff --git a/lib/ui/edit_profile/view/EditProfileView.dart b/lib/ui/edit_profile/view/EditProfileView.dart index ec55fcb..9bae7af 100644 --- a/lib/ui/edit_profile/view/EditProfileView.dart +++ b/lib/ui/edit_profile/view/EditProfileView.dart @@ -1,10 +1,10 @@ -import 'package:aranduapp/ui/shared/TextName.dart'; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; - import 'package:aranduapp/ui/edit_profile/viewModel/EditProfileViewModel.dart'; import 'package:aranduapp/ui/shared/TextEmail.dart'; +import 'package:aranduapp/ui/shared/ProfileHeader.dart'; +import 'package:aranduapp/ui/shared/TextName.dart'; import 'package:aranduapp/ui/shared/TextPassword.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class EditProfile extends StatelessWidget { const EditProfile({super.key}); @@ -18,61 +18,109 @@ class EditProfile extends StatelessWidget { } } -class EditProfileScreen extends StatefulWidget { - const EditProfileScreen({Key? key}) : super(key: key); - - @override - State createState() => _EditProfileScreenState(); -} - -class _EditProfileScreenState extends State { +class EditProfileScreen extends StatelessWidget { + const EditProfileScreen({super.key}); @override Widget build(BuildContext context) { final viewModel = Provider.of(context); return Scaffold( appBar: AppBar( - title: const Text('Editar Perfil'), + backgroundColor: Theme.of(context).colorScheme.surface, + elevation: 0, + title: Center( + child: Text( + 'Editar perfil', + style: TextStyle( + color: Theme.of(context).colorScheme.onSurface, + fontSize: 24, + ), + ), + ), + actions: [ + IconButton( + color: Theme.of(context).colorScheme.primary, + icon: const Icon(Icons.notifications), + onPressed: () {}, + ), + ], + leading: IconButton( + color: Theme.of(context).colorScheme.primary, + icon: const Icon(Icons.arrow_back), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ), + body: LayoutBuilder( + builder: (context, constraints) { + final isSmallScreen = constraints.maxWidth < 600; + return SingleChildScrollView( + padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20), + child: Column( + children: [ + _buildProfileHeader(context), + SizedBox(height: isSmallScreen ? 30 : 50), + _buildForm(context, viewModel, isSmallScreen), + ], + ), + ); + }, ), - body: _buildForm(viewModel) ); } - Widget _buildForm(EditProfileViewModel viewModel) { - return SingleChildScrollView( - padding: const EdgeInsets.all(16.0), - child: Form( - key: viewModel.formKey, - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - - TextName( - controller: viewModel.firstNameController, - padding: const EdgeInsets.symmetric(vertical: 16) - ), - - TextEmail( - padding: const EdgeInsets.symmetric(vertical: 16), - controller: viewModel.emailController, - ), - - TextPassWord( - padding: const EdgeInsets.symmetric(vertical: 16), - controller: viewModel.passwordController, - ), - - const SizedBox(height: 32), - _saveButton(viewModel), - const SizedBox(height: 16), - _deleteButton(context), - ], - ), + Widget _buildForm(BuildContext context, EditProfileViewModel viewModel, + bool isSmallScreen) { + return Form( + key: viewModel.formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + TextName( + controller: viewModel.firstNameController, + padding: const EdgeInsets.symmetric(vertical: 0), + ), + const SizedBox(height: 20), + TextEmail( + padding: const EdgeInsets.symmetric(vertical: 0), + controller: viewModel.emailController, + ), + const SizedBox(height: 20), + TextPassWord( + padding: const EdgeInsets.symmetric(vertical: 0), + controller: viewModel.passwordController, + ), + SizedBox(height: isSmallScreen ? 100 : 56), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Expanded( + child: _saveButton(context, viewModel), + ), + SizedBox(width: isSmallScreen ? 10 : 20), + Expanded( + child: _deleteButton(context), + ), + ], + ), + ], ), ); } - Widget _saveButton(EditProfileViewModel viewModel) { + Widget _buildProfileHeader(BuildContext context) { + return const Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ProfileHeader( + name: "Stefani", + role: "Estudante", + ), + ]); + } + + Widget _saveButton(BuildContext context, EditProfileViewModel viewModel) { return ElevatedButton( onPressed: () async { if (viewModel.isLoading) return; @@ -87,19 +135,23 @@ class _EditProfileScreenState extends State { ); } }, - + style: ElevatedButton.styleFrom( + minimumSize: Size(0, 50), + ), child: Consumer( builder: (context, value, child) => value.isLoading ? const CircularProgressIndicator(value: null) : const Text('Salvar'), ), - ); } Widget _deleteButton(BuildContext context) { return ElevatedButton( onPressed: () => _showDeleteConfirmationDialog(context), + style: ElevatedButton.styleFrom( + minimumSize: Size(0, 50), + ), child: const Text('Deletar Conta'), ); } diff --git a/lib/ui/edit_profile/viewModel/EditProfileViewModel.dart b/lib/ui/edit_profile/viewModel/EditProfileViewModel.dart index ca2e67d..9b8f33b 100644 --- a/lib/ui/edit_profile/viewModel/EditProfileViewModel.dart +++ b/lib/ui/edit_profile/viewModel/EditProfileViewModel.dart @@ -1,3 +1,4 @@ +import 'package:aranduapp/core/log/Log.dart'; import 'package:flutter/material.dart'; class EditProfileViewModel extends ChangeNotifier { diff --git a/lib/ui/navbar/view/navBarView.dart b/lib/ui/navbar/view/navBarView.dart index 10eba37..2460990 100644 --- a/lib/ui/navbar/view/navBarView.dart +++ b/lib/ui/navbar/view/navBarView.dart @@ -1,4 +1,6 @@ import 'package:aranduapp/ui/home/view/HomeView.dart'; +import 'package:aranduapp/ui/profile/view/ProfileView.dart'; +//import 'package:aranduapp/ui/profile/view/profileView.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:aranduapp/ui/navbar/model/navBarViewModel.dart'; @@ -25,7 +27,7 @@ Widget page(BuildContext context) { const HomeView(), const Center(child: Text('Friends', style: TextStyle(fontSize: 20))), const Center(child: Text('Dashbord', style: TextStyle(fontSize: 20))), - const Center(child: Text('Profile', style: TextStyle(fontSize: 20))), + const Profile(), ]; return Scaffold( @@ -34,7 +36,7 @@ Widget page(BuildContext context) { currentIndex: viewModel.selectedIndex, onTap: viewModel.changeTab, selectedItemColor: Theme.of(context).colorScheme.primary, - unselectedItemColor:Theme.of(context).colorScheme.onSurface, + unselectedItemColor: Theme.of(context).colorScheme.onSurface, items: const [ BottomNavigationBarItem( icon: Icon(Icons.home_outlined), diff --git a/lib/ui/profile/view/Profile.dart b/lib/ui/profile/view/Profile.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/ui/profile/view/ProfileView.dart b/lib/ui/profile/view/ProfileView.dart new file mode 100644 index 0000000..236c69b --- /dev/null +++ b/lib/ui/profile/view/ProfileView.dart @@ -0,0 +1,115 @@ +import 'package:provider/provider.dart'; +import 'package:flutter/material.dart'; + +import 'package:aranduapp/ui/shared/ProfileHeader.dart'; +import 'package:aranduapp/ui/profile/viewModel/ProfileViewModel.dart'; +import 'package:aranduapp/ui/edit_profile/view/EditProfileView.dart'; + +class Profile extends StatelessWidget { + const Profile({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: _buildAppBar(context), + body: ChangeNotifierProvider( + create: (context) => ProfileViewModel(context), + builder: (context, child) { + return _buildPage(context); + }, + ), + ); + } + + /// AppBar + AppBar _buildAppBar(BuildContext context) { + return AppBar( + backgroundColor: Theme.of(context).colorScheme.onPrimary, + scrolledUnderElevation: 0, + title: Text( + 'Perfil', + style: Theme.of(context).textTheme.headlineSmall?.copyWith( + color: Theme.of(context).colorScheme.onSurface, + ), + ), + centerTitle: true, + actions: [ + Padding( + padding: const EdgeInsets.only(right: 16.0), + child: Container( + child: Center( + child: Icon( + Icons.notifications_none_outlined, + color: Theme.of(context).colorScheme.primary, + size: 32, + ), + ), + ), + ), + ], + ); + } + + /// Página principal + Widget _buildPage(BuildContext context) { + return SingleChildScrollView( + child: Center( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildProfileHeader(context), + const SizedBox(height: 80), + _buildLogoutButton(context), + ], + ), + ), + ); + } + + /// Cabeçalho do Perfil + Widget _buildProfileHeader(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ProfileHeader( + name: "Stefani", + role: "Estudante", + ), + Padding( + padding: const EdgeInsets.only(right: 16.0), // Margem direita + child: ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const EditProfile()), + ); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.primary, + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), + elevation: 2, + ), + child: Text( + "Editar", + style: Theme.of(context).textTheme.bodySmall!.apply( + color: Theme.of(context).colorScheme.onPrimary, + ), + ), + ), + ), + ], + ); + } + + /// Botão Deslogar + Widget _buildLogoutButton(BuildContext context) { + return SizedBox( + width: 291, + height: 64, + child: ElevatedButton( + onPressed: () => {}, + child: const Text('Deslogar'), + ), + ); + } +} diff --git a/lib/ui/profile/viewModel/ProfileViewModel.dart b/lib/ui/profile/viewModel/ProfileViewModel.dart new file mode 100644 index 0000000..dfa1c59 --- /dev/null +++ b/lib/ui/profile/viewModel/ProfileViewModel.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +class ProfileViewModel extends ChangeNotifier { + final BuildContext context; + + // Controllers e Key para o formulário + final GlobalKey formKey = GlobalKey(); + final TextEditingController emailController = TextEditingController(); + + // Estado de carregamento + bool _isLoading = false; + bool get isLoading => _isLoading; + + ProfileViewModel(this.context); + + // Método para simular o envio do e-mail de recuperação de senha + Future forgetPassword() async { + // Verifica se o formulário é válido + if (!formKey.currentState!.validate()) { + return; + } + + _setLoading(true); + + try { + // Simulação de chamada de API + await Future.delayed(const Duration(seconds: 2)); + + // Validações ou chamadas reais para a API iriam aqui + final email = emailController.text.trim(); + if (email.isEmpty) { + throw Exception("O campo de e-mail não pode estar vazio."); + } + + // Log fictício para simular sucesso + debugPrint("E-mail de recuperação enviado para: $email"); + } catch (e) { + // Relança a exceção para que o consumidor exiba o erro + throw Exception("Erro ao enviar o e-mail: $e"); + } finally { + _setLoading(false); + } + } + + // Define o estado de carregamento e notifica os ouvintes + void _setLoading(bool value) { + _isLoading = value; + notifyListeners(); + } + + // Destruir controllers ao finalizar a ViewModel + @override + void dispose() { + emailController.dispose(); + super.dispose(); + } +} diff --git a/lib/ui/shared/ProfileHeader.dart b/lib/ui/shared/ProfileHeader.dart new file mode 100644 index 0000000..c5067c1 --- /dev/null +++ b/lib/ui/shared/ProfileHeader.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; + +class ProfileHeader extends StatelessWidget { + final String name; + final String role; + + const ProfileHeader({ + Key? key, + required this.name, + required this.role, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(16.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + // Imagem circular + texto + Row( + children: [ + // Imagem circular + Container( + width: 80, + height: 80, + decoration: BoxDecoration( + color: + Theme.of(context).colorScheme.primary, // Cor cinza claro + shape: BoxShape.circle, + ), + ), + const SizedBox(width: 16), + // Nome e descrição + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + name, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.onSurface, + ), + ), + const SizedBox(height: 4), + Text( + role, + style: const TextStyle( + fontSize: 16, + color: Colors.grey, + ), + ), + ], + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/ui/shared/ProfileSection.dart b/lib/ui/shared/ProfileSection.dart new file mode 100644 index 0000000..3a0953a --- /dev/null +++ b/lib/ui/shared/ProfileSection.dart @@ -0,0 +1,126 @@ +import 'package:flutter/material.dart'; + +class ProfileSection extends StatefulWidget { + final String title; + final List items; + + const ProfileSection({ + super.key, + required this.title, + required this.items, + }); + + @override + State createState() => _ProfileSectionState(); +} + +class _ProfileSectionState extends State { + final Map switchStates = {}; + + @override + void initState() { + super.initState(); + for (int i = 0; i < widget.items.length; i++) { + switchStates[i] = widget.items[i].switchValue ?? false; + } + } + + @override + Widget build(BuildContext context) { + return Container( + margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.1), + blurRadius: 6, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.title, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + const SizedBox(height: 8), + ...widget.items.map((item) { + int index = widget.items.indexOf(item); + return Column( + children: [ + _buildMenuItem(context, item, index), + if (index < widget.items.length - 1) + const Divider( + color: Colors.grey, + thickness: 0.5, + ), + ], + ); + }).toList(), + ], + ), + ); + } + + Widget _buildMenuItem(BuildContext context, ProfileLinkItem item, int index) { + return ListTile( + leading: Icon( + item.icon, + color: Colors.orange, + ), + title: Text( + item.name, + style: const TextStyle( + fontSize: 16, + color: Colors.black87, + ), + ), + trailing: item.hasSwitch + ? Switch( + value: switchStates[index]!, + onChanged: (value) { + setState(() { + switchStates[index] = value; + }); + if (item.onSwitchChanged != null) { + item.onSwitchChanged!(value); + } + }, + activeColor: Colors.white, + ) + : IconButton( + icon: const Icon(Icons.chevron_right), + color: Colors.black, + onPressed: item.onTap, + ), + onTap: item.onTap, + ); + } +} + +class ProfileLinkItem { + final IconData icon; + final String name; + final VoidCallback? onTap; + final bool hasSwitch; + final bool? switchValue; + final ValueChanged? onSwitchChanged; + + ProfileLinkItem({ + required this.icon, + required this.name, + this.onTap, + this.hasSwitch = false, + this.switchValue, + this.onSwitchChanged, + }); +}