From 73a18123e488944f5da6be41c7da7f76a3d4ad39 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:56:59 +0100 Subject: [PATCH 001/123] First structure of the front Most of the widgets are set up but there is no end-point configured --- lib/phonebook/class/association.dart | 37 +++++ lib/phonebook/class/completeMember.dart | 46 ++++++ lib/phonebook/class/member.dart | 58 +++++++ lib/phonebook/class/post.dart | 48 ++++++ lib/phonebook/class/role.dart | 38 +++++ .../providers/association_provider.dart | 15 ++ lib/phonebook/providers/member_provider.dart | 15 ++ .../providers/phonebook_page_provider.dart | 16 ++ lib/phonebook/providers/post_provider.dart | 16 ++ lib/phonebook/providers/role_provider.dart | 15 ++ lib/phonebook/tools/constants.dart | 9 ++ lib/phonebook/ui/page_switcher.dart | 37 +++++ .../ui/pages/admin_page/admin_page.dart | 45 ++++++ .../association_editor_page.dart | 83 ++++++++++ .../association_page/association_page.dart | 74 +++++++++ .../ui/pages/main_page/main_page.dart | 146 ++++++++++++++++++ .../member_detail_page.dart | 61 ++++++++ .../role_member_page/role_member_page.dart | 80 ++++++++++ .../ui/pages/role_page/role_page.dart | 11 ++ lib/phonebook/ui/phonebook.dart | 67 ++++++++ lib/phonebook/ui/top_bar.dart | 77 +++++++++ 21 files changed, 994 insertions(+) create mode 100644 lib/phonebook/class/association.dart create mode 100644 lib/phonebook/class/completeMember.dart create mode 100644 lib/phonebook/class/member.dart create mode 100644 lib/phonebook/class/post.dart create mode 100644 lib/phonebook/class/role.dart create mode 100644 lib/phonebook/providers/association_provider.dart create mode 100644 lib/phonebook/providers/member_provider.dart create mode 100644 lib/phonebook/providers/phonebook_page_provider.dart create mode 100644 lib/phonebook/providers/post_provider.dart create mode 100644 lib/phonebook/providers/role_provider.dart create mode 100644 lib/phonebook/tools/constants.dart create mode 100644 lib/phonebook/ui/page_switcher.dart create mode 100644 lib/phonebook/ui/pages/admin_page/admin_page.dart create mode 100644 lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart create mode 100644 lib/phonebook/ui/pages/association_page/association_page.dart create mode 100644 lib/phonebook/ui/pages/main_page/main_page.dart create mode 100644 lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart create mode 100644 lib/phonebook/ui/pages/role_member_page/role_member_page.dart create mode 100644 lib/phonebook/ui/pages/role_page/role_page.dart create mode 100644 lib/phonebook/ui/phonebook.dart create mode 100644 lib/phonebook/ui/top_bar.dart diff --git a/lib/phonebook/class/association.dart b/lib/phonebook/class/association.dart new file mode 100644 index 000000000..a5628b34d --- /dev/null +++ b/lib/phonebook/class/association.dart @@ -0,0 +1,37 @@ +class Association{ + Association({ + required this.id, + required this.name, + }); + + late final String id; + late final String name; + + Association.fromJSON(Map json){ + id = json['id']; + name = json['name']; + } + + Map toJSON(){ + final data = { + 'id': id, + 'name': name, + }; + return data; + } + + Association copyWith({ + String? id, + String? name, + }) { + return Association( + id: id ?? this.id, + name: name ?? this.name, + ); + } + + Association.empty(){ + id = ""; + name = ""; + } +} \ No newline at end of file diff --git a/lib/phonebook/class/completeMember.dart b/lib/phonebook/class/completeMember.dart new file mode 100644 index 000000000..b239e4a6d --- /dev/null +++ b/lib/phonebook/class/completeMember.dart @@ -0,0 +1,46 @@ +import 'package:flutter/widgets.dart'; +import 'package:myecl/phonebook/class/post.dart'; +import 'package:tuple/tuple.dart'; +import 'role.dart'; +import 'association.dart'; +import 'member.dart'; + +class CompleteMember{ + CompleteMember({ + required this.member, + required this.post, + }); + + late final Member member; + late final List post; + + + CompleteMember.fromJSON(Map json){ + member = json['user']; + post = json['post']; + } + + Map toJSON(){ + final data = { + 'member': member.id, + 'post': post.map((e) => [e.association.id, e.role.id]), + }; + return data; + } + + CompleteMember copyWith({ + Member? member, + List? post, + }) { + return CompleteMember( + member: member ?? this.member, + post: post ?? this.post, + ); + } + + CompleteMember.empty(){ + member = Member.empty(); + post = []; + } + +} diff --git a/lib/phonebook/class/member.dart b/lib/phonebook/class/member.dart new file mode 100644 index 000000000..2eff486c3 --- /dev/null +++ b/lib/phonebook/class/member.dart @@ -0,0 +1,58 @@ +class Member{ + Member({ + required this.name, + required this.firstname, + required this.nickname, + required this.id, + required this.email, + }); + + late final String name; + late final String firstname; + late final String? nickname; + late final String id; + late final String email; + + Member.fromJSON(Map json){ + name = json['name']; + firstname = json['firstname']; + nickname = json['nickname']; + id = json['id']; + email = json['email']; + } + + Map toJSON(){ + final data = { + 'name': name, + 'firstname': firstname, + 'nickname': nickname, + 'id': id, + 'email': email, + }; + return data; + } + + Member copyWith({ + String? name, + String? firstname, + String? nickname, + String? id, + String? email, + }) { + return Member( + name: name ?? this.name, + firstname: firstname ?? this.firstname, + nickname: nickname, + id: id ?? this.id, + email: email ?? this.email, + ); + } + + Member.empty(){ + name = "nom"; + firstname = "prénom"; + nickname = null; + id = ""; + email = ""; + } +} \ No newline at end of file diff --git a/lib/phonebook/class/post.dart b/lib/phonebook/class/post.dart new file mode 100644 index 000000000..0a9e5e538 --- /dev/null +++ b/lib/phonebook/class/post.dart @@ -0,0 +1,48 @@ +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/class/role.dart'; + +class Post{ + Post({ + required this.association, + required this.role, + }); + + late final Association association; + late final Role role; + + Post.fromJSON(Map json){ + association = json['association']; + role = json['role']; + } + + Map toJSON(){ + final data = { + 'association': association.id, + 'role': role.id, + }; + return data; + } + + Post copyWith({ + Association? association, + Role? role, + }) { + return Post( + association: association ?? this.association, + role: role ?? this.role, + ); + } + + Post.empty(){ + association = Association.empty(); + role = Role.empty(); + } + + Post setAssociation(String name, String id) { + return copyWith(association: association.copyWith(name: name, id: id)); + } + + Post setRole(String name, String id) { + return copyWith(role: role.copyWith(name: name, id: id)); + } +} \ No newline at end of file diff --git a/lib/phonebook/class/role.dart b/lib/phonebook/class/role.dart new file mode 100644 index 000000000..262ff5217 --- /dev/null +++ b/lib/phonebook/class/role.dart @@ -0,0 +1,38 @@ +class Role{ + Role({ + required this.id, + required this.name, + }); + + late final String id; + late final String name; + + Role.fromJSON(Map json){ + id = json['id']; + name = json['name']; + } + + Map toJSON(){ + final data = { + 'id': id, + 'name': name, + }; + return data; + } + + Role copyWith({ + String? id, + String? name, + }) { + return Role( + id: id ?? this.id, + name: name ?? this.name, + ); + } + + Role.empty(){ + id = ""; + name = ""; + } + +} \ No newline at end of file diff --git a/lib/phonebook/providers/association_provider.dart b/lib/phonebook/providers/association_provider.dart new file mode 100644 index 000000000..468c6e8c7 --- /dev/null +++ b/lib/phonebook/providers/association_provider.dart @@ -0,0 +1,15 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/phonebook/class/association.dart'; + + +final associationProvider = StateNotifierProvider((ref) { + return AssociationProvider(); +}); + +class AssociationProvider extends StateNotifier { +AssociationProvider() : super(Association.empty()); + + void setAssociation(Association i) { + state = i; + } +} \ No newline at end of file diff --git a/lib/phonebook/providers/member_provider.dart b/lib/phonebook/providers/member_provider.dart new file mode 100644 index 000000000..3d6118930 --- /dev/null +++ b/lib/phonebook/providers/member_provider.dart @@ -0,0 +1,15 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/phonebook/class/completeMember.dart'; + + +final completeMemberProvider = StateNotifierProvider((ref) { + return CompleteMemberProvider(); +}); + +class CompleteMemberProvider extends StateNotifier { + CompleteMemberProvider() : super(CompleteMember.empty()); + + void setCompleteMember(CompleteMember i) { + state = i; + } +} \ No newline at end of file diff --git a/lib/phonebook/providers/phonebook_page_provider.dart b/lib/phonebook/providers/phonebook_page_provider.dart new file mode 100644 index 000000000..f74d3fd0b --- /dev/null +++ b/lib/phonebook/providers/phonebook_page_provider.dart @@ -0,0 +1,16 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +enum PhonebookPage { main, admin, memberDetail, addEditAssociation, addEditRoleMember, editRole, associationEditor} + + +final phonebookPageProvider = StateNotifierProvider((ref) { + return PhonebookPageNotifier(); +}); + +class PhonebookPageNotifier extends StateNotifier { + PhonebookPageNotifier() : super(PhonebookPage.main); + + void setPhonebookPage(PhonebookPage i) { + state = i; + } +} \ No newline at end of file diff --git a/lib/phonebook/providers/post_provider.dart b/lib/phonebook/providers/post_provider.dart new file mode 100644 index 000000000..79b75c7dc --- /dev/null +++ b/lib/phonebook/providers/post_provider.dart @@ -0,0 +1,16 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/phonebook/class/post.dart'; + + + +final postProvider = StateNotifierProvider((ref) { + return PostProvider(); +}); + +class PostProvider extends StateNotifier { +PostProvider() : super(Post.empty()); + + void setPost(Post i) { + state = i; + } +} \ No newline at end of file diff --git a/lib/phonebook/providers/role_provider.dart b/lib/phonebook/providers/role_provider.dart new file mode 100644 index 000000000..0ded16660 --- /dev/null +++ b/lib/phonebook/providers/role_provider.dart @@ -0,0 +1,15 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/phonebook/class/role.dart'; + + +final roleProvider = StateNotifierProvider((ref) { + return RoleProvider(); +}); + +class RoleProvider extends StateNotifier { +RoleProvider() : super(Role.empty()); + + void setRole(Role i) { + state = i; + } +} \ No newline at end of file diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart new file mode 100644 index 000000000..2d7812ec9 --- /dev/null +++ b/lib/phonebook/tools/constants.dart @@ -0,0 +1,9 @@ +class PhonebookTextConstants { + static const String phonebook = "Annuaire"; + static const String phonebookSearch = "Rechercher une personne par : "; + static const String phonebookSearchName = "Nom/Prénom/Surnom"; + static const String phonebookSearchRole = "Poste"; + static const String phonebookSearchAssociation = "Association"; + static const String phonebookSearchField = "Rechercher :"; + static const double phonebookMargin = 1; +} \ No newline at end of file diff --git a/lib/phonebook/ui/page_switcher.dart b/lib/phonebook/ui/page_switcher.dart new file mode 100644 index 000000000..475a04cf9 --- /dev/null +++ b/lib/phonebook/ui/page_switcher.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/ui/pages/admin_page/admin_page.dart'; +import 'package:myecl/phonebook/ui/pages/association_editor_page/association_editor_page.dart'; +import 'package:myecl/phonebook/ui/pages/association_page/association_page.dart'; +import 'package:myecl/phonebook/ui/pages/main_page/main_page.dart'; +import 'package:myecl/phonebook/ui/pages/member_detail_page/member_detail_page.dart'; +import 'package:myecl/phonebook/ui/pages/role_member_page/role_member_page.dart'; +import 'package:myecl/phonebook/ui/pages/role_page/role_page.dart'; + +class PageSwitcher extends ConsumerWidget { + const PageSwitcher({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final page = ref.watch(phonebookPageProvider); + switch (page) { + case PhonebookPage.main: + return const MainPage(); + case PhonebookPage.admin: + return const AdminPage(); + case PhonebookPage.memberDetail: + return const MemberDetailPage(); + case PhonebookPage.addEditAssociation: + return const AssociationPage(); + case PhonebookPage.addEditRoleMember: + return const RoleMemberPage(); + case PhonebookPage.editRole: + return const RolePage(); + case PhonebookPage.associationEditor: + return const AssociationEditorPage(); + default: + return const Text('Unknown page'); + } + } +} diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart new file mode 100644 index 000000000..6ebfdadb9 --- /dev/null +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; + +class AdminPage extends HookConsumerWidget { + const AdminPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final pageNotifier = ref.watch(phonebookPageProvider.notifier); + return Expanded( + child: Column(children: [ + const Center( + child : Text("Admin Page", style: TextStyle(fontSize: 40))), + Expanded( + child: Container( + margin: const EdgeInsets.all(10), + width: MediaQuery.of(context).size.width, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50), + color: Colors.red + ), + child: GestureDetector( + child: const Center(child : Text("Manage Association", style: TextStyle(fontSize: 40))), + onTap: () { + pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); + }, + ))), + Expanded( + child : Container( + margin: const EdgeInsets.all(10), + width: MediaQuery.of(context).size.width, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50), + color: Colors.red + ), + child: GestureDetector( + child: const Center( child : Text("Edit Role", style: TextStyle(fontSize: 40))), + onTap: () { + pageNotifier.setPhonebookPage(PhonebookPage.editRole); + }, + ))) + ])); + } +} diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart new file mode 100644 index 000000000..2c05a5f11 --- /dev/null +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -0,0 +1,83 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; + +class AssociationEditorPage extends HookConsumerWidget { + const AssociationEditorPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final pageNotifier = ref.watch(phonebookPageProvider.notifier); + Association association = ref.watch(associationProvider); + String text = ""; + if (association.id == "") { + text = "Ajouter une association"; + } + else { + text = "Modifier une association"; + } + return Expanded( + child: Column(children: [ + Center( + child : Text(text, style: const TextStyle(fontSize: 20))), + Row( + children: const [ + Text("Nom de l'association", style: TextStyle(fontSize: 20)), + Expanded( + child: TextField( + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Nom de l\'association', + ), + ), + ), + ], + ), + Container( + margin: const EdgeInsets.all(10), + width: MediaQuery.of(context).size.width, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50), + color: Colors.red + ), + child: GestureDetector( + child: const Center(child : Text("Insérer option image", style: TextStyle(fontSize: 20))), + onTap: () { + pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); + }, + )), + Row(children: [ + GestureDetector( + child: Container( + margin: const EdgeInsets.all(10), + width: MediaQuery.of(context).size.width/2.3, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50), + color: Colors.red + ), + child: const Center(child : Text("Annuler", style: TextStyle(fontSize: 20))),), + onTap: () { + pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); + }, + ), + GestureDetector( + child: Container( + margin: const EdgeInsets.all(10), + width: MediaQuery.of(context).size.width/2.3, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50), + color: Colors.red + ), + child: const Center(child : Text("Valider", style: TextStyle(fontSize: 20))), + ), + onTap: () { + pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); + }, + ) + + ]), + ])); + } +} \ No newline at end of file diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart new file mode 100644 index 000000000..be0709ee2 --- /dev/null +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:heroicons/heroicons.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/drawer/providers/page_provider.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/class/completeMember.dart'; +import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:myecl/admin/providers/is_admin.dart'; +import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; + +class AssociationPage extends HookConsumerWidget { + const AssociationPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final associationNotifier = ref.watch(associationProvider.notifier); + final pageNotifier = ref.watch(phonebookPageProvider.notifier); + final search = useState(""); + return Column(children: [ + const Text(PhonebookTextConstants.phonebookSearchField), + const SizedBox( + width: 5), + Container( + padding: const EdgeInsets.symmetric(horizontal: 5), + decoration: BoxDecoration( + border: Border.all(color: Colors.black), + borderRadius: BorderRadius.circular(10)), + child: TextField( + decoration: const InputDecoration( + border: InputBorder.none, + ), + onChanged: (String value) { + search.value = value; + }, + )), + ElevatedButton( + onPressed: (){ + associationNotifier.setAssociation(Association.empty()); + pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); + }, + child: const Text("Ajouter une association")), + Container( + margin: const EdgeInsets.symmetric(vertical: 7), + color: Colors.black, + height: 2, + ), + Expanded( + child: ListView.builder( + padding: const EdgeInsets.all( + PhonebookTextConstants.phonebookMargin), + itemCount: 10, + itemBuilder: (BuildContext context, int index) { + return Card( + child: ListTile( + title: Row( + children: [ + Expanded( + child: Text( + "Nom $index Prénom $index (Surnom $index)")), + ], + ), + subtitle: Text("Email: $index"), + onTap: () { + associationNotifier.setAssociation( + Association.empty()); + pageNotifier.setPhonebookPage( + PhonebookPage.associationEditor); + }, + )); + }))]); + } +} \ No newline at end of file diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart new file mode 100644 index 000000000..bc8bef5b3 --- /dev/null +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -0,0 +1,146 @@ +import 'package:flutter/material.dart'; +import 'package:heroicons/heroicons.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/drawer/providers/page_provider.dart'; +import 'package:myecl/phonebook/class/completeMember.dart'; +import 'package:myecl/phonebook/providers/member_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:myecl/admin/providers/is_admin.dart'; +import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; + +class MainPage extends HookConsumerWidget { + const MainPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final search = useState(""); + final searchType = useState("name"); + final isAdmin = ref.watch(isAdminProvider); + final pageNotifier = ref.watch(phonebookPageProvider.notifier); + final completeMemberNotifier = ref.watch(completeMemberProvider.notifier); + return Expanded( + child: Container( + padding: const EdgeInsets.all(10), + child: Stack( + children: [ + Column(children: [ + const SizedBox(height: 60), + Row( + children: [ + const Text(PhonebookTextConstants.phonebookSearch), + DropdownButton( + value: searchType.value, + icon: const Icon(Icons.arrow_downward), + iconSize: 14, + elevation: 16, + style: const TextStyle(color: Colors.deepPurple), + underline: Container( + height: 2, + color: Colors.deepPurpleAccent, + ), + onChanged: (String? newValue) { + searchType.value = newValue!; + }, + items: >[ + [PhonebookTextConstants.phonebookSearchName, "name"], + [PhonebookTextConstants.phonebookSearchRole, "role"], + [ + PhonebookTextConstants.phonebookSearchAssociation, + "association" + ] + ].map>((List value) { + return DropdownMenuItem( + value: value[1], + child: Text(value[0]), + ); + }).toList(), + ) + ], + ), + Row(children: [ + const Text(PhonebookTextConstants.phonebookSearchField), + const SizedBox(width: 5), + Expanded( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 5), + decoration: BoxDecoration( + border: Border.all(color: Colors.black), + borderRadius: BorderRadius.circular(10)), + child: TextField( + decoration: const InputDecoration( + border: InputBorder.none, + ), + onChanged: (String value) { + search.value = value; + }, + ))) + ]), + Container( + margin: const EdgeInsets.symmetric(vertical: 7), + color: Colors.black, + height: 2, + ), + Expanded( + child: ListView.builder( + padding: const EdgeInsets.all( + PhonebookTextConstants.phonebookMargin), + itemCount: 10, + itemBuilder: (BuildContext context, int index) { + return Card( + child: ListTile( + title: Row( + children: [ + Expanded( + child: Text( + "Nom $index Prénom $index (Surnom $index)")), + ], + ), + subtitle: Text("Email: $index"), + onTap: () { + completeMemberNotifier + .setCompleteMember(CompleteMember.empty()); + pageNotifier.setPhonebookPage( + PhonebookPage.memberDetail); + }, + )); + })) + ]), + if (isAdmin) + Positioned( + top: 15, + right: 15, + child: GestureDetector( + onTap: () { + pageNotifier.setPhonebookPage(PhonebookPage.admin); + }, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + blurRadius: 10, + offset: const Offset(0, 5)) + ]), + child: Row( + children: const [ + HeroIcon(HeroIcons.userGroup, color: Colors.white), + SizedBox(width: 10), + Text("Admin", + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.white)), + ], + ), + ), + ), + ) + ], + ))); + } +} diff --git a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart new file mode 100644 index 000000000..e6be1f3b2 --- /dev/null +++ b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/admin/providers/is_admin.dart'; +import 'package:myecl/phonebook/class/post.dart'; +import 'package:myecl/phonebook/providers/member_provider.dart'; +import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/providers/post_provider.dart'; + +class MemberDetailPage extends HookConsumerWidget { + const MemberDetailPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final isAdmin = ref.watch(isAdminProvider); + final pageNotifier = ref.watch(phonebookPageProvider.notifier); + final memberProvider = ref.watch(completeMemberProvider); + final postProviderNotifier = ref.watch(postProvider.notifier); + return Expanded( + child: Container( + margin: const EdgeInsets.all(10), + width: MediaQuery.of(context).size.width, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50), + color: const Color.fromARGB(255, 187, 187, 187)), + child: Column(children: [ + const Text("Détail"), + Text("Nom: ${memberProvider.member.name}"), + Text("Prénom: ${memberProvider.member.firstname}"), + if (memberProvider.member.nickname != null) + Text("Surnom: ${memberProvider.member.nickname!}"), + Text("Email: ${memberProvider.member.email}"), + const Text("Association :"), + for (var post in memberProvider.post) + Row(children: [ + Text("${post.association.name} : ${post.role.name}"), + if (isAdmin) + IconButton( + icon: const Icon(Icons.edit), + onPressed: () { + postProviderNotifier.setPost(post); + pageNotifier.setPhonebookPage( + PhonebookPage.addEditRoleMember); + }), + ]), + if (isAdmin) + ElevatedButton( + onPressed: () { + postProviderNotifier.setPost(Post.empty()); + pageNotifier + .setPhonebookPage(PhonebookPage.addEditRoleMember); + }, + child: Row( + children: const [ + Icon(Icons.add), + Text("Ajouter un rôle") + ], + )) + ]))); + } +} diff --git a/lib/phonebook/ui/pages/role_member_page/role_member_page.dart b/lib/phonebook/ui/pages/role_member_page/role_member_page.dart new file mode 100644 index 000000000..f657757c7 --- /dev/null +++ b/lib/phonebook/ui/pages/role_member_page/role_member_page.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/post.dart'; +import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/providers/post_provider.dart'; + + +class RoleMemberPage extends HookConsumerWidget { + const RoleMemberPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final post = ref.watch(postProvider); + final postNotifier = ref.watch(postProvider.notifier); + final pageNotifier = ref.watch(phonebookPageProvider.notifier); + Post newPost = post; + final associationList = useState([["Association 1","1"], ["Association 2","2"], ["Association 3","3"]]); + final roleList = useState([["Rôle 1","1"], ["Rôle 2","2"], ["Rôle 3","3"]]); + return Column( + children: [ + const Text("Association :"), + const SizedBox(width: 10), + SizedBox( + width: 200, + child: Autocomplete( + initialValue: TextEditingValue(text: post.association.name), + optionsBuilder: (TextEditingValue textValue) { + if (textValue.text == "") { + return associationList.value.map((e) => e[0]).toList(); + } + return associationList.value.map((e) => e[0]).toList().where((String option) { + return option.toLowerCase().contains(textValue.text.toLowerCase()); + }); + }, + onSelected: (String selection) { + String id = associationList.value.firstWhere((element) => element[0] == selection)[1]; + newPost = newPost.setAssociation(selection,id); + },)), + + const SizedBox(width: 30), + const Text("Rôle :"), + const SizedBox(width: 10), + SizedBox( + width: 200, + child: Autocomplete( + initialValue: TextEditingValue(text: post.role.name), + optionsBuilder: (TextEditingValue textValue) { + if (textValue.text == "") { + return roleList.value.map((e) => e[0]).toList(); + } + return roleList.value.map((e) => e[0]).toList().where((String option) { + return option.toLowerCase().contains(textValue.text.toLowerCase()); + }); + }, + onSelected: (String selection) { + String id = roleList.value.firstWhere((element) => element[0] == selection)[1]; + newPost = newPost.setRole(selection,id); + },)), + ElevatedButton( + onPressed: () { + if (newPost.association.name == "") { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Veuillez choisir une association"))); + return; + } + else if (newPost.role.name == "") { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Veuillez choisir un rôle"))); + return; + } + else { + postNotifier.setPost(newPost); + pageNotifier.setPhonebookPage(PhonebookPage.memberDetail); + } + }, + child: const Text("Valider"), + ) + ], + ); + } +} \ No newline at end of file diff --git a/lib/phonebook/ui/pages/role_page/role_page.dart b/lib/phonebook/ui/pages/role_page/role_page.dart new file mode 100644 index 000000000..e70820d1c --- /dev/null +++ b/lib/phonebook/ui/pages/role_page/role_page.dart @@ -0,0 +1,11 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +class RolePage extends HookConsumerWidget { + const RolePage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return const Text('RolePage'); + } +} \ No newline at end of file diff --git a/lib/phonebook/ui/phonebook.dart b/lib/phonebook/ui/phonebook.dart new file mode 100644 index 000000000..41995a6c1 --- /dev/null +++ b/lib/phonebook/ui/phonebook.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/drawer/providers/swipe_provider.dart'; +import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/ui/page_switcher.dart'; +import 'package:myecl/phonebook/ui/top_bar.dart'; + +class PhonebookHomePage extends HookConsumerWidget { + final SwipeControllerNotifier controllerNotifier; + final AnimationController controller; + const PhonebookHomePage( + {Key? key, required this.controllerNotifier, required this.controller}) + : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final page = ref.watch(phonebookPageProvider); + final pageNotifier = ref.watch(phonebookPageProvider.notifier); + return Scaffold( + body: WillPopScope( + onWillPop: () async { + switch (page) { + case PhonebookPage.main: + if (!controller.isCompleted) { + controllerNotifier.toggle(); + break; + } else { + return true; + } + case PhonebookPage.memberDetail: + pageNotifier.setPhonebookPage(PhonebookPage.main); + break; + case PhonebookPage.addEditAssociation: + pageNotifier.setPhonebookPage(PhonebookPage.admin); + break; + case PhonebookPage.admin: + pageNotifier.setPhonebookPage(PhonebookPage.main); + break; + case PhonebookPage.addEditRoleMember: + pageNotifier.setPhonebookPage(PhonebookPage.memberDetail); + break; + case PhonebookPage.editRole: + pageNotifier.setPhonebookPage(PhonebookPage.admin); + break; + case PhonebookPage.associationEditor: + pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); + break; + } + return false; + }, + child: SafeArea( + child: IgnorePointer( + ignoring: controller.isCompleted, + child: Column( + children: [ + TopBar( + controllerNotifier: controllerNotifier, + ), + const Expanded(child: PageSwitcher()), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/phonebook/ui/top_bar.dart b/lib/phonebook/ui/top_bar.dart new file mode 100644 index 000000000..2d875733a --- /dev/null +++ b/lib/phonebook/ui/top_bar.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:heroicons/heroicons.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/drawer/providers/swipe_provider.dart'; +import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; + +class TopBar extends HookConsumerWidget { + final SwipeControllerNotifier controllerNotifier; + const TopBar({Key? key, required this.controllerNotifier}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final page = ref.watch(phonebookPageProvider); + final pageNotifier = ref.watch(phonebookPageProvider.notifier); + return Column( + children: [ + const SizedBox( + height: 15, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox( + width: 70, + child: Builder( + builder: (BuildContext appBarContext) { + return IconButton( + onPressed: () { + switch (page) { + case PhonebookPage.main: + controllerNotifier.toggle(); + break; + case PhonebookPage.memberDetail: + pageNotifier.setPhonebookPage(PhonebookPage.main); + break; + case PhonebookPage.addEditAssociation: + pageNotifier.setPhonebookPage(PhonebookPage.admin); + break; + case PhonebookPage.admin: + pageNotifier.setPhonebookPage(PhonebookPage.main); + break; + case PhonebookPage.addEditRoleMember: + pageNotifier.setPhonebookPage(PhonebookPage.memberDetail); + break; + case PhonebookPage.editRole: + pageNotifier.setPhonebookPage(PhonebookPage.admin); + break; + case PhonebookPage.associationEditor: + pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); + break; + } + }, + icon: HeroIcon( + page == PhonebookPage.main + ? HeroIcons.bars3BottomLeft + : HeroIcons.chevronLeft, + color: Colors.black, + size: 30, + )); + }, + ), + ), + const Text(PhonebookTextConstants.phonebook, + style: TextStyle( + fontSize: 40, + fontWeight: FontWeight.w700, + color: Colors.black)), + const SizedBox( + width: 70, + ), + ], + ), + ], + ); + } +} From 0ab427aca35aa73899e4397ed03c2b49e50fdf95 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:56:59 +0100 Subject: [PATCH 002/123] Change Admin Page visual and add Association pictures --- .../providers/association_id_provider.dart | 12 ++ .../providers/association_list_provider.dart | 77 ++++++++++ .../association_picture_provider.dart | 101 ++++++++++++ .../association_picture_repository.dart | 17 +++ .../repositories/association_repository.dart | 53 +++++++ lib/phonebook/tools/constants.dart | 31 +++- .../ui/pages/admin_page/admin_page.dart | 66 ++++---- .../ui/pages/admin_page/asso_ui.dart | 144 ++++++++++++++++++ .../ui/pages/admin_page/association_bar.dart | 121 +++++++++++++++ .../ui/pages/admin_page/role_bar.dart | 121 +++++++++++++++ .../association_editor_page.dart | 70 ++++++++- .../association_page/association_page.dart | 5 +- .../ui/pages/main_page/main_page.dart | 35 +---- .../ui/pages/main_page/member_cards.dart | 73 +++++++++ .../member_detail_page.dart | 15 +- .../role_member_page/role_member_page.dart | 11 +- 16 files changed, 868 insertions(+), 84 deletions(-) create mode 100644 lib/phonebook/providers/association_id_provider.dart create mode 100644 lib/phonebook/providers/association_list_provider.dart create mode 100644 lib/phonebook/providers/association_picture_provider.dart create mode 100644 lib/phonebook/repositories/association_picture_repository.dart create mode 100644 lib/phonebook/repositories/association_repository.dart create mode 100644 lib/phonebook/ui/pages/admin_page/asso_ui.dart create mode 100644 lib/phonebook/ui/pages/admin_page/association_bar.dart create mode 100644 lib/phonebook/ui/pages/admin_page/role_bar.dart create mode 100644 lib/phonebook/ui/pages/main_page/member_cards.dart diff --git a/lib/phonebook/providers/association_id_provider.dart b/lib/phonebook/providers/association_id_provider.dart new file mode 100644 index 000000000..c8385d61b --- /dev/null +++ b/lib/phonebook/providers/association_id_provider.dart @@ -0,0 +1,12 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +class AssociationIdNotifier extends StateNotifier { + AssociationIdNotifier() : super(""); + + void setId(String id) { + state = id; + } +} + +final associationIdProvider = + StateNotifierProvider((ref) => AssociationIdNotifier()); \ No newline at end of file diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart new file mode 100644 index 000000000..893531fe2 --- /dev/null +++ b/lib/phonebook/providers/association_list_provider.dart @@ -0,0 +1,77 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/repositories/association_repository.dart'; +import 'package:myecl/auth/providers/openid_provider.dart'; +import 'package:myecl/tools/providers/list_notifier.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; +import 'package:myecl/user/class/user.dart'; +import 'package:myecl/user/providers/user_provider.dart'; + +class AssociationListNotifier extends ListNotifier { + final AssociationRepository associationRepository = AssociationRepository(); + AssociationListNotifier({required String token}) + : super(const AsyncValue.loading()) { + associationRepository.setToken(token); + } + + Future>> loadAssociations() async { + return await loadList(associationRepository.getAssociationList); + } + +// Future>> loadAssociationsFromUser(User user) async { +// return await loadList(() async { +// return user.associations; +// }); +// } + + Future createAssociation(Association association) async { + return await add(associationRepository.createAssociation, association); + } + + Future updateAssociation(Association association) async { + return await update( + associationRepository.updateAssociation, + (associations, association) => + associations..[associations.indexWhere((g) => g.id == association.id)] = association, + association); + } + + Future deleteAssociation(Association association) async { + return await delete( + associationRepository.deleteAssociation, + (associations, association) => associations..removeWhere((i) => i.id == association.id), + association.id, + association); + } + + void setAssociation(Association association) { + state.whenData( + (d) { + state = + AsyncValue.data(d..[d.indexWhere((g) => g.id == association.id)] = association); + }, + ); + } +} + +final allAssociationListProvider = + StateNotifierProvider>>( + (ref) { + final token = ref.watch(tokenProvider); + AssociationListNotifier provider = AssociationListNotifier(token: token); + tokenExpireWrapperAuth(ref, () async { + await provider.loadAssociations(); + }); + return provider; +}); + +//final userAssociationListNotifier = +// StateNotifierProvider>>( +// (ref) { +// final token = ref.watch(tokenProvider); +// AssociationListNotifier provider = AssociationListNotifier(token: token); +// tokenExpireWrapperAuth(ref, () async { +// await provider.loadAssociationsFromUser(ref.watch(userProvider)); +// }); +// return provider; +//}); diff --git a/lib/phonebook/providers/association_picture_provider.dart b/lib/phonebook/providers/association_picture_provider.dart new file mode 100644 index 000000000..b22132a19 --- /dev/null +++ b/lib/phonebook/providers/association_picture_provider.dart @@ -0,0 +1,101 @@ +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:image_cropper/image_cropper.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/auth/providers/openid_provider.dart'; +import 'package:myecl/phonebook/repositories/association_picture_repository.dart'; +import 'package:myecl/tools/constants.dart'; +import 'package:myecl/tools/providers/single_notifier.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; +import 'package:path_provider/path_provider.dart'; + +class AssociationPictureNotifier extends SingleNotifier { + final AssociationPictureRepository _associationPictureRepository = + AssociationPictureRepository(); + final ImagePicker _picker = ImagePicker(); + AssociationPictureNotifier(String token) : super(const AsyncLoading()) { + _associationPictureRepository.setToken(token); + } + + Future> getAssociationPicture(String userId) async { + return await load( + () async => _associationPictureRepository.getAssociationPicture(userId)); + } + + Future setAssociationPicture(ImageSource source, String associationId) async { + final previousState = state; + state = const AsyncLoading(); + final XFile? image = + await _picker.pickImage(source: source, imageQuality: 20); + if (image != null) { + try { + final i = await _associationPictureRepository.addAssociationPicture(image.path, associationId); + state = AsyncValue.data(i); + return true; + } catch (e) { + state = previousState; + return false; + } + } + state = previousState; + return null; + } + + Future cropImage(String associationId) async { + final previousState = state; + state.whenData((value) async { + Directory tempDir = await getTemporaryDirectory(); + File file = await File( + '${tempDir.path}/${DateTime.now().millisecondsSinceEpoch}.png') + .create(); + final File newImage = await file.writeAsBytes(value); + CroppedFile? croppedFile = await ImageCropper().cropImage( + sourcePath: newImage.path, + aspectRatioPresets: [ + CropAspectRatioPreset.square, + CropAspectRatioPreset.ratio3x2, + CropAspectRatioPreset.original, + CropAspectRatioPreset.ratio4x3, + CropAspectRatioPreset.ratio16x9 + ], + uiSettings: [ + AndroidUiSettings( + toolbarTitle: 'Recadrer', + toolbarColor: ColorConstants.gradient1, + toolbarWidgetColor: Colors.grey[100], + initAspectRatio: CropAspectRatioPreset.original, + lockAspectRatio: false), + IOSUiSettings( + title: 'Recadrer', + ), + ], + ); + if (croppedFile != null) { + try { + final i = await _associationPictureRepository + .addAssociationPicture(croppedFile.path, associationId); + state = AsyncValue.data(i); + return true; + } catch (e) { + state = previousState; + return false; + } + } else { + state = previousState; + return null; + } + }); + state = previousState; + return null; + } +} + +final associationPictureProvider = + StateNotifierProvider>((ref) { + final token = ref.watch(tokenProvider); + AssociationPictureNotifier notifier = AssociationPictureNotifier(token); + return notifier; +}); diff --git a/lib/phonebook/repositories/association_picture_repository.dart b/lib/phonebook/repositories/association_picture_repository.dart new file mode 100644 index 000000000..1fad48f7e --- /dev/null +++ b/lib/phonebook/repositories/association_picture_repository.dart @@ -0,0 +1,17 @@ +import 'package:flutter/services.dart'; +import 'package:myecl/tools/repository/logo_repository.dart'; + +class AssociationPictureRepository extends LogoRepository { + @override + // ignore: overridden_fields + final ext = 'phonebook/'; + + Future getAssociationPicture(String associationId) async { + return await getLogo(associationId, suffix: "/association-picture/"); + } + + Future addAssociationPicture(String path, String associationId) async { + final image = await saveLogoToTemp(path); + return await addLogo(image.path, associationId, suffix: "/association-picture"); + } +} diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart new file mode 100644 index 000000000..e31988cb3 --- /dev/null +++ b/lib/phonebook/repositories/association_repository.dart @@ -0,0 +1,53 @@ +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/tools/repository/repository.dart'; +import 'package:myecl/user/class/list_users.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:myecl/tools/exception.dart'; + +class AssociationRepository extends Repository { + @override + // ignore: overridden_fields + final ext = "phonebook/association/"; + + Future> getAssociationList() async { + return List.from( + (await getList()).map((x) => Association.fromJSON(x))); + } + + Future getAssociation(String associationId) async { + return Association.fromJSON(await getOne(associationId)); + } + + Future deleteAssociation(String associationId) async { + return await delete(associationId); + } + + Future updateAssociation(Association association) async { + return await update(association.toJSON(), association.id); + } + +Future createAssociation(Association association) async { + return Association.fromJSON(await create(association.toJSON())); + } + + Future addMember(Association association, SimpleUser user) async { + await create({"user_id": user.id, "association_id": association.id}, + suffix: "membership"); + return true; + } + + Future deleteMember(Association association, SimpleUser user) async { + final response = await http.delete( + Uri.parse("$host${ext}membership"), + headers: headers, + body: json.encode({"user_id": user.id, "association_id": association.id})); + if (response.statusCode == 204) { + return true; + } else if (response.statusCode == 403) { + throw AppException(ErrorType.tokenExpire, response.body); + } else { + throw AppException(ErrorType.notFound, "Failed to update item"); + } + } +} diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index 2d7812ec9..974895232 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -1,9 +1,38 @@ class PhonebookTextConstants { + static const String errorAssociationPicture = + "Erreur lors de la modification de la photo d'association"; static const String phonebook = "Annuaire"; static const String phonebookSearch = "Rechercher une personne par : "; static const String phonebookSearchName = "Nom/Prénom/Surnom"; static const String phonebookSearchRole = "Poste"; static const String phonebookSearchAssociation = "Association"; static const String phonebookSearchField = "Rechercher :"; - static const double phonebookMargin = 1; + static const String updatedAssociationPicture = "La photo d'association a été changée"; + static const String tooHeavyAssociationPicture = + "L'image est trop lourde (max 4Mo)"; + static const String postAssociation = "Association :"; + static const String postRole = "Rôle :"; + static const String postAssociationError = "Veuillez choisir une association"; + static const String postRoleError = "Veuillez choisir un rôle"; + static const String validation = "Valider"; + static const String cancel = "Annuler"; + static const String association = "Association :"; + static const String associationPure = "Association"; + static const String rolePure = "Rôle"; + static const String name = "Nom"; + static const String firstname = "Prénom"; + static const String nickname = "Surnom"; + static const String email = "Email"; + static const String detail = "Détail"; + static const String addRole = "Ajouter un rôle"; + static const String adminPage = "Page Administrateur"; + static const String addEditAssociation = "Ajouter/Modifier une association"; + static const String editRole = "Modifier un rôle"; + static const String admin = "Admin"; + static const String addAssociation = "Ajouter une association"; + static const String errorLoadAssociationPicture = "Erreur lors du chargement de la photo d'association"; + static const String deleting = "Suppression"; + static const String deleteAssociation = "Supprimer l'association ?"; + static const String deletedAssociation = "Association supprimée"; + static const String deletingError = "Erreur lors de la suppression"; } \ No newline at end of file diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 6ebfdadb9..2571e26fb 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -1,6 +1,10 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:heroicons/heroicons.dart'; +import 'package:myecl/phonebook/ui/pages/admin_page/association_bar.dart'; +import 'package:myecl/phonebook/ui/pages/admin_page/role_bar.dart'; class AdminPage extends HookConsumerWidget { const AdminPage({Key? key}) : super(key: key); @@ -8,38 +12,36 @@ class AdminPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final pageNotifier = ref.watch(phonebookPageProvider.notifier); - return Expanded( - child: Column(children: [ - const Center( - child : Text("Admin Page", style: TextStyle(fontSize: 40))), - Expanded( - child: Container( - margin: const EdgeInsets.all(10), - width: MediaQuery.of(context).size.width, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(50), - color: Colors.red + return DefaultTabController( + length: 2, + child: Column( + children: const [ + SizedBox( + height: 10, + ), + TabBar( + labelColor: Colors.black, + unselectedLabelColor: Colors.grey, + indicatorColor: Colors.black, + tabs: [ + Tab( + text: PhonebookTextConstants.associationPure, ), - child: GestureDetector( - child: const Center(child : Text("Manage Association", style: TextStyle(fontSize: 40))), - onTap: () { - pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); - }, - ))), - Expanded( - child : Container( - margin: const EdgeInsets.all(10), - width: MediaQuery.of(context).size.width, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(50), - color: Colors.red - ), - child: GestureDetector( - child: const Center( child : Text("Edit Role", style: TextStyle(fontSize: 40))), - onTap: () { - pageNotifier.setPhonebookPage(PhonebookPage.editRole); - }, - ))) - ])); + Tab( + text: PhonebookTextConstants.rolePure, + ) + ], + ), + Expanded( + child: TabBarView( + children: [ + AssociationBar(), + RoleBar(), + ], + ), + ), + ], + ), + ); } } diff --git a/lib/phonebook/ui/pages/admin_page/asso_ui.dart b/lib/phonebook/ui/pages/admin_page/asso_ui.dart new file mode 100644 index 000000000..00b0e8c18 --- /dev/null +++ b/lib/phonebook/ui/pages/admin_page/asso_ui.dart @@ -0,0 +1,144 @@ +import 'package:flutter/material.dart'; +import 'package:heroicons/heroicons.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/tools/constants.dart'; +import 'package:myecl/tools/ui/shrink_button.dart'; + +class AssoUi extends HookConsumerWidget { + final Association association; + final void Function() onEdit; + final Future Function() onDelete; + const AssoUi( + {super.key, + required this.association, + required this.onEdit, + required this.onDelete}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Container( + margin: const EdgeInsets.symmetric(vertical: 10), + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 5, + spreadRadius: 2) + ]), + child: Row( + children: [ + const SizedBox( + width: 10, + ), + Expanded( + child: Text( + association.name, + style: const TextStyle( + color: Colors.black, + fontSize: 20, + fontWeight: FontWeight.bold), + ), + ), + const SizedBox( + width: 10, + ), + Row( + children: [ + GestureDetector( + onTap: onEdit, + child: Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + Colors.grey.shade800, + Colors.grey.shade900, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + boxShadow: [ + BoxShadow( + color: Colors.grey.shade900.withOpacity(0.3), + spreadRadius: 2, + blurRadius: 4, + offset: const Offset(2, 3), + ), + ], + borderRadius: BorderRadius.circular(10), + ), + child: const HeroIcon( + HeroIcons.eye, + color: Colors.white, + ), + ), + ), + const SizedBox( + width: 10, + ), + ShrinkButton( + waitChild: Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.3), + spreadRadius: 2, + blurRadius: 4, + offset: const Offset(2, 3), + ), + ], + borderRadius: BorderRadius.circular(10), + ), + child: const Center( + child: CircularProgressIndicator( + color: Colors.white, + ), + ), + ), + onTap: onDelete, + child: Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.3), + spreadRadius: 2, + blurRadius: 4, + offset: const Offset(2, 3), + ), + ], + borderRadius: BorderRadius.circular(10), + ), + child: const HeroIcon( + HeroIcons.xMark, + color: Colors.white, + ), + )), + ], + ) + ], + ), + ); + } +} diff --git a/lib/phonebook/ui/pages/admin_page/association_bar.dart b/lib/phonebook/ui/pages/admin_page/association_bar.dart new file mode 100644 index 000000000..05bab4dfa --- /dev/null +++ b/lib/phonebook/ui/pages/admin_page/association_bar.dart @@ -0,0 +1,121 @@ +import 'package:flutter/material.dart'; +import 'package:heroicons/heroicons.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/ui/pages/admin_page/asso_ui.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/tools/constants.dart'; +import 'package:myecl/tools/ui/dialog.dart'; +import 'package:myecl/tools/functions.dart'; +import 'package:myecl/tools/ui/refresher.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; +import 'package:myecl/phonebook/providers/association_list_provider.dart'; +import 'package:myecl/phonebook/providers/association_id_provider.dart'; + +class AssociationBar extends HookConsumerWidget { + const AssociationBar({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final pageNotifier = ref.watch(phonebookPageProvider.notifier); + final associationsNotifier = ref.watch(allAssociationListProvider.notifier); + final associations = ref.watch(allAssociationListProvider); + final associationIdNotifier = ref.watch(associationIdProvider.notifier); + void displayToastWithContext(TypeMsg type, String msg) { + displayToast(context, type, msg); + } + + + return Refresher( + onRefresh: () async { + await associationsNotifier.loadAssociations(); + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: associations.when(data: (a) { + return Column(children: [ + Column( + children: [ + GestureDetector( + onTap: () { + pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); + }, + child: Container( + margin: const EdgeInsets.symmetric(vertical: 10), + padding: const EdgeInsets.symmetric( + horizontal: 10, vertical: 10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 5, + spreadRadius: 2) + ]), + child: Row( + children: [ + const Spacer(), + HeroIcon( + HeroIcons.plus, + color: Colors.grey.shade700, + size: 40, + ), + const Spacer(), + ], + ), + ), + ), + ...a + .map((association) => AssoUi( + association: association, + onEdit: () { + associationIdNotifier.setId(association.id); + pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); + }, + onDelete: () async { + await showDialog( + context: context, + builder: (context) { + return CustomDialogBox( + title: PhonebookTextConstants.deleting, + descriptions: + PhonebookTextConstants.deleteAssociation, + onYes: () async { + tokenExpireWrapper(ref, () async { + final value = await associationsNotifier + .deleteAssociation(association); + if (value) { + displayToastWithContext( + TypeMsg.msg, + PhonebookTextConstants + .deletedAssociation); + } else { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.deletingError); + } + }); + }, + ); + }); + }, + )) + .toList(), + const SizedBox( + height: 20, + ) + ], + ), + ]); + }, error: (e, s) { + return Text(e.toString()); + }, loading: () { + return const Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(ColorConstants.gradient1), + )); + }), + ), + ); + } +} \ No newline at end of file diff --git a/lib/phonebook/ui/pages/admin_page/role_bar.dart b/lib/phonebook/ui/pages/admin_page/role_bar.dart new file mode 100644 index 000000000..4f391c310 --- /dev/null +++ b/lib/phonebook/ui/pages/admin_page/role_bar.dart @@ -0,0 +1,121 @@ +import 'package:flutter/material.dart'; +import 'package:heroicons/heroicons.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/ui/pages/admin_page/asso_ui.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/tools/constants.dart'; +import 'package:myecl/tools/ui/dialog.dart'; +import 'package:myecl/tools/functions.dart'; +import 'package:myecl/tools/ui/refresher.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; +import 'package:myecl/phonebook/providers/association_list_provider.dart'; +import 'package:myecl/phonebook/providers/association_id_provider.dart'; + +class RoleBar extends HookConsumerWidget { + const RoleBar({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final pageNotifier = ref.watch(phonebookPageProvider.notifier); + final associationsNotifier = ref.watch(allAssociationListProvider.notifier); + final associations = ref.watch(allAssociationListProvider); + final associationIdNotifier = ref.watch(associationIdProvider.notifier); + void displayToastWithContext(TypeMsg type, String msg) { + displayToast(context, type, msg); + } + + + return Refresher( + onRefresh: () async { + await associationsNotifier.loadAssociations(); + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: associations.when(data: (a) { + return Column(children: [ + Column( + children: [ + GestureDetector( + onTap: () { + pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); + }, + child: Container( + margin: const EdgeInsets.symmetric(vertical: 10), + padding: const EdgeInsets.symmetric( + horizontal: 10, vertical: 10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 5, + spreadRadius: 2) + ]), + child: Row( + children: [ + const Spacer(), + HeroIcon( + HeroIcons.plus, + color: Colors.grey.shade700, + size: 40, + ), + const Spacer(), + ], + ), + ), + ), + ...a + .map((association) => AssoUi( + association: association, + onEdit: () { + associationIdNotifier.setId(association.id); + pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); + }, + onDelete: () async { + await showDialog( + context: context, + builder: (context) { + return CustomDialogBox( + title: PhonebookTextConstants.deleting, + descriptions: + PhonebookTextConstants.deleteAssociation, + onYes: () async { + tokenExpireWrapper(ref, () async { + final value = await associationsNotifier + .deleteAssociation(association); + if (value) { + displayToastWithContext( + TypeMsg.msg, + PhonebookTextConstants + .deletedAssociation); + } else { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.deletingError); + } + }); + }, + ); + }); + }, + )) + .toList(), + const SizedBox( + height: 20, + ) + ], + ), + ]); + }, error: (e, s) { + return Text(e.toString()); + }, loading: () { + return const Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(ColorConstants.gradient1), + )); + }), + ), + ); + } +} \ No newline at end of file diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 2c05a5f11..bb8628b8b 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -1,8 +1,14 @@ import 'package:flutter/material.dart'; +import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:image_picker/image_picker.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/tools/constants.dart'; +import 'package:myecl/tools/functions.dart'; class AssociationEditorPage extends HookConsumerWidget { const AssociationEditorPage({Key? key}) : super(key: key); @@ -11,6 +17,8 @@ class AssociationEditorPage extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final pageNotifier = ref.watch(phonebookPageProvider.notifier); Association association = ref.watch(associationProvider); + final associationPicture = ref.watch(associationPictureProvider); + final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); String text = ""; if (association.id == "") { text = "Ajouter une association"; @@ -18,6 +26,9 @@ class AssociationEditorPage extends HookConsumerWidget { else { text = "Modifier une association"; } + void displayToastWithContext(TypeMsg type, String msg) { + displayToast(context, type, msg); + } return Expanded( child: Column(children: [ Center( @@ -43,11 +54,56 @@ class AssociationEditorPage extends HookConsumerWidget { color: Colors.red ), child: GestureDetector( - child: const Center(child : Text("Insérer option image", style: TextStyle(fontSize: 20))), - onTap: () { - pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); - }, - )), + onTap: () async { + final value = await associationPictureNotifier + .setAssociationPicture(ImageSource.gallery, association.id); + if (value != null) { + if (value) { + displayToastWithContext( + TypeMsg.msg, + PhonebookTextConstants + .updatedAssociationPicture); + } else { + displayToastWithContext( + TypeMsg.error, + PhonebookTextConstants + .tooHeavyAssociationPicture); + } + } else { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.errorAssociationPicture); + } + }, + child: Container( + height: 40, + width: 40, + padding: const EdgeInsets.all(7), + decoration: BoxDecoration( + shape: BoxShape.circle, + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2 + .withOpacity(0.3), + spreadRadius: 2, + blurRadius: 4, + offset: const Offset(2, 3), + ), + ], + ), + child: const HeroIcon( + HeroIcons.photo, + color: Colors.white, + ), + ), + ),), Row(children: [ GestureDetector( child: Container( @@ -57,7 +113,7 @@ class AssociationEditorPage extends HookConsumerWidget { borderRadius: BorderRadius.circular(50), color: Colors.red ), - child: const Center(child : Text("Annuler", style: TextStyle(fontSize: 20))),), + child: const Center(child : Text(PhonebookTextConstants.cancel, style: TextStyle(fontSize: 20))),), onTap: () { pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); }, @@ -70,7 +126,7 @@ class AssociationEditorPage extends HookConsumerWidget { borderRadius: BorderRadius.circular(50), color: Colors.red ), - child: const Center(child : Text("Valider", style: TextStyle(fontSize: 20))), + child: const Center(child : Text(PhonebookTextConstants.validation, style: TextStyle(fontSize: 20))), ), onTap: () { pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index be0709ee2..81ca1e736 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -40,7 +40,7 @@ class AssociationPage extends HookConsumerWidget { associationNotifier.setAssociation(Association.empty()); pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); }, - child: const Text("Ajouter une association")), + child: const Text(PhonebookTextConstants.addAssociation)), Container( margin: const EdgeInsets.symmetric(vertical: 7), color: Colors.black, @@ -48,8 +48,7 @@ class AssociationPage extends HookConsumerWidget { ), Expanded( child: ListView.builder( - padding: const EdgeInsets.all( - PhonebookTextConstants.phonebookMargin), + padding: const EdgeInsets.all(1), itemCount: 10, itemBuilder: (BuildContext context, int index) { return Card( diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index bc8bef5b3..7e31feff5 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -8,6 +8,7 @@ import 'package:myecl/phonebook/tools/constants.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:myecl/admin/providers/is_admin.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/ui/pages/main_page/member_cards.dart'; class MainPage extends HookConsumerWidget { const MainPage({Key? key}) : super(key: key); @@ -18,9 +19,7 @@ class MainPage extends HookConsumerWidget { final searchType = useState("name"); final isAdmin = ref.watch(isAdminProvider); final pageNotifier = ref.watch(phonebookPageProvider.notifier); - final completeMemberNotifier = ref.watch(completeMemberProvider.notifier); - return Expanded( - child: Container( + return Container( padding: const EdgeInsets.all(10), child: Stack( children: [ @@ -81,30 +80,8 @@ class MainPage extends HookConsumerWidget { color: Colors.black, height: 2, ), - Expanded( - child: ListView.builder( - padding: const EdgeInsets.all( - PhonebookTextConstants.phonebookMargin), - itemCount: 10, - itemBuilder: (BuildContext context, int index) { - return Card( - child: ListTile( - title: Row( - children: [ - Expanded( - child: Text( - "Nom $index Prénom $index (Surnom $index)")), - ], - ), - subtitle: Text("Email: $index"), - onTap: () { - completeMemberNotifier - .setCompleteMember(CompleteMember.empty()); - pageNotifier.setPhonebookPage( - PhonebookPage.memberDetail); - }, - )); - })) + const Expanded( + child: MemberCards() ) ]), if (isAdmin) Positioned( @@ -130,7 +107,7 @@ class MainPage extends HookConsumerWidget { children: const [ HeroIcon(HeroIcons.userGroup, color: Colors.white), SizedBox(width: 10), - Text("Admin", + Text(PhonebookTextConstants.admin, style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, @@ -141,6 +118,6 @@ class MainPage extends HookConsumerWidget { ), ) ], - ))); + )); } } diff --git a/lib/phonebook/ui/pages/main_page/member_cards.dart b/lib/phonebook/ui/pages/main_page/member_cards.dart new file mode 100644 index 000000000..75e33773b --- /dev/null +++ b/lib/phonebook/ui/pages/main_page/member_cards.dart @@ -0,0 +1,73 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/completeMember.dart'; +import 'package:myecl/phonebook/providers/association_picture_provider.dart'; +import 'package:myecl/phonebook/providers/member_provider.dart'; +import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; + +class MemberCards extends HookConsumerWidget { + const MemberCards({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final pageNotifier = ref.watch(phonebookPageProvider.notifier); + final completeMemberNotifier = ref.watch(completeMemberProvider.notifier); + final associationPicture = ref.watch(associationPictureProvider); + + return ListView.builder( + padding: const EdgeInsets.all(1), + itemCount: 10, + itemBuilder: (BuildContext context, int index) { + return Card( + child: ListTile( + title: Row( + children: [ + Expanded( + child: Text( + "Nom $index Prénom $index (Surnom $index)")), + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + spreadRadius: 5, + blurRadius: 10, + offset: const Offset(2, 3), + ), + ], + ), + + child: + associationPicture.when(data: (picture){ + return CircleAvatar( + radius: 80, + backgroundImage: picture.isEmpty ? + const AssetImage('assets/images/profile.png') : + Image.memory(picture).image, + ); + }, loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, error: (e, s) { + return const Center( + child: Text(PhonebookTextConstants.errorLoadAssociationPicture), + ); + }, + ), + ) + ], + ), + subtitle: Text("Email: $index"), + onTap: () { + completeMemberNotifier + .setCompleteMember(CompleteMember.empty()); + pageNotifier.setPhonebookPage( + PhonebookPage.memberDetail); + }, + )); + }); + } +} \ No newline at end of file diff --git a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart index e6be1f3b2..de4052721 100644 --- a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart +++ b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart @@ -6,6 +6,7 @@ import 'package:myecl/phonebook/class/post.dart'; import 'package:myecl/phonebook/providers/member_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/providers/post_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; class MemberDetailPage extends HookConsumerWidget { const MemberDetailPage({Key? key}) : super(key: key); @@ -24,13 +25,13 @@ class MemberDetailPage extends HookConsumerWidget { borderRadius: BorderRadius.circular(50), color: const Color.fromARGB(255, 187, 187, 187)), child: Column(children: [ - const Text("Détail"), - Text("Nom: ${memberProvider.member.name}"), - Text("Prénom: ${memberProvider.member.firstname}"), + const Text(PhonebookTextConstants.detail), + Text("${PhonebookTextConstants.name} ${memberProvider.member.name}"), + Text("${PhonebookTextConstants.firstname} ${memberProvider.member.firstname}"), if (memberProvider.member.nickname != null) - Text("Surnom: ${memberProvider.member.nickname!}"), - Text("Email: ${memberProvider.member.email}"), - const Text("Association :"), + Text("${PhonebookTextConstants.nickname} ${memberProvider.member.nickname!}"), + Text("${PhonebookTextConstants.email} ${memberProvider.member.email}"), + const Text(PhonebookTextConstants.association), //à changer pour dépendre du nombre d'associatione for (var post in memberProvider.post) Row(children: [ Text("${post.association.name} : ${post.role.name}"), @@ -53,7 +54,7 @@ class MemberDetailPage extends HookConsumerWidget { child: Row( children: const [ Icon(Icons.add), - Text("Ajouter un rôle") + Text(PhonebookTextConstants.addRole) ], )) ]))); diff --git a/lib/phonebook/ui/pages/role_member_page/role_member_page.dart b/lib/phonebook/ui/pages/role_member_page/role_member_page.dart index f657757c7..ed2f5f2af 100644 --- a/lib/phonebook/ui/pages/role_member_page/role_member_page.dart +++ b/lib/phonebook/ui/pages/role_member_page/role_member_page.dart @@ -4,6 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/post.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/providers/post_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; class RoleMemberPage extends HookConsumerWidget { @@ -19,7 +20,7 @@ class RoleMemberPage extends HookConsumerWidget { final roleList = useState([["Rôle 1","1"], ["Rôle 2","2"], ["Rôle 3","3"]]); return Column( children: [ - const Text("Association :"), + const Text(PhonebookTextConstants.postAssociation), const SizedBox(width: 10), SizedBox( width: 200, @@ -39,7 +40,7 @@ class RoleMemberPage extends HookConsumerWidget { },)), const SizedBox(width: 30), - const Text("Rôle :"), + const Text(PhonebookTextConstants.postRole), const SizedBox(width: 10), SizedBox( width: 200, @@ -60,11 +61,11 @@ class RoleMemberPage extends HookConsumerWidget { ElevatedButton( onPressed: () { if (newPost.association.name == "") { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Veuillez choisir une association"))); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text(PhonebookTextConstants.postAssociationError))); return; } else if (newPost.role.name == "") { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Veuillez choisir un rôle"))); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text(PhonebookTextConstants.postRoleError))); return; } else { @@ -72,7 +73,7 @@ class RoleMemberPage extends HookConsumerWidget { pageNotifier.setPhonebookPage(PhonebookPage.memberDetail); } }, - child: const Text("Valider"), + child: const Text(PhonebookTextConstants.validation), ) ], ); From e4cbd85366b1f0b1ec4745ab018a2e7db08af917 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:56:59 +0100 Subject: [PATCH 003/123] Complete associations and members descriptions Navigation from main page to member detail, including association detail --- lib/phonebook/class/association.dart | 12 ++ ...mpleteMember.dart => complete_member.dart} | 8 +- lib/phonebook/class/member.dart | 2 +- .../providers/association_list_provider.dart | 6 +- .../association_member_list_provider.dart | 31 +++ .../association_picture_provider.dart | 27 +-- .../providers/complete_member_provider.dart | 15 ++ lib/phonebook/providers/member_provider.dart | 17 +- .../providers/phonebook_page_provider.dart | 2 +- .../association_member_repository.dart | 38 ++++ .../association_picture_repository.dart | 6 +- .../repositories/association_repository.dart | 28 +-- .../repositories/member_repository.dart | 23 +++ lib/phonebook/tools/constants.dart | 22 +- lib/phonebook/ui/page_switcher.dart | 4 +- .../association_page/association_page.dart | 162 +++++++++------ .../pages/association_page/member_card.dart | 110 ++++++++++ .../ui/pages/main_page/association_cards.dart | 86 ++++++++ .../ui/pages/main_page/main_page.dart | 190 ++++++++---------- .../ui/pages/main_page/member_cards.dart | 73 ------- .../ui/pages/main_page/research_bar.dart | 56 ++++++ .../member_detail_page.dart | 99 +++++---- lib/phonebook/ui/phonebook.dart | 10 +- lib/phonebook/ui/top_bar.dart | 10 +- 24 files changed, 688 insertions(+), 349 deletions(-) rename lib/phonebook/class/{completeMember.dart => complete_member.dart} (80%) create mode 100644 lib/phonebook/providers/association_member_list_provider.dart create mode 100644 lib/phonebook/providers/complete_member_provider.dart create mode 100644 lib/phonebook/repositories/association_member_repository.dart create mode 100644 lib/phonebook/repositories/member_repository.dart create mode 100644 lib/phonebook/ui/pages/association_page/member_card.dart create mode 100644 lib/phonebook/ui/pages/main_page/association_cards.dart delete mode 100644 lib/phonebook/ui/pages/main_page/member_cards.dart create mode 100644 lib/phonebook/ui/pages/main_page/research_bar.dart diff --git a/lib/phonebook/class/association.dart b/lib/phonebook/class/association.dart index a5628b34d..4787bee7f 100644 --- a/lib/phonebook/class/association.dart +++ b/lib/phonebook/class/association.dart @@ -2,20 +2,24 @@ class Association{ Association({ required this.id, required this.name, + required this.description, }); late final String id; late final String name; + late final String description; Association.fromJSON(Map json){ id = json['id']; name = json['name']; + description = json['description']; } Map toJSON(){ final data = { 'id': id, 'name': name, + 'description': description, }; return data; } @@ -23,15 +27,23 @@ class Association{ Association copyWith({ String? id, String? name, + String? description, }) { return Association( id: id ?? this.id, name: name ?? this.name, + description: description ?? this.description, ); } Association.empty(){ id = ""; name = ""; + description = ""; + } + + @override + String toString(){ + return "Nom : $name, id : $id, description : $description"; } } \ No newline at end of file diff --git a/lib/phonebook/class/completeMember.dart b/lib/phonebook/class/complete_member.dart similarity index 80% rename from lib/phonebook/class/completeMember.dart rename to lib/phonebook/class/complete_member.dart index b239e4a6d..a080311b5 100644 --- a/lib/phonebook/class/completeMember.dart +++ b/lib/phonebook/class/complete_member.dart @@ -1,8 +1,4 @@ -import 'package:flutter/widgets.dart'; import 'package:myecl/phonebook/class/post.dart'; -import 'package:tuple/tuple.dart'; -import 'role.dart'; -import 'association.dart'; import 'member.dart'; class CompleteMember{ @@ -16,8 +12,8 @@ class CompleteMember{ CompleteMember.fromJSON(Map json){ - member = json['user']; - post = json['post']; + member = Member.fromJSON(json['user']); + post = json['post'].map((post) => Post.fromJSON(post)).toList(); } Map toJSON(){ diff --git a/lib/phonebook/class/member.dart b/lib/phonebook/class/member.dart index 2eff486c3..5aab73cc3 100644 --- a/lib/phonebook/class/member.dart +++ b/lib/phonebook/class/member.dart @@ -53,6 +53,6 @@ class Member{ firstname = "prénom"; nickname = null; id = ""; - email = ""; + email = "email.test@empty.useless"; } } \ No newline at end of file diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index 893531fe2..0c151bd43 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -4,8 +4,6 @@ import 'package:myecl/phonebook/repositories/association_repository.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/tools/providers/list_notifier.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; -import 'package:myecl/user/class/user.dart'; -import 'package:myecl/user/providers/user_provider.dart'; class AssociationListNotifier extends ListNotifier { final AssociationRepository associationRepository = AssociationRepository(); @@ -14,8 +12,8 @@ class AssociationListNotifier extends ListNotifier { associationRepository.setToken(token); } - Future>> loadAssociations() async { - return await loadList(associationRepository.getAssociationList); + Future>> loadAssociations([String? filter]) async { + return await loadList(() async => associationRepository.getAssociationList(filter!)); } // Future>> loadAssociationsFromUser(User user) async { diff --git a/lib/phonebook/providers/association_member_list_provider.dart b/lib/phonebook/providers/association_member_list_provider.dart new file mode 100644 index 000000000..242753ea7 --- /dev/null +++ b/lib/phonebook/providers/association_member_list_provider.dart @@ -0,0 +1,31 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/auth/providers/openid_provider.dart'; +import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/repositories/association_member_repository.dart'; +import 'package:myecl/tools/providers/list_notifier.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; + +class AssociationMemberListNotifier extends ListNotifier { + final AssociationMemberRepository associationMemberRepository = AssociationMemberRepository(); + AssociationMemberListNotifier({required String token}) + : super(const AsyncValue.loading()) { + associationMemberRepository.setToken(token); + } + + Future>> loadMembers(String associationId) async { + return await loadList(() async => associationMemberRepository.getAssociationMemberList(associationId)); + } +} + +final associationMemberListProvider = + StateNotifierProvider>>( + (ref) { + final token = ref.watch(tokenProvider); + AssociationMemberListNotifier provider = AssociationMemberListNotifier(token: token); + tokenExpireWrapperAuth(ref, () async { + final association = ref.watch(associationProvider); + await provider.loadMembers(association.id); + }); + return provider; +}); \ No newline at end of file diff --git a/lib/phonebook/providers/association_picture_provider.dart b/lib/phonebook/providers/association_picture_provider.dart index b22132a19..a30527ea0 100644 --- a/lib/phonebook/providers/association_picture_provider.dart +++ b/lib/phonebook/providers/association_picture_provider.dart @@ -12,17 +12,25 @@ import 'package:myecl/tools/providers/single_notifier.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:path_provider/path_provider.dart'; +final associationPictureProvider = + StateNotifierProvider>((ref) { + final token = ref.watch(tokenProvider); + AssociationPictureNotifier notifier = AssociationPictureNotifier(token); + return notifier; +}); + + class AssociationPictureNotifier extends SingleNotifier { - final AssociationPictureRepository _associationPictureRepository = + final AssociationPictureRepository associationPictureRepository = AssociationPictureRepository(); final ImagePicker _picker = ImagePicker(); AssociationPictureNotifier(String token) : super(const AsyncLoading()) { - _associationPictureRepository.setToken(token); + associationPictureRepository.setToken(token); } - Future> getAssociationPicture(String userId) async { + Future> getAssociationPicture(String associationId) async { return await load( - () async => _associationPictureRepository.getAssociationPicture(userId)); + () async => associationPictureRepository.getAssociationPicture(associationId)); } Future setAssociationPicture(ImageSource source, String associationId) async { @@ -32,7 +40,7 @@ class AssociationPictureNotifier extends SingleNotifier { await _picker.pickImage(source: source, imageQuality: 20); if (image != null) { try { - final i = await _associationPictureRepository.addAssociationPicture(image.path, associationId); + final i = await associationPictureRepository.addAssociationPicture(image.path, associationId); state = AsyncValue.data(i); return true; } catch (e) { @@ -75,7 +83,7 @@ class AssociationPictureNotifier extends SingleNotifier { ); if (croppedFile != null) { try { - final i = await _associationPictureRepository + final i = await associationPictureRepository .addAssociationPicture(croppedFile.path, associationId); state = AsyncValue.data(i); return true; @@ -93,9 +101,4 @@ class AssociationPictureNotifier extends SingleNotifier { } } -final associationPictureProvider = - StateNotifierProvider>((ref) { - final token = ref.watch(tokenProvider); - AssociationPictureNotifier notifier = AssociationPictureNotifier(token); - return notifier; -}); + diff --git a/lib/phonebook/providers/complete_member_provider.dart b/lib/phonebook/providers/complete_member_provider.dart new file mode 100644 index 000000000..936547928 --- /dev/null +++ b/lib/phonebook/providers/complete_member_provider.dart @@ -0,0 +1,15 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/phonebook/class/complete_member.dart'; + + +final completeMemberProvider = StateNotifierProvider((ref) { + return CompleteMemberProvider(); +}); + +class CompleteMemberProvider extends StateNotifier { + CompleteMemberProvider() : super(CompleteMember.empty()); + + void setCompleteMember(CompleteMember i) { + state = i; + } +} \ No newline at end of file diff --git a/lib/phonebook/providers/member_provider.dart b/lib/phonebook/providers/member_provider.dart index 3d6118930..dc499e6ed 100644 --- a/lib/phonebook/providers/member_provider.dart +++ b/lib/phonebook/providers/member_provider.dart @@ -1,15 +1,20 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:myecl/phonebook/class/completeMember.dart'; +import 'package:myecl/phonebook/class/member.dart'; +import 'package:myecl/phonebook/repositories/member_repository.dart'; -final completeMemberProvider = StateNotifierProvider((ref) { - return CompleteMemberProvider(); +final memberProvider = StateNotifierProvider((ref) { + return MemberProvider(); }); -class CompleteMemberProvider extends StateNotifier { - CompleteMemberProvider() : super(CompleteMember.empty()); +class MemberProvider extends StateNotifier { + MemberProvider() : super(Member.empty()); - void setCompleteMember(CompleteMember i) { + void setMember(Member i) { state = i; } + + void getMember(String id) async { + state = await MemberRepository().getMember(id); + } } \ No newline at end of file diff --git a/lib/phonebook/providers/phonebook_page_provider.dart b/lib/phonebook/providers/phonebook_page_provider.dart index f74d3fd0b..55be99c9d 100644 --- a/lib/phonebook/providers/phonebook_page_provider.dart +++ b/lib/phonebook/providers/phonebook_page_provider.dart @@ -1,6 +1,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; -enum PhonebookPage { main, admin, memberDetail, addEditAssociation, addEditRoleMember, editRole, associationEditor} +enum PhonebookPage { main, admin, memberDetail, addEditRoleMember, editRole, associationEditor, associationPage} final phonebookPageProvider = StateNotifierProvider((ref) { diff --git a/lib/phonebook/repositories/association_member_repository.dart b/lib/phonebook/repositories/association_member_repository.dart new file mode 100644 index 000000000..8d21260c5 --- /dev/null +++ b/lib/phonebook/repositories/association_member_repository.dart @@ -0,0 +1,38 @@ +import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/class/role.dart'; +import 'package:myecl/tools/repository/repository.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:myecl/tools/exception.dart'; + +class AssociationMemberRepository extends Repository { + @override + // ignore: overridden_fields + final ext = "phonebook/association/"; + + Future> getAssociationMemberList(String associationId) async { + return List.from( + (await getList(suffix: "$associationId/members")).map((x) => CompleteMember.fromJSON(x))); + } + + Future addMember(Association association, CompleteMember member, Role role) async { + await create({"member_id": member.member.id, "association_id": association.id, "roleId": role.id}, + suffix: "membership"); + return true; + } + + Future deleteMember(Association association, CompleteMember member) async { + final response = await http.delete( + Uri.parse("$host${ext}membership"), + headers: headers, + body: json.encode({"member_id": member.member.id, "association_id": association.id})); + if (response.statusCode == 204) { + return true; + } else if (response.statusCode == 403) { + throw AppException(ErrorType.tokenExpire, response.body); + } else { + throw AppException(ErrorType.notFound, "Failed to update item"); + } + } +} \ No newline at end of file diff --git a/lib/phonebook/repositories/association_picture_repository.dart b/lib/phonebook/repositories/association_picture_repository.dart index 1fad48f7e..b24a47d81 100644 --- a/lib/phonebook/repositories/association_picture_repository.dart +++ b/lib/phonebook/repositories/association_picture_repository.dart @@ -4,14 +4,14 @@ import 'package:myecl/tools/repository/logo_repository.dart'; class AssociationPictureRepository extends LogoRepository { @override // ignore: overridden_fields - final ext = 'phonebook/'; + final ext = 'phonebook/association/'; Future getAssociationPicture(String associationId) async { - return await getLogo(associationId, suffix: "/association-picture/"); + return await getLogo(associationId, suffix: "/picture"); } Future addAssociationPicture(String path, String associationId) async { final image = await saveLogoToTemp(path); - return await addLogo(image.path, associationId, suffix: "/association-picture"); + return await addLogo(image.path, associationId, suffix: "/picture"); } } diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index e31988cb3..dccfd89b3 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -10,9 +10,13 @@ class AssociationRepository extends Repository { // ignore: overridden_fields final ext = "phonebook/association/"; - Future> getAssociationList() async { + Future> getAssociationList([String? filter]) async { + String suffix = ""; + if (filter != null) { + suffix = "?filter=$filter"; + } return List.from( - (await getList()).map((x) => Association.fromJSON(x))); + (await getList(suffix: suffix)).map((x) => Association.fromJSON(x))); } Future getAssociation(String associationId) async { @@ -30,24 +34,4 @@ class AssociationRepository extends Repository { Future createAssociation(Association association) async { return Association.fromJSON(await create(association.toJSON())); } - - Future addMember(Association association, SimpleUser user) async { - await create({"user_id": user.id, "association_id": association.id}, - suffix: "membership"); - return true; - } - - Future deleteMember(Association association, SimpleUser user) async { - final response = await http.delete( - Uri.parse("$host${ext}membership"), - headers: headers, - body: json.encode({"user_id": user.id, "association_id": association.id})); - if (response.statusCode == 204) { - return true; - } else if (response.statusCode == 403) { - throw AppException(ErrorType.tokenExpire, response.body); - } else { - throw AppException(ErrorType.notFound, "Failed to update item"); - } - } } diff --git a/lib/phonebook/repositories/member_repository.dart b/lib/phonebook/repositories/member_repository.dart new file mode 100644 index 000000000..d707a91b5 --- /dev/null +++ b/lib/phonebook/repositories/member_repository.dart @@ -0,0 +1,23 @@ +import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/member.dart'; +import 'package:myecl/phonebook/class/post.dart'; +import 'package:myecl/tools/repository/repository.dart'; + +class MemberRepository extends Repository { + @override + // ignore: overridden_fields + final ext = "phonebook/member/"; + + Future> getMemberPostList(int memberId) async { + return List.from( + (await getList(suffix: "/$memberId/posts")).map((x) => Post.fromJSON(x))); + } + + Future getMember(String memberId) async { + return Member.fromJSON(await getOne(memberId)); + } + + Future getCompleteMember(String memberId) async { + return CompleteMember.fromJSON(await getOne(memberId, suffix: "complete")); + } +} \ No newline at end of file diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index 974895232..a4b03c07d 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -1,8 +1,10 @@ +import 'package:flutter/material.dart'; + class PhonebookTextConstants { static const String errorAssociationPicture = "Erreur lors de la modification de la photo d'association"; static const String phonebook = "Annuaire"; - static const String phonebookSearch = "Rechercher une personne par : "; + static const String phonebookSearch = "Rechercher"; static const String phonebookSearchName = "Nom/Prénom/Surnom"; static const String phonebookSearchRole = "Poste"; static const String phonebookSearchAssociation = "Association"; @@ -19,11 +21,11 @@ class PhonebookTextConstants { static const String association = "Association :"; static const String associationPure = "Association"; static const String rolePure = "Rôle"; - static const String name = "Nom"; - static const String firstname = "Prénom"; - static const String nickname = "Surnom"; - static const String email = "Email"; - static const String detail = "Détail"; + static const String name = "Nom :"; + static const String firstname = "Prénom :"; + static const String nickname = "Surnom :"; + static const String email = "Email :"; + static const String detail = "Détail :"; static const String addRole = "Ajouter un rôle"; static const String adminPage = "Page Administrateur"; static const String addEditAssociation = "Ajouter/Modifier une association"; @@ -35,4 +37,12 @@ class PhonebookTextConstants { static const String deleteAssociation = "Supprimer l'association ?"; static const String deletedAssociation = "Association supprimée"; static const String deletingError = "Erreur lors de la suppression"; + static const String errorLoadAssociationList = "Erreur lors du chargement de la liste des associations"; + static const String associationDetail = "Détail de l'association :"; + + static const String errorLoadAssociationMember = "Erreur lors du chargement des membres de l'association"; +} + +class PhonebookColorConstants{ + static const Color textDark = Color(0xFF1D1D1D); } \ No newline at end of file diff --git a/lib/phonebook/ui/page_switcher.dart b/lib/phonebook/ui/page_switcher.dart index 475a04cf9..f4bdc5e3c 100644 --- a/lib/phonebook/ui/page_switcher.dart +++ b/lib/phonebook/ui/page_switcher.dart @@ -22,14 +22,14 @@ class PageSwitcher extends ConsumerWidget { return const AdminPage(); case PhonebookPage.memberDetail: return const MemberDetailPage(); - case PhonebookPage.addEditAssociation: - return const AssociationPage(); case PhonebookPage.addEditRoleMember: return const RoleMemberPage(); case PhonebookPage.editRole: return const RolePage(); case PhonebookPage.associationEditor: return const AssociationEditorPage(); + case PhonebookPage.associationPage: + return const AssociationPage(); default: return const Text('Unknown page'); } diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index 81ca1e736..6d3a24399 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -1,73 +1,123 @@ import 'package:flutter/material.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/drawer/providers/page_provider.dart'; import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/class/completeMember.dart'; +import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/member.dart'; +import 'package:myecl/phonebook/class/post.dart'; +import 'package:myecl/phonebook/class/role.dart'; +import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:myecl/admin/providers/is_admin.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/ui/pages/association_page/member_card.dart'; class AssociationPage extends HookConsumerWidget { const AssociationPage({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { - final associationNotifier = ref.watch(associationProvider.notifier); + final association = ref.watch(associationProvider); final pageNotifier = ref.watch(phonebookPageProvider.notifier); - final search = useState(""); + final associationPicture = ref.watch(associationPictureProvider); + final associationMemberList = ref.watch(associationMemberListProvider); + return Column(children: [ - const Text(PhonebookTextConstants.phonebookSearchField), - const SizedBox( - width: 5), - Container( - padding: const EdgeInsets.symmetric(horizontal: 5), - decoration: BoxDecoration( - border: Border.all(color: Colors.black), - borderRadius: BorderRadius.circular(10)), - child: TextField( - decoration: const InputDecoration( - border: InputBorder.none, - ), - onChanged: (String value) { - search.value = value; - }, - )), - ElevatedButton( - onPressed: (){ - associationNotifier.setAssociation(Association.empty()); - pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); - }, - child: const Text(PhonebookTextConstants.addAssociation)), - Container( - margin: const EdgeInsets.symmetric(vertical: 7), - color: Colors.black, - height: 2, - ), - Expanded( - child: ListView.builder( - padding: const EdgeInsets.all(1), - itemCount: 10, - itemBuilder: (BuildContext context, int index) { - return Card( - child: ListTile( - title: Row( - children: [ - Expanded( - child: Text( - "Nom $index Prénom $index (Surnom $index)")), - ], - ), - subtitle: Text("Email: $index"), - onTap: () { - associationNotifier.setAssociation( - Association.empty()); - pageNotifier.setPhonebookPage( - PhonebookPage.associationEditor); - }, - )); - }))]); + const Text(PhonebookTextConstants.associationDetail), + const SizedBox(height: 20,), + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + spreadRadius: 5, + blurRadius: 10, + offset: const Offset(2, 3), + ), + ], + ), + child: associationPicture.when( + data: (picture) { + return CircleAvatar( + radius: 80, + backgroundImage: picture.isEmpty + ? const AssetImage('assets/images/logo_alpha.png') + : Image.memory(picture).image, + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return const Center( + child: Text(PhonebookTextConstants.errorLoadAssociationPicture), + ); + }, + ), + ), + const SizedBox(height: 20,), + Text(association.name, + style: const TextStyle( + fontSize: 20, + color: Colors.black + ), + ), + const SizedBox(height: 10,), + Text(association.description, + style: const TextStyle( + fontSize: 15, + color: Colors.black + ), + ), + const SizedBox(height: 20,), + SingleChildScrollView( + scrollDirection: Axis.vertical, + physics: const BouncingScrollPhysics(), + child: associationMemberList.when( + data: (members) { + return Column( + children: members.map((member) => + MemberCard(member: member) + ).toList() + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + //return const Center( + // child: Text(PhonebookTextConstants.errorLoadAssociationMember), + List members = [ + CompleteMember( + member: Member(name: 'Dupond', firstname: 'Michel', nickname: 'Testouille', id: '1', email: 'test1@useless'), + post: [Post(association: association, role: Role(id: '1', name: 'Prez\''))]), + CompleteMember( + member: Member(name: 'Debouck', firstname: 'Frank', nickname: 'Chad', id: '2', email: 'test2@useless'), + post: [Post(association: association, role: Role(id: '2', name: 'Trez\''))]), + CompleteMember( + member: Member(name: 'Ray', firstname: 'Pascal', nickname: 'Salut', id: '3', email: 'test3@useless'), + post: [Post(association: association, role: Role(id: '3', name: 'SG'))]), + CompleteMember( + member: Member(name: 'Guarriguenc', firstname: 'Jean-Luc', nickname: 'Cascouille', id: '4', email: 'test4@useless'), + post: [Post(association: association, role: Role(id: '4', name: 'Fillot')), + Post(association: Association(id: '12',name: 'testTest', description: 'JSP frère'), + role: Role(id: '5', name: 'Bourrin'))]), + ]; + return Column( + children: members.map((member) => + MemberCard(member: member) + ).toList() + ); + }, + ) + ), + ]); } -} \ No newline at end of file +} diff --git a/lib/phonebook/ui/pages/association_page/member_card.dart b/lib/phonebook/ui/pages/association_page/member_card.dart new file mode 100644 index 000000000..1baa5da6d --- /dev/null +++ b/lib/phonebook/ui/pages/association_page/member_card.dart @@ -0,0 +1,110 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/user/providers/profile_picture_provider.dart'; +import 'package:myecl/phonebook/providers/complete_member_provider.dart'; +import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; + +class MemberCard extends HookConsumerWidget { + const MemberCard({super.key, required this.member}); + + final CompleteMember member; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final pageNotifier = ref.watch(phonebookPageProvider.notifier); + final memberNotifier = ref.watch(completeMemberProvider.notifier); + final profilePicture = ref.watch(profilePictureProvider); + final association = ref.watch(associationProvider); + + return GestureDetector( + onTap: () { + memberNotifier.setCompleteMember(member); + pageNotifier.setPhonebookPage(PhonebookPage.memberDetail); + }, + child: Container( + margin: const EdgeInsets.all(10), + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + border: Border.all(), + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(20)), + ), + child: Row( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + spreadRadius: 5, + blurRadius: 10, + offset: const Offset(2, 3), + ), + ], + ), + child: profilePicture.when( + data: (picture) { + return CircleAvatar( + radius: 20, + backgroundImage: picture.isEmpty + ? const AssetImage('assets/images/logo_alpha.png') + : Image.memory(picture).image, + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return const Center( + child: Text( + PhonebookTextConstants.errorLoadAssociationPicture), + ); + }, + ), + ), + const SizedBox(width: 10), + SizedBox( + width: 400, + child: Column( + children: [ + Text( + "${member.member.name} ${member.member.firstname} (${member.member.nickname})", + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 5), + Text( + member.member.email, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + SizedBox( + width: 200, + child: Center( + child: Text( + member.post.firstWhere((element) => element.association.id == association.id).role.name, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ) + ) + ], + ))); + } +} diff --git a/lib/phonebook/ui/pages/main_page/association_cards.dart b/lib/phonebook/ui/pages/main_page/association_cards.dart new file mode 100644 index 000000000..c0109c398 --- /dev/null +++ b/lib/phonebook/ui/pages/main_page/association_cards.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/providers/association_picture_provider.dart'; +import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; + +class AssociationCards extends HookConsumerWidget { + const AssociationCards({super.key, + required this.association + }); + + final Association association; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final pageNotifier = ref.watch(phonebookPageProvider.notifier); + final associationNotifier = ref.watch(associationProvider.notifier); + final associationPicture = ref.watch(associationPictureProvider); + + return GestureDetector( + onTap: () { + associationNotifier.setAssociation(association); + pageNotifier.setPhonebookPage(PhonebookPage.associationPage); + }, + child: Container( + margin: const EdgeInsets.all(10), + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + border: Border.all(), + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(20)), + ), + + child: Row( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + spreadRadius: 5, + blurRadius: 10, + offset: const Offset(2, 3), + ), + ], + ), + + child: + associationPicture.when(data: (picture){ + return CircleAvatar( + radius: 80, + backgroundImage: picture.isEmpty ? + const AssetImage('assets/images/profile.png') : + Image.memory(picture).image, + ); + }, loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, error: (e, s) { + return const Center( + child: Text(PhonebookTextConstants.errorLoadAssociationPicture), + ); + }, + ), + ), + const SizedBox(width: 10), + SizedBox( + width: 200, + child: Text( + association.name, + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ) + ) + ); + } +} \ No newline at end of file diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 7e31feff5..3fa1cf51c 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -1,123 +1,103 @@ import 'package:flutter/material.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/drawer/providers/page_provider.dart'; -import 'package:myecl/phonebook/class/completeMember.dart'; -import 'package:myecl/phonebook/providers/member_provider.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:myecl/admin/providers/is_admin.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; -import 'package:myecl/phonebook/ui/pages/main_page/member_cards.dart'; +import 'package:myecl/phonebook/ui/pages/main_page/association_cards.dart'; +import 'package:myecl/phonebook/ui/pages/main_page/research_bar.dart'; class MainPage extends HookConsumerWidget { const MainPage({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { - final search = useState(""); - final searchType = useState("name"); final isAdmin = ref.watch(isAdminProvider); final pageNotifier = ref.watch(phonebookPageProvider.notifier); - return Container( - padding: const EdgeInsets.all(10), - child: Stack( - children: [ - Column(children: [ - const SizedBox(height: 60), - Row( - children: [ - const Text(PhonebookTextConstants.phonebookSearch), - DropdownButton( - value: searchType.value, - icon: const Icon(Icons.arrow_downward), - iconSize: 14, - elevation: 16, - style: const TextStyle(color: Colors.deepPurple), - underline: Container( - height: 2, - color: Colors.deepPurpleAccent, - ), - onChanged: (String? newValue) { - searchType.value = newValue!; - }, - items: >[ - [PhonebookTextConstants.phonebookSearchName, "name"], - [PhonebookTextConstants.phonebookSearchRole, "role"], - [ - PhonebookTextConstants.phonebookSearchAssociation, - "association" - ] - ].map>((List value) { - return DropdownMenuItem( - value: value[1], - child: Text(value[0]), - ); - }).toList(), - ) - ], - ), - Row(children: [ - const Text(PhonebookTextConstants.phonebookSearchField), - const SizedBox(width: 5), - Expanded( - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 5), - decoration: BoxDecoration( - border: Border.all(color: Colors.black), - borderRadius: BorderRadius.circular(10)), - child: TextField( - decoration: const InputDecoration( - border: InputBorder.none, - ), - onChanged: (String value) { - search.value = value; - }, - ))) - ]), - Container( - margin: const EdgeInsets.symmetric(vertical: 7), + final associationList = ref.watch(allAssociationListProvider); + return Stack( + children: [ + Column( + children: [ + const ResearchBar(), + const SizedBox(width: 10), + SingleChildScrollView( + scrollDirection: Axis.vertical, + physics: const BouncingScrollPhysics(), + child: associationList.when( + data: (data) { + return Column( + children: data.map((association) { + return AssociationCards(association: association); + }).toList(), + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + List assos = [ + Association(id: '1', name: 'test1', description: 'description test1'), + Association(id: '2', name: 'test2', description: 'description test2'), + Association(id: '3', name: 'test3', description: 'description test3'), + Association(id: '4', name: 'test4', description: 'description test4'), + Association(id: '5', name: 'test5', description: 'description test5'), + Association(id: '6', name: 'test6', description: 'description test6'), + Association(id: '7', name: 'test7', description: 'description test7'), + ]; + return Column( + children: assos.map((association) { + return AssociationCards(association: association); + }).toList(), + ); + + //return const Center( + // child: Text(PhonebookTextConstants.errorLoadAssociationList), + //); + }, + )) + ], + ), + if (isAdmin) + Positioned( + top: 15, + right: 15, + child: GestureDetector( + onTap: () { + pageNotifier.setPhonebookPage(PhonebookPage.admin); + }, + child: Container( + padding: + const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: BoxDecoration( color: Colors.black, - height: 2, - ), - const Expanded( - child: MemberCards() ) - ]), - if (isAdmin) - Positioned( - top: 15, - right: 15, - child: GestureDetector( - onTap: () { - pageNotifier.setPhonebookPage(PhonebookPage.admin); - }, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 10, - offset: const Offset(0, 5)) - ]), - child: Row( - children: const [ - HeroIcon(HeroIcons.userGroup, color: Colors.white), - SizedBox(width: 10), - Text(PhonebookTextConstants.admin, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.white)), - ], - ), - ), - ), - ) - ], - )); + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + blurRadius: 10, + offset: const Offset(0, 5)) + ]), + child: Row( + children: const [ + HeroIcon(HeroIcons.userGroup, color: Colors.white), + SizedBox(width: 10), + Text(PhonebookTextConstants.admin, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.white)), + ], + ), + ), + ), + ) + ], + ); } } diff --git a/lib/phonebook/ui/pages/main_page/member_cards.dart b/lib/phonebook/ui/pages/main_page/member_cards.dart deleted file mode 100644 index 75e33773b..000000000 --- a/lib/phonebook/ui/pages/main_page/member_cards.dart +++ /dev/null @@ -1,73 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/class/completeMember.dart'; -import 'package:myecl/phonebook/providers/association_picture_provider.dart'; -import 'package:myecl/phonebook/providers/member_provider.dart'; -import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; -import 'package:myecl/phonebook/tools/constants.dart'; - -class MemberCards extends HookConsumerWidget { - const MemberCards({super.key}); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final pageNotifier = ref.watch(phonebookPageProvider.notifier); - final completeMemberNotifier = ref.watch(completeMemberProvider.notifier); - final associationPicture = ref.watch(associationPictureProvider); - - return ListView.builder( - padding: const EdgeInsets.all(1), - itemCount: 10, - itemBuilder: (BuildContext context, int index) { - return Card( - child: ListTile( - title: Row( - children: [ - Expanded( - child: Text( - "Nom $index Prénom $index (Surnom $index)")), - Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - spreadRadius: 5, - blurRadius: 10, - offset: const Offset(2, 3), - ), - ], - ), - - child: - associationPicture.when(data: (picture){ - return CircleAvatar( - radius: 80, - backgroundImage: picture.isEmpty ? - const AssetImage('assets/images/profile.png') : - Image.memory(picture).image, - ); - }, loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, error: (e, s) { - return const Center( - child: Text(PhonebookTextConstants.errorLoadAssociationPicture), - ); - }, - ), - ) - ], - ), - subtitle: Text("Email: $index"), - onTap: () { - completeMemberNotifier - .setCompleteMember(CompleteMember.empty()); - pageNotifier.setPhonebookPage( - PhonebookPage.memberDetail); - }, - )); - }); - } -} \ No newline at end of file diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart new file mode 100644 index 000000000..3abfa60db --- /dev/null +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/association_list_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; + +class ResearchBar extends HookConsumerWidget { + const ResearchBar({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final associationListNotifier = + ref.watch(allAssociationListProvider.notifier); + final focusNode = useFocusNode(); + final editingController = useTextEditingController(); + return Container( + width: 300, + child: TextField( + onChanged: (value) { + tokenExpireWrapper(ref, () async { + if (editingController.text.isNotEmpty) { + await associationListNotifier + .loadAssociations(editingController.text); + } else { + await associationListNotifier.loadAssociations(); + } + }); + }, + focusNode: focusNode, + controller: editingController, + cursorColor: PhonebookColorConstants.textDark, + decoration: const InputDecoration( + labelText: PhonebookTextConstants.associationPure, + labelStyle: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: PhonebookColorConstants.textDark), + suffixIcon: Icon( + Icons.search, + color: PhonebookColorConstants.textDark, + size: 30, + ), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: Colors.transparent, + ), + ), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: PhonebookColorConstants.textDark, + ), + )), + )); + } +} diff --git a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart index de4052721..419acdab3 100644 --- a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart +++ b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart @@ -3,7 +3,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/admin/providers/is_admin.dart'; import 'package:myecl/phonebook/class/post.dart'; -import 'package:myecl/phonebook/providers/member_provider.dart'; +import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/providers/post_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; @@ -17,46 +17,61 @@ class MemberDetailPage extends HookConsumerWidget { final pageNotifier = ref.watch(phonebookPageProvider.notifier); final memberProvider = ref.watch(completeMemberProvider); final postProviderNotifier = ref.watch(postProvider.notifier); - return Expanded( - child: Container( - margin: const EdgeInsets.all(10), - width: MediaQuery.of(context).size.width, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(50), - color: const Color.fromARGB(255, 187, 187, 187)), - child: Column(children: [ - const Text(PhonebookTextConstants.detail), - Text("${PhonebookTextConstants.name} ${memberProvider.member.name}"), - Text("${PhonebookTextConstants.firstname} ${memberProvider.member.firstname}"), - if (memberProvider.member.nickname != null) - Text("${PhonebookTextConstants.nickname} ${memberProvider.member.nickname!}"), - Text("${PhonebookTextConstants.email} ${memberProvider.member.email}"), - const Text(PhonebookTextConstants.association), //à changer pour dépendre du nombre d'associatione - for (var post in memberProvider.post) - Row(children: [ - Text("${post.association.name} : ${post.role.name}"), - if (isAdmin) - IconButton( - icon: const Icon(Icons.edit), - onPressed: () { - postProviderNotifier.setPost(post); - pageNotifier.setPhonebookPage( - PhonebookPage.addEditRoleMember); - }), - ]), - if (isAdmin) - ElevatedButton( - onPressed: () { - postProviderNotifier.setPost(Post.empty()); - pageNotifier - .setPhonebookPage(PhonebookPage.addEditRoleMember); - }, - child: Row( - children: const [ - Icon(Icons.add), - Text(PhonebookTextConstants.addRole) - ], - )) - ]))); + return Container( + margin: const EdgeInsets.all(10), + width: MediaQuery.of(context).size.width, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50), + color: const Color.fromARGB(255, 187, 187, 187)), + child: Column(children: [ + const Text(PhonebookTextConstants.detail), + Text("${PhonebookTextConstants.name} ${memberProvider.member.name}"), + Text( + "${PhonebookTextConstants.firstname} ${memberProvider.member.firstname}"), + if (memberProvider.member.nickname != null) + Text( + "${PhonebookTextConstants.nickname} ${memberProvider.member.nickname!}"), + Text( + "${PhonebookTextConstants.email} ${memberProvider.member.email}"), + const Text(PhonebookTextConstants + .association), //à changer pour dépendre du nombre d'associatione + Column(children: [ + for (var post in memberProvider.post) + Container( + margin: const EdgeInsets.all(10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50), + border: Border.all(), + color: const Color.fromARGB(255, 187, 187, 187)), + child: Row( + children: [ + const Spacer(flex: 1), + Text("${post.association.name} : ${post.role.name}", + style: const TextStyle(fontSize: 20)), + if (isAdmin) + IconButton( + icon: const Icon(Icons.edit), + onPressed: () { + postProviderNotifier.setPost(post); + pageNotifier.setPhonebookPage( + PhonebookPage.addEditRoleMember); + }), + const Spacer(flex: 1), + ])) + ]), + if (isAdmin) + ElevatedButton( + onPressed: () { + postProviderNotifier.setPost(Post.empty()); + pageNotifier + .setPhonebookPage(PhonebookPage.addEditRoleMember); + }, + child: Row( + children: const [ + Icon(Icons.add), + Text(PhonebookTextConstants.addRole) + ], + )) + ])); } } diff --git a/lib/phonebook/ui/phonebook.dart b/lib/phonebook/ui/phonebook.dart index 41995a6c1..6fba7517a 100644 --- a/lib/phonebook/ui/phonebook.dart +++ b/lib/phonebook/ui/phonebook.dart @@ -28,10 +28,7 @@ class PhonebookHomePage extends HookConsumerWidget { return true; } case PhonebookPage.memberDetail: - pageNotifier.setPhonebookPage(PhonebookPage.main); - break; - case PhonebookPage.addEditAssociation: - pageNotifier.setPhonebookPage(PhonebookPage.admin); + pageNotifier.setPhonebookPage(PhonebookPage.associationPage); break; case PhonebookPage.admin: pageNotifier.setPhonebookPage(PhonebookPage.main); @@ -43,7 +40,10 @@ class PhonebookHomePage extends HookConsumerWidget { pageNotifier.setPhonebookPage(PhonebookPage.admin); break; case PhonebookPage.associationEditor: - pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); + pageNotifier.setPhonebookPage(PhonebookPage.admin); + break; + case PhonebookPage.associationPage: + pageNotifier.setPhonebookPage(PhonebookPage.main); break; } return false; diff --git a/lib/phonebook/ui/top_bar.dart b/lib/phonebook/ui/top_bar.dart index 2d875733a..731535256 100644 --- a/lib/phonebook/ui/top_bar.dart +++ b/lib/phonebook/ui/top_bar.dart @@ -32,10 +32,7 @@ class TopBar extends HookConsumerWidget { controllerNotifier.toggle(); break; case PhonebookPage.memberDetail: - pageNotifier.setPhonebookPage(PhonebookPage.main); - break; - case PhonebookPage.addEditAssociation: - pageNotifier.setPhonebookPage(PhonebookPage.admin); + pageNotifier.setPhonebookPage(PhonebookPage.associationPage); break; case PhonebookPage.admin: pageNotifier.setPhonebookPage(PhonebookPage.main); @@ -47,7 +44,10 @@ class TopBar extends HookConsumerWidget { pageNotifier.setPhonebookPage(PhonebookPage.admin); break; case PhonebookPage.associationEditor: - pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); + pageNotifier.setPhonebookPage(PhonebookPage.admin); + break; + case PhonebookPage.associationPage: + pageNotifier.setPhonebookPage(PhonebookPage.main); break; } }, From b054832185e41a14ff22157ccf399fbfedc719d9 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:56:59 +0100 Subject: [PATCH 004/123] Major implementation (look description for detail) - switch from Post to Membership for comprehension purpose - improvement of providers to implement adding/deleting/modifying associations/memberships/roles - improvement of repositories to allow previous changes - creation of fake objects to test without back - remodeling of most admin, association editor, association, member detail UIs and sub-widgets - creation of global widgets deletion button and text input dialog --- lib/phonebook/class/complete_member.dart | 16 +- .../class/{post.dart => membership.dart} | 16 +- .../providers/association_list_provider.dart | 8 +- .../association_picture_provider.dart | 1 - .../providers/association_provider.dart | 46 ++++- .../providers/membership_provider.dart | 16 ++ lib/phonebook/providers/post_provider.dart | 16 -- .../providers/role_list_provider.dart | 64 +++++++ lib/phonebook/providers/role_provider.dart | 36 +++- .../association_member_repository.dart | 25 --- .../repositories/association_repository.dart | 24 ++- .../repositories/member_repository.dart | 8 +- .../repositories/role_repository.dart | 33 ++++ lib/phonebook/tools/constants.dart | 14 +- lib/phonebook/tools/fake_class.dart | 66 +++++++ ...ation_cards.dart => association_card.dart} | 13 +- lib/phonebook/ui/delete_button.dart | 70 ++++++++ .../ui/pages/admin_page/admin_page.dart | 109 +++++++---- .../ui/pages/admin_page/asso_ui.dart | 21 +++ .../ui/pages/admin_page/association_bar.dart | 121 ------------- .../admin_page/association_research_bar.dart | 69 +++++++ .../ui/pages/admin_page/role_bar.dart | 121 ------------- .../ui/pages/admin_page/role_card.dart | 117 ++++++++++++ .../pages/admin_page/role_research_bar.dart | 69 +++++++ .../association_editor_page.dart | 147 +++++++++------ .../member_editable_card.dart | 148 +++++++++++++++ .../association_page/association_page.dart | 169 ++++++++---------- .../pages/association_page/member_card.dart | 13 +- .../ui/pages/main_page/main_page.dart | 167 ++++++++--------- .../ui/pages/main_page/research_bar.dart | 15 +- .../member_detail_page.dart | 33 +--- .../role_member_page/role_member_page.dart | 32 ++-- lib/phonebook/ui/text_input_dialog.dart | 64 +++++++ 33 files changed, 1236 insertions(+), 651 deletions(-) rename lib/phonebook/class/{post.dart => membership.dart} (76%) create mode 100644 lib/phonebook/providers/membership_provider.dart delete mode 100644 lib/phonebook/providers/post_provider.dart create mode 100644 lib/phonebook/providers/role_list_provider.dart create mode 100644 lib/phonebook/repositories/role_repository.dart create mode 100644 lib/phonebook/tools/fake_class.dart rename lib/phonebook/ui/{pages/main_page/association_cards.dart => association_card.dart} (85%) create mode 100644 lib/phonebook/ui/delete_button.dart delete mode 100644 lib/phonebook/ui/pages/admin_page/association_bar.dart create mode 100644 lib/phonebook/ui/pages/admin_page/association_research_bar.dart delete mode 100644 lib/phonebook/ui/pages/admin_page/role_bar.dart create mode 100644 lib/phonebook/ui/pages/admin_page/role_card.dart create mode 100644 lib/phonebook/ui/pages/admin_page/role_research_bar.dart create mode 100644 lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart create mode 100644 lib/phonebook/ui/text_input_dialog.dart diff --git a/lib/phonebook/class/complete_member.dart b/lib/phonebook/class/complete_member.dart index a080311b5..4d9192b7a 100644 --- a/lib/phonebook/class/complete_member.dart +++ b/lib/phonebook/class/complete_member.dart @@ -1,42 +1,42 @@ -import 'package:myecl/phonebook/class/post.dart'; +import 'package:myecl/phonebook/class/membership.dart'; import 'member.dart'; class CompleteMember{ CompleteMember({ required this.member, - required this.post, + required this.memberships, }); late final Member member; - late final List post; + late final List memberships; CompleteMember.fromJSON(Map json){ member = Member.fromJSON(json['user']); - post = json['post'].map((post) => Post.fromJSON(post)).toList(); + memberships = json['membership'].map((membership) => Membership.fromJSON(membership)).toList(); } Map toJSON(){ final data = { 'member': member.id, - 'post': post.map((e) => [e.association.id, e.role.id]), + 'membership': memberships.map((e) => [e.association.id, e.role.id]), }; return data; } CompleteMember copyWith({ Member? member, - List? post, + List? membership, }) { return CompleteMember( member: member ?? this.member, - post: post ?? this.post, + memberships: membership ?? this.memberships, ); } CompleteMember.empty(){ member = Member.empty(); - post = []; + memberships = []; } } diff --git a/lib/phonebook/class/post.dart b/lib/phonebook/class/membership.dart similarity index 76% rename from lib/phonebook/class/post.dart rename to lib/phonebook/class/membership.dart index 0a9e5e538..c3d3f457a 100644 --- a/lib/phonebook/class/post.dart +++ b/lib/phonebook/class/membership.dart @@ -1,8 +1,8 @@ import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/role.dart'; -class Post{ - Post({ +class Membership{ + Membership({ required this.association, required this.role, }); @@ -10,7 +10,7 @@ class Post{ late final Association association; late final Role role; - Post.fromJSON(Map json){ + Membership.fromJSON(Map json){ association = json['association']; role = json['role']; } @@ -23,26 +23,26 @@ class Post{ return data; } - Post copyWith({ + Membership copyWith({ Association? association, Role? role, }) { - return Post( + return Membership( association: association ?? this.association, role: role ?? this.role, ); } - Post.empty(){ + Membership.empty(){ association = Association.empty(); role = Role.empty(); } - Post setAssociation(String name, String id) { + Membership setAssociation(String name, String id) { return copyWith(association: association.copyWith(name: name, id: id)); } - Post setRole(String name, String id) { + Membership setRole(String name, String id) { return copyWith(role: role.copyWith(name: name, id: id)); } } \ No newline at end of file diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index 0c151bd43..1a4fd62d9 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -52,15 +52,15 @@ class AssociationListNotifier extends ListNotifier { } } -final allAssociationListProvider = +final associationListProvider = StateNotifierProvider>>( (ref) { final token = ref.watch(tokenProvider); - AssociationListNotifier provider = AssociationListNotifier(token: token); + AssociationListNotifier notifier = AssociationListNotifier(token: token); tokenExpireWrapperAuth(ref, () async { - await provider.loadAssociations(); + await notifier.loadAssociations(); }); - return provider; + return notifier; }); //final userAssociationListNotifier = diff --git a/lib/phonebook/providers/association_picture_provider.dart b/lib/phonebook/providers/association_picture_provider.dart index a30527ea0..27187f58f 100644 --- a/lib/phonebook/providers/association_picture_provider.dart +++ b/lib/phonebook/providers/association_picture_provider.dart @@ -9,7 +9,6 @@ import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/repositories/association_picture_repository.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/providers/single_notifier.dart'; -import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:path_provider/path_provider.dart'; final associationPictureProvider = diff --git a/lib/phonebook/providers/association_provider.dart b/lib/phonebook/providers/association_provider.dart index 468c6e8c7..72dfaf1a2 100644 --- a/lib/phonebook/providers/association_provider.dart +++ b/lib/phonebook/providers/association_provider.dart @@ -1,15 +1,45 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/role.dart'; +import 'package:myecl/phonebook/repositories/association_repository.dart'; +import 'package:myecl/tools/providers/single_notifier.dart'; -final associationProvider = StateNotifierProvider((ref) { - return AssociationProvider(); -}); +class AssociationNotifier extends SingleNotifier { + final AssociationRepository associationRepository = AssociationRepository(); + AssociationNotifier({required String token}) : super(const AsyncValue.loading()) { + associationRepository.setToken(token); + } + + Future> loadAssociation(String associationId) async { + return await load(() async => associationRepository.getAssociation(associationId)); + } + + Future addMember(Association association, CompleteMember user, Role role) async { + return await update( + (association) async => associationRepository.addMember(association, user, role), association); + } -class AssociationProvider extends StateNotifier { -AssociationProvider() : super(Association.empty()); + Future deleteMember(Association association, CompleteMember user) async { + return await update( + (association) async => associationRepository.deleteMember(association, user), association); + } - void setAssociation(Association i) { - state = i; + void setAssociation(Association association) { + state = AsyncValue.data(association); } -} \ No newline at end of file +} + +final asyncAssociationProvider = + StateNotifierProvider>((ref) { + final token = ref.watch(tokenProvider); + return AssociationNotifier(token: token); +}); + +final associationProvider = Provider((ref) { + final association = ref.watch(asyncAssociationProvider); + return association.maybeWhen( + data: (association) => association, orElse: () => Association.empty()); +}); \ No newline at end of file diff --git a/lib/phonebook/providers/membership_provider.dart b/lib/phonebook/providers/membership_provider.dart new file mode 100644 index 000000000..e47ee35a1 --- /dev/null +++ b/lib/phonebook/providers/membership_provider.dart @@ -0,0 +1,16 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/phonebook/class/membership.dart'; + + + +final membershipProvider = StateNotifierProvider((ref) { + return MembershipProvider(); +}); + +class MembershipProvider extends StateNotifier { +MembershipProvider() : super(Membership.empty()); + + void setMembership(Membership i) { + state = i; + } +} \ No newline at end of file diff --git a/lib/phonebook/providers/post_provider.dart b/lib/phonebook/providers/post_provider.dart deleted file mode 100644 index 79b75c7dc..000000000 --- a/lib/phonebook/providers/post_provider.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:myecl/phonebook/class/post.dart'; - - - -final postProvider = StateNotifierProvider((ref) { - return PostProvider(); -}); - -class PostProvider extends StateNotifier { -PostProvider() : super(Post.empty()); - - void setPost(Post i) { - state = i; - } -} \ No newline at end of file diff --git a/lib/phonebook/providers/role_list_provider.dart b/lib/phonebook/providers/role_list_provider.dart new file mode 100644 index 000000000..d0ff253c0 --- /dev/null +++ b/lib/phonebook/providers/role_list_provider.dart @@ -0,0 +1,64 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/phonebook/class/role.dart'; +import 'package:myecl/phonebook/repositories/role_repository.dart'; +import 'package:myecl/auth/providers/openid_provider.dart'; +import 'package:myecl/tools/providers/list_notifier.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; + +class RoleListNotifier extends ListNotifier { + final RoleRepository roleRepository = RoleRepository(); + RoleListNotifier({required String token}) + : super(const AsyncValue.loading()) { + roleRepository.setToken(token); + } + + Future>> loadRoles([String? filter]) async { + return await loadList(() async => roleRepository.getRoleList(filter!)); + } + +// Future>> loadRolesFromUser(User user) async { +// return await loadList(() async { +// return user.roles; +// }); +// } + + Future createRole(Role role) async { + return await add(roleRepository.createRole, role); + } + + Future updateRole(Role role) async { + return await update( + roleRepository.updateRole, + (roles, role) => + roles..[roles.indexWhere((g) => g.id == role.id)] = role, + role); + } + + Future deleteRole(Role role) async { + return await delete( + roleRepository.deleteRole, + (roles, role) => roles..removeWhere((i) => i.id == role.id), + role.id, + role); + } + + void setRole(Role role) { + state.whenData( + (d) { + state = + AsyncValue.data(d..[d.indexWhere((g) => g.id == role.id)] = role); + }, + ); + } +} + +final roleListProvider = + StateNotifierProvider>>( + (ref) { + final token = ref.watch(tokenProvider); + RoleListNotifier provider = RoleListNotifier(token: token); + tokenExpireWrapperAuth(ref, () async { + await provider.loadRoles(); + }); + return provider; +}); diff --git a/lib/phonebook/providers/role_provider.dart b/lib/phonebook/providers/role_provider.dart index 0ded16660..7d46baab3 100644 --- a/lib/phonebook/providers/role_provider.dart +++ b/lib/phonebook/providers/role_provider.dart @@ -1,15 +1,35 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/role.dart'; +import 'package:myecl/phonebook/repositories/role_repository.dart'; +import 'package:myecl/tools/providers/single_notifier.dart'; -final roleProvider = StateNotifierProvider((ref) { - return RoleProvider(); -}); - -class RoleProvider extends StateNotifier { -RoleProvider() : super(Role.empty()); +class RoleNotifier extends SingleNotifier { + final RoleRepository roleRepository = RoleRepository(); + RoleNotifier({required String token}) + : super(const AsyncValue.loading()) { + roleRepository.setToken(token); + } void setRole(Role i) { - state = i; + state = AsyncValue.data(i); + } + + Future updateRole(Role role) async { + return update((role) async => roleRepository.updateRole(role), role); + } + + Future deleteRole(Role role) async { + return delete((role) async => roleRepository.deleteRole(role), role, role.id); + } + + Future createRole(Role role) async { + return add((role) async => roleRepository.createRole(role), role); } -} \ No newline at end of file +} + +final roleProvider = StateNotifierProvider>((ref) { + final token = ref.watch(tokenProvider); + return RoleNotifier(token: token); +}); \ No newline at end of file diff --git a/lib/phonebook/repositories/association_member_repository.dart b/lib/phonebook/repositories/association_member_repository.dart index 8d21260c5..7183d5ec7 100644 --- a/lib/phonebook/repositories/association_member_repository.dart +++ b/lib/phonebook/repositories/association_member_repository.dart @@ -1,10 +1,5 @@ import 'package:myecl/phonebook/class/complete_member.dart'; -import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/class/role.dart'; import 'package:myecl/tools/repository/repository.dart'; -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:myecl/tools/exception.dart'; class AssociationMemberRepository extends Repository { @override @@ -15,24 +10,4 @@ class AssociationMemberRepository extends Repository { return List.from( (await getList(suffix: "$associationId/members")).map((x) => CompleteMember.fromJSON(x))); } - - Future addMember(Association association, CompleteMember member, Role role) async { - await create({"member_id": member.member.id, "association_id": association.id, "roleId": role.id}, - suffix: "membership"); - return true; - } - - Future deleteMember(Association association, CompleteMember member) async { - final response = await http.delete( - Uri.parse("$host${ext}membership"), - headers: headers, - body: json.encode({"member_id": member.member.id, "association_id": association.id})); - if (response.statusCode == 204) { - return true; - } else if (response.statusCode == 403) { - throw AppException(ErrorType.tokenExpire, response.body); - } else { - throw AppException(ErrorType.notFound, "Failed to update item"); - } - } } \ No newline at end of file diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index dccfd89b3..5f9f35ba5 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -1,4 +1,6 @@ import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/role.dart'; import 'package:myecl/tools/repository/repository.dart'; import 'package:myecl/user/class/list_users.dart'; import 'dart:convert'; @@ -31,7 +33,27 @@ class AssociationRepository extends Repository { return await update(association.toJSON(), association.id); } -Future createAssociation(Association association) async { + Future createAssociation(Association association) async { return Association.fromJSON(await create(association.toJSON())); } + + Future addMember(Association association, CompleteMember member, Role role) async { + await create({"member_id": member.member.id, "association_id": association.id, "roleId": role.id}, + suffix: "membership"); + return true; + } + + Future deleteMember(Association association, CompleteMember member) async { + final response = await http.delete( + Uri.parse("$host${ext}membership"), + headers: headers, + body: json.encode({"member_id": member.member.id, "association_id": association.id})); + if (response.statusCode == 204) { + return true; + } else if (response.statusCode == 403) { + throw AppException(ErrorType.tokenExpire, response.body); + } else { + throw AppException(ErrorType.notFound, "Failed to update item"); + } + } } diff --git a/lib/phonebook/repositories/member_repository.dart b/lib/phonebook/repositories/member_repository.dart index d707a91b5..3ec3c8b98 100644 --- a/lib/phonebook/repositories/member_repository.dart +++ b/lib/phonebook/repositories/member_repository.dart @@ -1,6 +1,6 @@ import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/member.dart'; -import 'package:myecl/phonebook/class/post.dart'; +import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/tools/repository/repository.dart'; class MemberRepository extends Repository { @@ -8,9 +8,9 @@ class MemberRepository extends Repository { // ignore: overridden_fields final ext = "phonebook/member/"; - Future> getMemberPostList(int memberId) async { - return List.from( - (await getList(suffix: "/$memberId/posts")).map((x) => Post.fromJSON(x))); + Future> getMemberMembershipList(int memberId) async { + return List.from( + (await getList(suffix: "/$memberId/posts")).map((x) => Membership.fromJSON(x))); } Future getMember(String memberId) async { diff --git a/lib/phonebook/repositories/role_repository.dart b/lib/phonebook/repositories/role_repository.dart new file mode 100644 index 000000000..4bf87bf01 --- /dev/null +++ b/lib/phonebook/repositories/role_repository.dart @@ -0,0 +1,33 @@ +import 'package:myecl/phonebook/class/role.dart'; +import 'package:myecl/tools/repository/repository.dart'; + +class RoleRepository extends Repository { + @override + // ignore: overridden_fields + final ext = "phonebook/role/"; + + Future> getRoleList([String? filter]) async { + String suffix = ""; + if (filter != null) { + suffix = "?filter=$filter"; + } + return List.from( + (await getList(suffix: suffix)).map((x) => Role.fromJSON(x))); + } + + Future getRole(String roleId) async { + return Role.fromJSON(await getOne(roleId)); + } + + Future deleteRole(String roleId) async { + return await delete(roleId); + } + + Future updateRole(Role role) async { + return await update(role.toJSON(), role.id); + } + +Future createRole(Role role) async { + return Role.fromJSON(await create(role.toJSON())); + } +} diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index a4b03c07d..4ef5190d8 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -12,10 +12,10 @@ class PhonebookTextConstants { static const String updatedAssociationPicture = "La photo d'association a été changée"; static const String tooHeavyAssociationPicture = "L'image est trop lourde (max 4Mo)"; - static const String postAssociation = "Association :"; - static const String postRole = "Rôle :"; - static const String postAssociationError = "Veuillez choisir une association"; - static const String postRoleError = "Veuillez choisir un rôle"; + static const String membershipAssociation = "Association :"; + static const String membershipRole = "Rôle :"; + static const String membershipAssociationError = "Veuillez choisir une association"; + static const String membershipRoleError = "Veuillez choisir un rôle"; static const String validation = "Valider"; static const String cancel = "Annuler"; static const String association = "Association :"; @@ -39,8 +39,12 @@ class PhonebookTextConstants { static const String deletingError = "Erreur lors de la suppression"; static const String errorLoadAssociationList = "Erreur lors du chargement de la liste des associations"; static const String associationDetail = "Détail de l'association :"; - static const String errorLoadAssociationMember = "Erreur lors du chargement des membres de l'association"; + static const String errorLoadRoleList = "Erreur lors du chargement de la liste des rôles"; + static const String editRoleName = "Modifier le nom du rôle"; + static const String deleteRole = "Supprimer le rôle ?"; + static const String deletedRole = "Rôle supprimé"; + static const String errorLoadProfilePicture = "Erreur"; } class PhonebookColorConstants{ diff --git a/lib/phonebook/tools/fake_class.dart b/lib/phonebook/tools/fake_class.dart new file mode 100644 index 000000000..c9b7a287b --- /dev/null +++ b/lib/phonebook/tools/fake_class.dart @@ -0,0 +1,66 @@ +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/member.dart'; +import 'package:myecl/phonebook/class/membership.dart'; +import 'package:myecl/phonebook/class/role.dart'; + +List fakeAssociations = [ + Association(id: '1', name: 'test1', description: 'description test1'), + Association(id: '2', name: 'test2', description: 'description test2'), + Association(id: '3', name: 'test3', description: 'description test3'), + Association(id: '4', name: 'test4', description: 'description test4'), + Association(id: '5', name: 'test5', description: 'description test5'), + Association(id: '6', name: 'test6', description: 'description test6'), + Association(id: '7', name: 'test7', description: 'description test7'), +]; + +List fakeRoles = [ + Role(id: '1', name: 'Prez\''), + Role(id: '2', name: 'Trez\''), + Role(id: '3', name: 'SG'), + Role(id: '4', name: 'Fillot'), + Role(id: '5', name: 'VP Emprunt'), +]; + +List fakeMembersContructor(Association association) { + return [ + CompleteMember( + member: Member( + name: 'Dupond', + firstname: 'Michel', + nickname: 'Testouille', + id: '1', + email: 'test1@useless'), + memberships: [Membership(association: association, role: fakeRoles[0])]), + CompleteMember( + member: Member( + name: 'Debouck', + firstname: 'Frank', + nickname: 'Chad', + id: '2', + email: 'test2@useless'), + memberships: [Membership(association: association, role: fakeRoles[1])]), + CompleteMember( + member: Member( + name: 'Ray', + firstname: 'Pascal', + nickname: 'Salut', + id: '3', + email: 'test3@useless'), + memberships: [Membership(association: association, role: fakeRoles[2])]), + CompleteMember( + member: Member( + name: 'Guarriguenc', + firstname: 'Jean-Luc', + nickname: 'Cascouille', + id: '4', + email: 'test4@useless'), + memberships: [ + Membership(association: association, role: fakeRoles[3]), + Membership( + association: Association( + id: '12', name: 'testTest', description: 'JSP frère'), + role: fakeRoles[4]) + ]), + ]; +} diff --git a/lib/phonebook/ui/pages/main_page/association_cards.dart b/lib/phonebook/ui/association_card.dart similarity index 85% rename from lib/phonebook/ui/pages/main_page/association_cards.dart rename to lib/phonebook/ui/association_card.dart index c0109c398..99e556bf2 100644 --- a/lib/phonebook/ui/pages/main_page/association_cards.dart +++ b/lib/phonebook/ui/association_card.dart @@ -2,27 +2,26 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; -import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -class AssociationCards extends HookConsumerWidget { - const AssociationCards({super.key, - required this.association +class AssociationCard extends HookConsumerWidget { + const AssociationCard({super.key, + required this.association, + required this.onClicked, }); final Association association; + final VoidCallback onClicked; @override Widget build(BuildContext context, WidgetRef ref) { final pageNotifier = ref.watch(phonebookPageProvider.notifier); - final associationNotifier = ref.watch(associationProvider.notifier); final associationPicture = ref.watch(associationPictureProvider); return GestureDetector( onTap: () { - associationNotifier.setAssociation(association); - pageNotifier.setPhonebookPage(PhonebookPage.associationPage); + onClicked(); }, child: Container( margin: const EdgeInsets.all(10), diff --git a/lib/phonebook/ui/delete_button.dart b/lib/phonebook/ui/delete_button.dart new file mode 100644 index 000000000..8e505b545 --- /dev/null +++ b/lib/phonebook/ui/delete_button.dart @@ -0,0 +1,70 @@ +import 'package:flutter/material.dart'; +import 'package:heroicons/heroicons.dart'; +import 'package:myecl/tools/constants.dart'; +import 'package:myecl/tools/ui/shrink_button.dart'; + +class DeleteButton extends StatelessWidget { + final Future Function() onDelete; + + const DeleteButton({Key? key, + required this.onDelete}) : super(key: key); + + @override + Widget build(BuildContext context) { + return ShrinkButton( + waitChild: Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.3), + spreadRadius: 2, + blurRadius: 4, + offset: const Offset(2, 3), + ), + ], + borderRadius: BorderRadius.circular(10), + ), + child: const Center( + child: CircularProgressIndicator( + color: Colors.white, + ), + ), + ), + onTap: onDelete, + child: Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.3), + spreadRadius: 2, + blurRadius: 4, + offset: const Offset(2, 3), + ), + ], + borderRadius: BorderRadius.circular(10), + ), + child: const HeroIcon( + HeroIcons.xMark, + color: Colors.white, + ), + )); + } +} \ No newline at end of file diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 2571e26fb..1e88f132d 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -1,10 +1,15 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/association_list_provider.dart'; +import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; -import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:heroicons/heroicons.dart'; -import 'package:myecl/phonebook/ui/pages/admin_page/association_bar.dart'; -import 'package:myecl/phonebook/ui/pages/admin_page/role_bar.dart'; +import 'package:myecl/phonebook/providers/role_list_provider.dart'; +import 'package:myecl/phonebook/tools/fake_class.dart'; +import 'package:myecl/phonebook/ui/pages/admin_page/association_research_bar.dart'; +import 'package:myecl/phonebook/ui/pages/admin_page/role_research_bar.dart'; +import 'package:myecl/phonebook/ui/pages/admin_page/role_card.dart'; +import 'package:myecl/phonebook/ui/association_card.dart'; +import 'package:myecl/tools/ui/refresher.dart'; class AdminPage extends HookConsumerWidget { const AdminPage({Key? key}) : super(key: key); @@ -12,36 +17,76 @@ class AdminPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final pageNotifier = ref.watch(phonebookPageProvider.notifier); - return DefaultTabController( - length: 2, + final associationNotifier = ref.watch(asyncAssociationProvider.notifier); + final roles = ref.watch(roleListProvider); + final rolesNotifier = ref.watch(roleListProvider.notifier); + final associations = ref.watch(associationListProvider); + final associationsNotifier = ref.watch(associationListProvider.notifier); + final controller = ScrollController(); + return Refresher( + onRefresh: () async { + await associationsNotifier.loadAssociations(); + await rolesNotifier.loadRoles(); + }, child: Column( - children: const [ - SizedBox( - height: 10, - ), - TabBar( - labelColor: Colors.black, - unselectedLabelColor: Colors.grey, - indicatorColor: Colors.black, - tabs: [ - Tab( - text: PhonebookTextConstants.associationPure, + children: [ + const RoleResearchBar(), + const SizedBox(width: 10), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + physics: const BouncingScrollPhysics(), + controller: controller, + child: roles.when( + data: (data) { + return Row( + children: data.map((e) => RoleCard(role: e)).toList(), + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + //return const Center( + // child: Text(PhonebookTextConstants.errorLoadRoleList), + //); + return Row( + children: fakeRoles.map((e) => RoleCard(role: e)).toList(), + ); + }), ), - Tab( - text: PhonebookTextConstants.rolePure, - ) - ], - ), - Expanded( - child: TabBarView( - children: [ - AssociationBar(), - RoleBar(), - ], - ), - ), + const SizedBox(width: 10), + const AssociationResearchBar(), + const SizedBox(width: 10), + associations.when( + data: (data) { + return Column( + children: data.map((association) => AssociationCard(association: association, onClicked: () { + associationNotifier.setAssociation(association); + pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); + },)).toList(), + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + //return const Center( + // child: Text(PhonebookTextConstants.errorLoadAssociationList), + //); + return Column( + children: fakeAssociations.map((association) { + return AssociationCard(association: association, onClicked: () { + associationNotifier.setAssociation(association); + pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); + },); + }).toList(), + ); + }), ], - ), - ); + )); } } diff --git a/lib/phonebook/ui/pages/admin_page/asso_ui.dart b/lib/phonebook/ui/pages/admin_page/asso_ui.dart index 00b0e8c18..ef4e28c43 100644 --- a/lib/phonebook/ui/pages/admin_page/asso_ui.dart +++ b/lib/phonebook/ui/pages/admin_page/asso_ui.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/providers/association_picture_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/ui/shrink_button.dart'; @@ -17,6 +19,8 @@ class AssoUi extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { + final associationPicture = + ref.watch(associationPictureProvider); return Container( margin: const EdgeInsets.symmetric(vertical: 10), padding: const EdgeInsets.all(10), @@ -34,6 +38,23 @@ class AssoUi extends HookConsumerWidget { const SizedBox( width: 10, ), + associationPicture.when(data: (picture){ + return CircleAvatar( + radius: 80, + backgroundImage: picture.isEmpty ? + const AssetImage('assets/images/profile.png') : + Image.memory(picture).image, + ); + }, loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, error: (e, s) { + return const Center( + child: Text(PhonebookTextConstants.errorLoadAssociationPicture), + ); + }, + ), Expanded( child: Text( association.name, diff --git a/lib/phonebook/ui/pages/admin_page/association_bar.dart b/lib/phonebook/ui/pages/admin_page/association_bar.dart deleted file mode 100644 index 05bab4dfa..000000000 --- a/lib/phonebook/ui/pages/admin_page/association_bar.dart +++ /dev/null @@ -1,121 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:heroicons/heroicons.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; -import 'package:myecl/phonebook/ui/pages/admin_page/asso_ui.dart'; -import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/tools/constants.dart'; -import 'package:myecl/tools/ui/dialog.dart'; -import 'package:myecl/tools/functions.dart'; -import 'package:myecl/tools/ui/refresher.dart'; -import 'package:myecl/tools/token_expire_wrapper.dart'; -import 'package:myecl/phonebook/providers/association_list_provider.dart'; -import 'package:myecl/phonebook/providers/association_id_provider.dart'; - -class AssociationBar extends HookConsumerWidget { - const AssociationBar({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final pageNotifier = ref.watch(phonebookPageProvider.notifier); - final associationsNotifier = ref.watch(allAssociationListProvider.notifier); - final associations = ref.watch(allAssociationListProvider); - final associationIdNotifier = ref.watch(associationIdProvider.notifier); - void displayToastWithContext(TypeMsg type, String msg) { - displayToast(context, type, msg); - } - - - return Refresher( - onRefresh: () async { - await associationsNotifier.loadAssociations(); - }, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 30.0), - child: associations.when(data: (a) { - return Column(children: [ - Column( - children: [ - GestureDetector( - onTap: () { - pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); - }, - child: Container( - margin: const EdgeInsets.symmetric(vertical: 10), - padding: const EdgeInsets.symmetric( - horizontal: 10, vertical: 10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.2), - blurRadius: 5, - spreadRadius: 2) - ]), - child: Row( - children: [ - const Spacer(), - HeroIcon( - HeroIcons.plus, - color: Colors.grey.shade700, - size: 40, - ), - const Spacer(), - ], - ), - ), - ), - ...a - .map((association) => AssoUi( - association: association, - onEdit: () { - associationIdNotifier.setId(association.id); - pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); - }, - onDelete: () async { - await showDialog( - context: context, - builder: (context) { - return CustomDialogBox( - title: PhonebookTextConstants.deleting, - descriptions: - PhonebookTextConstants.deleteAssociation, - onYes: () async { - tokenExpireWrapper(ref, () async { - final value = await associationsNotifier - .deleteAssociation(association); - if (value) { - displayToastWithContext( - TypeMsg.msg, - PhonebookTextConstants - .deletedAssociation); - } else { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.deletingError); - } - }); - }, - ); - }); - }, - )) - .toList(), - const SizedBox( - height: 20, - ) - ], - ), - ]); - }, error: (e, s) { - return Text(e.toString()); - }, loading: () { - return const Center( - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation(ColorConstants.gradient1), - )); - }), - ), - ); - } -} \ No newline at end of file diff --git a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart new file mode 100644 index 000000000..610f06c02 --- /dev/null +++ b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/association_list_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; + +class AssociationResearchBar extends HookConsumerWidget { + const AssociationResearchBar({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final associationListNotifier = + ref.watch(associationListProvider.notifier); + final focusNode = useFocusNode(); + final editingController = useTextEditingController(); + return Container( + decoration: BoxDecoration( + border: Border.all(), + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 1, + blurRadius: 7, + offset: const Offset(0, 3), // changes position of shadow + ), + ], + ), + width: 300, + child: TextField( + onChanged: (value) { + tokenExpireWrapper(ref, () async { + if (editingController.text.isNotEmpty) { + await associationListNotifier + .loadAssociations(editingController.text); + } else { + await associationListNotifier.loadAssociations(); + } + }); + }, + focusNode: focusNode, + controller: editingController, + cursorColor: PhonebookColorConstants.textDark, + decoration: const InputDecoration( + labelText: PhonebookTextConstants.associationPure, + labelStyle: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: PhonebookColorConstants.textDark), + suffixIcon: Icon( + Icons.search, + color: PhonebookColorConstants.textDark, + size: 30, + ), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: Colors.transparent, + ), + ), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: PhonebookColorConstants.textDark, + ), + )), + )); + } +} diff --git a/lib/phonebook/ui/pages/admin_page/role_bar.dart b/lib/phonebook/ui/pages/admin_page/role_bar.dart deleted file mode 100644 index 4f391c310..000000000 --- a/lib/phonebook/ui/pages/admin_page/role_bar.dart +++ /dev/null @@ -1,121 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:heroicons/heroicons.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; -import 'package:myecl/phonebook/ui/pages/admin_page/asso_ui.dart'; -import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/tools/constants.dart'; -import 'package:myecl/tools/ui/dialog.dart'; -import 'package:myecl/tools/functions.dart'; -import 'package:myecl/tools/ui/refresher.dart'; -import 'package:myecl/tools/token_expire_wrapper.dart'; -import 'package:myecl/phonebook/providers/association_list_provider.dart'; -import 'package:myecl/phonebook/providers/association_id_provider.dart'; - -class RoleBar extends HookConsumerWidget { - const RoleBar({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final pageNotifier = ref.watch(phonebookPageProvider.notifier); - final associationsNotifier = ref.watch(allAssociationListProvider.notifier); - final associations = ref.watch(allAssociationListProvider); - final associationIdNotifier = ref.watch(associationIdProvider.notifier); - void displayToastWithContext(TypeMsg type, String msg) { - displayToast(context, type, msg); - } - - - return Refresher( - onRefresh: () async { - await associationsNotifier.loadAssociations(); - }, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 30.0), - child: associations.when(data: (a) { - return Column(children: [ - Column( - children: [ - GestureDetector( - onTap: () { - pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); - }, - child: Container( - margin: const EdgeInsets.symmetric(vertical: 10), - padding: const EdgeInsets.symmetric( - horizontal: 10, vertical: 10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.2), - blurRadius: 5, - spreadRadius: 2) - ]), - child: Row( - children: [ - const Spacer(), - HeroIcon( - HeroIcons.plus, - color: Colors.grey.shade700, - size: 40, - ), - const Spacer(), - ], - ), - ), - ), - ...a - .map((association) => AssoUi( - association: association, - onEdit: () { - associationIdNotifier.setId(association.id); - pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); - }, - onDelete: () async { - await showDialog( - context: context, - builder: (context) { - return CustomDialogBox( - title: PhonebookTextConstants.deleting, - descriptions: - PhonebookTextConstants.deleteAssociation, - onYes: () async { - tokenExpireWrapper(ref, () async { - final value = await associationsNotifier - .deleteAssociation(association); - if (value) { - displayToastWithContext( - TypeMsg.msg, - PhonebookTextConstants - .deletedAssociation); - } else { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.deletingError); - } - }); - }, - ); - }); - }, - )) - .toList(), - const SizedBox( - height: 20, - ) - ], - ), - ]); - }, error: (e, s) { - return Text(e.toString()); - }, loading: () { - return const Center( - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation(ColorConstants.gradient1), - )); - }), - ), - ); - } -} \ No newline at end of file diff --git a/lib/phonebook/ui/pages/admin_page/role_card.dart b/lib/phonebook/ui/pages/admin_page/role_card.dart new file mode 100644 index 000000000..e1594fc02 --- /dev/null +++ b/lib/phonebook/ui/pages/admin_page/role_card.dart @@ -0,0 +1,117 @@ +import 'package:flutter/material.dart'; +import 'package:heroicons/heroicons.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/role.dart'; +import 'package:myecl/phonebook/providers/role_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/phonebook/ui/delete_button.dart'; +import 'package:myecl/phonebook/ui/text_input_dialog.dart'; +import 'package:myecl/tools/functions.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; +import 'package:myecl/tools/ui/dialog.dart'; + +class RoleCard extends HookConsumerWidget { + const RoleCard({super.key, + required this.role + }); + + final Role role; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final roleNotifier = ref.watch(roleProvider.notifier); + final controller = TextEditingController(); + void displayToastWithContext(TypeMsg type, String msg) { + displayToast(context, type, msg); + } + + return Container( + margin: const EdgeInsets.all(10), + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + border: Border.all(), + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(20)), + ), + + child: Row( + children: [ + const SizedBox(width: 10), + SizedBox( + width: 200, + child: Text( + role.name, + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + GestureDetector( + onTap: (){ + roleNotifier.setRole(role); + showDialog( + context: context, + builder: (BuildContext context) { + return TextInputDialog( + controller: controller, + title: role.name, + text: PhonebookTextConstants.editRoleName, + defaultText: role.name, + onConfirm: (){ + roleNotifier.updateRole(role.copyWith(name: controller.text)); + Navigator.of(context).pop(); + },); + }); + }, + child: Container( + width: 40, + height: 40, + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.grey.shade200, + borderRadius: BorderRadius.circular(30), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 10, + offset: const Offset(2, 3)) + ], + ), + child: const HeroIcon(HeroIcons.pencil, + color: Colors.black), + ), + ), + const SizedBox(width: 10), + DeleteButton( + onDelete: () async { + await showDialog( + context: context, + builder: (context) { + return CustomDialogBox( + title: PhonebookTextConstants.deleting, + descriptions: + PhonebookTextConstants.deleteRole, + onYes: () async { + tokenExpireWrapper(ref, () async { + final value = await roleNotifier + .deleteRole(role); + if (value) { + displayToastWithContext( + TypeMsg.msg, + PhonebookTextConstants.deletedRole); + } else { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.deletingError); + } + }); + }, + ); + }); + }, + ), + ], + ) + ); + } +} \ No newline at end of file diff --git a/lib/phonebook/ui/pages/admin_page/role_research_bar.dart b/lib/phonebook/ui/pages/admin_page/role_research_bar.dart new file mode 100644 index 000000000..34618c1f2 --- /dev/null +++ b/lib/phonebook/ui/pages/admin_page/role_research_bar.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/role_list_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; + +class RoleResearchBar extends HookConsumerWidget { + const RoleResearchBar({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final associationListNotifier = + ref.watch(roleListProvider.notifier); + final focusNode = useFocusNode(); + final editingController = useTextEditingController(); + return Container( + decoration: BoxDecoration( + border: Border.all(), + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 1, + blurRadius: 7, + offset: const Offset(0, 3), // changes position of shadow + ), + ], + ), + width: 300, + child: TextField( + onChanged: (value) { + tokenExpireWrapper(ref, () async { + if (editingController.text.isNotEmpty) { + await associationListNotifier + .loadRoles(editingController.text); + } else { + await associationListNotifier.loadRoles(); + } + }); + }, + focusNode: focusNode, + controller: editingController, + cursorColor: PhonebookColorConstants.textDark, + decoration: const InputDecoration( + labelText: PhonebookTextConstants.rolePure, + labelStyle: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: PhonebookColorConstants.textDark), + suffixIcon: Icon( + Icons.search, + color: PhonebookColorConstants.textDark, + size: 30, + ), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: Colors.transparent, + ), + ), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: PhonebookColorConstants.textDark, + ), + )), + )); + } +} diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index bb8628b8b..871004b80 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -2,23 +2,30 @@ import 'package:flutter/material.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:image_picker/image_picker.dart'; -import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/phonebook/tools/fake_class.dart'; +import 'package:myecl/phonebook/ui/pages/association_editor_page/member_editable_card.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; +import 'package:myecl/tools/ui/refresher.dart'; class AssociationEditorPage extends HookConsumerWidget { const AssociationEditorPage({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { - final pageNotifier = ref.watch(phonebookPageProvider.notifier); - Association association = ref.watch(associationProvider); + final association = ref.watch(associationProvider); + final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); + final associationMemberList = ref.watch(associationMemberListProvider); final associationPicture = ref.watch(associationPictureProvider); final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); + + String text = ""; if (association.id == "") { text = "Ajouter une association"; @@ -29,7 +36,11 @@ class AssociationEditorPage extends HookConsumerWidget { void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); } - return Expanded( + return Refresher( + onRefresh: () async { + await associationMemberListNotifier.loadMembers(association.id); + await associationPictureNotifier.getAssociationPicture(association.id); + }, child: Column(children: [ Center( child : Text(text, style: const TextStyle(fontSize: 20))), @@ -54,56 +65,80 @@ class AssociationEditorPage extends HookConsumerWidget { color: Colors.red ), child: GestureDetector( - onTap: () async { - final value = await associationPictureNotifier - .setAssociationPicture(ImageSource.gallery, association.id); - if (value != null) { - if (value) { - displayToastWithContext( - TypeMsg.msg, - PhonebookTextConstants - .updatedAssociationPicture); - } else { - displayToastWithContext( - TypeMsg.error, - PhonebookTextConstants - .tooHeavyAssociationPicture); - } - } else { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.errorAssociationPicture); - } - }, - child: Container( - height: 40, - width: 40, - padding: const EdgeInsets.all(7), - decoration: BoxDecoration( - shape: BoxShape.circle, - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2 - .withOpacity(0.3), - spreadRadius: 2, - blurRadius: 4, - offset: const Offset(2, 3), - ), - ], - ), - child: const HeroIcon( - HeroIcons.photo, - color: Colors.white, - ), - ), - ),), + onTap: () async { + final value = await associationPictureNotifier + .setAssociationPicture(ImageSource.gallery, association.id); + if (value != null) { + if (value) { + displayToastWithContext( + TypeMsg.msg, + PhonebookTextConstants + .updatedAssociationPicture); + } else { + displayToastWithContext( + TypeMsg.error, + PhonebookTextConstants + .tooHeavyAssociationPicture); + } + } else { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.errorAssociationPicture); + } + }, + child: Container( + height: 40, + width: 40, + padding: const EdgeInsets.all(7), + decoration: BoxDecoration( + shape: BoxShape.circle, + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2 + .withOpacity(0.3), + spreadRadius: 2, + blurRadius: 4, + offset: const Offset(2, 3), + ), + ], + ), + child: const HeroIcon( + HeroIcons.photo, + color: Colors.white, + ), + ), + ),), + associationMemberList.when( + data: (members) { + return Column( + children: members.map((member) => + MemberEditableCard(member: member) + ).toList() + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + //return const Center( + // child: Text(PhonebookTextConstants.errorLoadAssociationMember), + List fakeMembers = fakeMembersContructor(association); + return Column( + children: fakeMembers.map((member) => + MemberEditableCard(member: member) + ).toList() + ); + }, + ), Row(children: [ GestureDetector( child: Container( @@ -115,7 +150,7 @@ class AssociationEditorPage extends HookConsumerWidget { ), child: const Center(child : Text(PhonebookTextConstants.cancel, style: TextStyle(fontSize: 20))),), onTap: () { - pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); + //to complete }, ), GestureDetector( @@ -129,7 +164,7 @@ class AssociationEditorPage extends HookConsumerWidget { child: const Center(child : Text(PhonebookTextConstants.validation, style: TextStyle(fontSize: 20))), ), onTap: () { - pageNotifier.setPhonebookPage(PhonebookPage.addEditAssociation); + //to complete }, ) diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart new file mode 100644 index 000000000..5b70ffdc9 --- /dev/null +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -0,0 +1,148 @@ +import 'package:flutter/material.dart'; +import 'package:heroicons/heroicons.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/user/providers/profile_picture_provider.dart'; +import 'package:myecl/phonebook/providers/complete_member_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; + +class MemberEditableCard extends HookConsumerWidget { + const MemberEditableCard({super.key, required this.member}); + + final CompleteMember member; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final memberNotifier = ref.watch(completeMemberProvider.notifier); + final profilePicture = ref.watch(profilePictureProvider); + final association = ref.watch(associationProvider); + final associationNotifier = ref.watch(asyncAssociationProvider.notifier); + + return Container( + margin: const EdgeInsets.all(10), + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + border: Border.all(), + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(20)), + ), + child: Row( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + spreadRadius: 5, + blurRadius: 10, + offset: const Offset(2, 3), + ), + ], + ), + child: profilePicture.when( + data: (picture) { + return CircleAvatar( + radius: 20, + backgroundImage: picture.isEmpty + ? const AssetImage('assets/images/logo_alpha.png') + : Image.memory(picture).image, + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return const Center( + child: Text( + PhonebookTextConstants.errorLoadAssociationPicture), + ); + }, + ), + ), + const SizedBox(width: 10), + SizedBox( + width: 400, + child: Column( + children: [ + Text( + "${member.member.name} ${member.member.firstname} (${member.member.nickname})", + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 5), + Text( + member.member.email, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + SizedBox( + width: 200, + child: Center( + child: Text( + member.memberships.firstWhere((element) => element.association.id == association.id).role.name, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ) + ), + const SizedBox(width: 10), + GestureDetector( + onTap: (){}, + child: Container( + width: 40, + height: 40, + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.grey.shade200, + borderRadius: BorderRadius.circular(30), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 10, + offset: const Offset(2, 3)) + ], + ), + child: const HeroIcon(HeroIcons.pencil, + color: Colors.black), + ), + ), + const SizedBox(width: 10), + GestureDetector( + onTap: (){ + associationNotifier.deleteMember(association ,member); + }, + child: Container( + width: 40, + height: 40, + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.grey.shade200, + borderRadius: BorderRadius.circular(30), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 10, + offset: const Offset(2, 3)) + ], + ), + child: const HeroIcon(HeroIcons.trash, + color: Colors.black), + ), + ), + ], + )); + } +} diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index 6d3a24399..ece35b95f 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -1,51 +1,90 @@ import 'package:flutter/material.dart'; -import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; -import 'package:myecl/phonebook/class/member.dart'; -import 'package:myecl/phonebook/class/post.dart'; -import 'package:myecl/phonebook/class/role.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/tools/fake_class.dart'; import 'package:myecl/phonebook/ui/pages/association_page/member_card.dart'; +import 'package:myecl/tools/ui/refresher.dart'; class AssociationPage extends HookConsumerWidget { + const AssociationPage({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { final association = ref.watch(associationProvider); - final pageNotifier = ref.watch(phonebookPageProvider.notifier); final associationPicture = ref.watch(associationPictureProvider); final associationMemberList = ref.watch(associationMemberListProvider); + final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); + final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); + - return Column(children: [ - const Text(PhonebookTextConstants.associationDetail), - const SizedBox(height: 20,), - Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - spreadRadius: 5, - blurRadius: 10, - offset: const Offset(2, 3), - ), - ], + return Refresher( + onRefresh : () async { + await associationMemberListNotifier.loadMembers(association.id); + await associationPictureNotifier.getAssociationPicture(association.id); + }, + child: Column( + children: [ + const Text(PhonebookTextConstants.associationDetail), + const SizedBox(height: 20,), + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + spreadRadius: 5, + blurRadius: 10, + offset: const Offset(2, 3), + ), + ], + ), + child: associationPicture.when( + data: (picture) { + return CircleAvatar( + radius: 80, + backgroundImage: picture.isEmpty + ? const AssetImage('assets/images/logo_alpha.png') + : Image.memory(picture).image, + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return const Center( + child: Text(PhonebookTextConstants.errorLoadAssociationPicture), + ); + }, + ), + ), + const SizedBox(height: 20,), + Text(association.name, + style: const TextStyle( + fontSize: 20, + color: Colors.black + ), + ), + const SizedBox(height: 10,), + Text(association.description, + style: const TextStyle( + fontSize: 15, + color: Colors.black + ), ), - child: associationPicture.when( - data: (picture) { - return CircleAvatar( - radius: 80, - backgroundImage: picture.isEmpty - ? const AssetImage('assets/images/logo_alpha.png') - : Image.memory(picture).image, + const SizedBox(height: 20,), + associationMemberList.when( + data: (members) { + return Column( + children: members.map((member) => + MemberCard(member: member) + ).toList() ); }, loading: () { @@ -54,70 +93,16 @@ class AssociationPage extends HookConsumerWidget { ); }, error: (e, s) { - return const Center( - child: Text(PhonebookTextConstants.errorLoadAssociationPicture), + //return const Center( + // child: Text(PhonebookTextConstants.errorLoadAssociationMember), + List fakeMembers = fakeMembersContructor(association); + return Column( + children: fakeMembers.map((member) => + MemberCard(member: member) + ).toList() ); }, - ), - ), - const SizedBox(height: 20,), - Text(association.name, - style: const TextStyle( - fontSize: 20, - color: Colors.black - ), - ), - const SizedBox(height: 10,), - Text(association.description, - style: const TextStyle( - fontSize: 15, - color: Colors.black - ), - ), - const SizedBox(height: 20,), - SingleChildScrollView( - scrollDirection: Axis.vertical, - physics: const BouncingScrollPhysics(), - child: associationMemberList.when( - data: (members) { - return Column( - children: members.map((member) => - MemberCard(member: member) - ).toList() - ); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - //return const Center( - // child: Text(PhonebookTextConstants.errorLoadAssociationMember), - List members = [ - CompleteMember( - member: Member(name: 'Dupond', firstname: 'Michel', nickname: 'Testouille', id: '1', email: 'test1@useless'), - post: [Post(association: association, role: Role(id: '1', name: 'Prez\''))]), - CompleteMember( - member: Member(name: 'Debouck', firstname: 'Frank', nickname: 'Chad', id: '2', email: 'test2@useless'), - post: [Post(association: association, role: Role(id: '2', name: 'Trez\''))]), - CompleteMember( - member: Member(name: 'Ray', firstname: 'Pascal', nickname: 'Salut', id: '3', email: 'test3@useless'), - post: [Post(association: association, role: Role(id: '3', name: 'SG'))]), - CompleteMember( - member: Member(name: 'Guarriguenc', firstname: 'Jean-Luc', nickname: 'Cascouille', id: '4', email: 'test4@useless'), - post: [Post(association: association, role: Role(id: '4', name: 'Fillot')), - Post(association: Association(id: '12',name: 'testTest', description: 'JSP frère'), - role: Role(id: '5', name: 'Bourrin'))]), - ]; - return Column( - children: members.map((member) => - MemberCard(member: member) - ).toList() - ); - }, - ) - ), - ]); + ) + ])); } } diff --git a/lib/phonebook/ui/pages/association_page/member_card.dart b/lib/phonebook/ui/pages/association_page/member_card.dart index 1baa5da6d..5c8b26457 100644 --- a/lib/phonebook/ui/pages/association_page/member_card.dart +++ b/lib/phonebook/ui/pages/association_page/member_card.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; -import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/user/providers/profile_picture_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; @@ -19,11 +18,15 @@ class MemberCard extends HookConsumerWidget { final memberNotifier = ref.watch(completeMemberProvider.notifier); final profilePicture = ref.watch(profilePictureProvider); final association = ref.watch(associationProvider); + final profilePictureNotifier = ref.watch(profilePictureProvider.notifier); + + //profilePictureNotifier.getProfilePicture(member.member.id); return GestureDetector( onTap: () { memberNotifier.setCompleteMember(member); pageNotifier.setPhonebookPage(PhonebookPage.memberDetail); + profilePictureNotifier.getProfilePicture(member.member.id); }, child: Container( margin: const EdgeInsets.all(10), @@ -64,14 +67,14 @@ class MemberCard extends HookConsumerWidget { error: (e, s) { return const Center( child: Text( - PhonebookTextConstants.errorLoadAssociationPicture), + PhonebookTextConstants.errorLoadProfilePicture), ); }, ), ), const SizedBox(width: 10), SizedBox( - width: 400, + width: 200, child: Column( children: [ Text( @@ -93,10 +96,10 @@ class MemberCard extends HookConsumerWidget { ), ), SizedBox( - width: 200, + width: 100, child: Center( child: Text( - member.post.firstWhere((element) => element.association.id == association.id).role.name, + member.memberships.firstWhere((element) => element.association.id == association.id).role.name, style: const TextStyle( fontSize: 15, fontWeight: FontWeight.bold, diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 3fa1cf51c..520295657 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -1,14 +1,15 @@ import 'package:flutter/material.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; +import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:myecl/admin/providers/is_admin.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; -import 'package:myecl/phonebook/ui/pages/main_page/association_cards.dart'; +import 'package:myecl/phonebook/tools/fake_class.dart'; +import 'package:myecl/phonebook/ui/association_card.dart'; import 'package:myecl/phonebook/ui/pages/main_page/research_bar.dart'; +import 'package:myecl/tools/ui/refresher.dart'; class MainPage extends HookConsumerWidget { const MainPage({Key? key}) : super(key: key); @@ -17,87 +18,91 @@ class MainPage extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final isAdmin = ref.watch(isAdminProvider); final pageNotifier = ref.watch(phonebookPageProvider.notifier); - final associationList = ref.watch(allAssociationListProvider); + final associationNotifier = ref.watch(asyncAssociationProvider.notifier); + final associationListNotifier = ref.watch(associationListProvider.notifier); + final associationList = ref.watch(associationListProvider); return Stack( - children: [ - Column( - children: [ - const ResearchBar(), - const SizedBox(width: 10), - SingleChildScrollView( - scrollDirection: Axis.vertical, - physics: const BouncingScrollPhysics(), - child: associationList.when( - data: (data) { - return Column( - children: data.map((association) { - return AssociationCards(association: association); - }).toList(), - ); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - List assos = [ - Association(id: '1', name: 'test1', description: 'description test1'), - Association(id: '2', name: 'test2', description: 'description test2'), - Association(id: '3', name: 'test3', description: 'description test3'), - Association(id: '4', name: 'test4', description: 'description test4'), - Association(id: '5', name: 'test5', description: 'description test5'), - Association(id: '6', name: 'test6', description: 'description test6'), - Association(id: '7', name: 'test7', description: 'description test7'), - ]; - return Column( - children: assos.map((association) { - return AssociationCards(association: association); - }).toList(), - ); + children: [ + Refresher( + onRefresh: () async { + await associationListNotifier.loadAssociations(); + }, + child: Column( + children: [ + const SizedBox(height: 70), + const ResearchBar(), + const SizedBox(width: 10), + SingleChildScrollView( + scrollDirection: Axis.vertical, + physics: const BouncingScrollPhysics(), + child: associationList.when( + data: (data) { + return Column( + children: data.map((association) { + return AssociationCard(association: association, onClicked: () { + associationNotifier.setAssociation(association); + pageNotifier.setPhonebookPage(PhonebookPage.associationPage); + },); + }).toList(), + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return Column( + children: fakeAssociations.map((association) { + return AssociationCard(association: association, onClicked: () { + associationNotifier.setAssociation(association); + pageNotifier.setPhonebookPage(PhonebookPage.associationPage); + },); + }).toList(), + ); - //return const Center( - // child: Text(PhonebookTextConstants.errorLoadAssociationList), - //); - }, - )) - ], - ), - if (isAdmin) - Positioned( - top: 15, - right: 15, - child: GestureDetector( - onTap: () { - pageNotifier.setPhonebookPage(PhonebookPage.admin); - }, - child: Container( - padding: - const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 10, - offset: const Offset(0, 5)) - ]), - child: Row( - children: const [ - HeroIcon(HeroIcons.userGroup, color: Colors.white), - SizedBox(width: 10), - Text(PhonebookTextConstants.admin, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.white)), - ], + //return const Center( + // child: Text(PhonebookTextConstants.errorLoadAssociationList), + //); + }, + )) + ], + )), + if (isAdmin) + Positioned( + top: 15, + right: 15, + child: GestureDetector( + onTap: () { + pageNotifier.setPhonebookPage(PhonebookPage.admin); + }, + child: Container( + padding: + const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + blurRadius: 10, + offset: const Offset(0, 5)) + ]), + child: Row( + children: const [ + HeroIcon(HeroIcons.userGroup, color: Colors.white), + SizedBox(width: 10), + Text(PhonebookTextConstants.admin, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.white)), + ], + ), ), ), - ), - ) - ], - ); + ) + ], + ); } } diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart index 3abfa60db..b545594dc 100644 --- a/lib/phonebook/ui/pages/main_page/research_bar.dart +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -11,10 +11,23 @@ class ResearchBar extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final associationListNotifier = - ref.watch(allAssociationListProvider.notifier); + ref.watch(associationListProvider.notifier); final focusNode = useFocusNode(); final editingController = useTextEditingController(); return Container( + decoration: BoxDecoration( + border: Border.all(), + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 1, + blurRadius: 7, + offset: const Offset(0, 3), // changes position of shadow + ), + ], + ), width: 300, child: TextField( onChanged: (value) { diff --git a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart index 419acdab3..e33c45879 100644 --- a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart +++ b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart @@ -1,11 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/admin/providers/is_admin.dart'; -import 'package:myecl/phonebook/class/post.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; -import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; -import 'package:myecl/phonebook/providers/post_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; class MemberDetailPage extends HookConsumerWidget { @@ -13,10 +8,7 @@ class MemberDetailPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final isAdmin = ref.watch(isAdminProvider); - final pageNotifier = ref.watch(phonebookPageProvider.notifier); final memberProvider = ref.watch(completeMemberProvider); - final postProviderNotifier = ref.watch(postProvider.notifier); return Container( margin: const EdgeInsets.all(10), width: MediaQuery.of(context).size.width, @@ -36,7 +28,7 @@ class MemberDetailPage extends HookConsumerWidget { const Text(PhonebookTextConstants .association), //à changer pour dépendre du nombre d'associatione Column(children: [ - for (var post in memberProvider.post) + for (var membership in memberProvider.memberships) Container( margin: const EdgeInsets.all(10), decoration: BoxDecoration( @@ -46,32 +38,11 @@ class MemberDetailPage extends HookConsumerWidget { child: Row( children: [ const Spacer(flex: 1), - Text("${post.association.name} : ${post.role.name}", + Text("${membership.association.name} : ${membership.role.name}", style: const TextStyle(fontSize: 20)), - if (isAdmin) - IconButton( - icon: const Icon(Icons.edit), - onPressed: () { - postProviderNotifier.setPost(post); - pageNotifier.setPhonebookPage( - PhonebookPage.addEditRoleMember); - }), const Spacer(flex: 1), ])) ]), - if (isAdmin) - ElevatedButton( - onPressed: () { - postProviderNotifier.setPost(Post.empty()); - pageNotifier - .setPhonebookPage(PhonebookPage.addEditRoleMember); - }, - child: Row( - children: const [ - Icon(Icons.add), - Text(PhonebookTextConstants.addRole) - ], - )) ])); } } diff --git a/lib/phonebook/ui/pages/role_member_page/role_member_page.dart b/lib/phonebook/ui/pages/role_member_page/role_member_page.dart index ed2f5f2af..91873d682 100644 --- a/lib/phonebook/ui/pages/role_member_page/role_member_page.dart +++ b/lib/phonebook/ui/pages/role_member_page/role_member_page.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/class/post.dart'; +import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; -import 'package:myecl/phonebook/providers/post_provider.dart'; +import 'package:myecl/phonebook/providers/membership_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; @@ -12,20 +12,20 @@ class RoleMemberPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final post = ref.watch(postProvider); - final postNotifier = ref.watch(postProvider.notifier); + final membership = ref.watch(membershipProvider); + final membershipNotifier = ref.watch(membershipProvider.notifier); final pageNotifier = ref.watch(phonebookPageProvider.notifier); - Post newPost = post; + Membership newMembership = membership; final associationList = useState([["Association 1","1"], ["Association 2","2"], ["Association 3","3"]]); final roleList = useState([["Rôle 1","1"], ["Rôle 2","2"], ["Rôle 3","3"]]); return Column( children: [ - const Text(PhonebookTextConstants.postAssociation), + const Text(PhonebookTextConstants.membershipAssociation), const SizedBox(width: 10), SizedBox( width: 200, child: Autocomplete( - initialValue: TextEditingValue(text: post.association.name), + initialValue: TextEditingValue(text: membership.association.name), optionsBuilder: (TextEditingValue textValue) { if (textValue.text == "") { return associationList.value.map((e) => e[0]).toList(); @@ -36,16 +36,16 @@ class RoleMemberPage extends HookConsumerWidget { }, onSelected: (String selection) { String id = associationList.value.firstWhere((element) => element[0] == selection)[1]; - newPost = newPost.setAssociation(selection,id); + newMembership = newMembership.setAssociation(selection,id); },)), const SizedBox(width: 30), - const Text(PhonebookTextConstants.postRole), + const Text(PhonebookTextConstants.membershipRole), const SizedBox(width: 10), SizedBox( width: 200, child: Autocomplete( - initialValue: TextEditingValue(text: post.role.name), + initialValue: TextEditingValue(text: membership.role.name), optionsBuilder: (TextEditingValue textValue) { if (textValue.text == "") { return roleList.value.map((e) => e[0]).toList(); @@ -56,20 +56,20 @@ class RoleMemberPage extends HookConsumerWidget { }, onSelected: (String selection) { String id = roleList.value.firstWhere((element) => element[0] == selection)[1]; - newPost = newPost.setRole(selection,id); + newMembership = newMembership.setRole(selection,id); },)), ElevatedButton( onPressed: () { - if (newPost.association.name == "") { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text(PhonebookTextConstants.postAssociationError))); + if (newMembership.association.name == "") { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text(PhonebookTextConstants.membershipAssociationError))); return; } - else if (newPost.role.name == "") { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text(PhonebookTextConstants.postRoleError))); + else if (newMembership.role.name == "") { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text(PhonebookTextConstants.membershipRoleError))); return; } else { - postNotifier.setPost(newPost); + membershipNotifier.setMembership(newMembership); pageNotifier.setPhonebookPage(PhonebookPage.memberDetail); } }, diff --git a/lib/phonebook/ui/text_input_dialog.dart b/lib/phonebook/ui/text_input_dialog.dart new file mode 100644 index 000000000..2eda50fd4 --- /dev/null +++ b/lib/phonebook/ui/text_input_dialog.dart @@ -0,0 +1,64 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; + +class TextInputDialog extends HookConsumerWidget{ + const TextInputDialog({ + Key? key, + required this.controller, + required this.title, + required this.text, + required this.defaultText, + required this.onConfirm + }) : super(key: key); + + final String title; + final String text; + final String defaultText; + final VoidCallback onConfirm; + final TextEditingController controller; + + @override + Widget build(BuildContext context, WidgetRef ref) { + controller.text = defaultText; + return AlertDialog( + title: Center( + child: Container( + decoration: const BoxDecoration( + border: Border(bottom: BorderSide(color: Colors.black)), + color: Colors.white, + ), + child: Text(title, style: const TextStyle(fontSize: 20)) + ) + ), + content: SizedBox( + height: 100, + child: Column( + children: [ + const SizedBox(height: 25), + Text(text), + const SizedBox(height: 5), + SizedBox( + width: 200, + child:TextField( + controller: controller, + ),) + ], + )), + actions: [ + TextButton( + onPressed: (){ + Navigator.of(context).pop(); + }, + child: const Text(PhonebookTextConstants.cancel), + ), + TextButton( + onPressed: () { + onConfirm(); + }, + child: const Text(PhonebookTextConstants.validation), + ), + ], + ); + } +} \ No newline at end of file From ee6c8f46ed5f5b349c36872571b4ced5d6728658 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:56:59 +0100 Subject: [PATCH 005/123] Allow local test and add client based research filter --- .../providers/association_list_provider.dart | 17 ++++- .../providers/role_list_provider.dart | 14 ++++- .../association_member_repository.dart | 6 +- .../repositories/association_repository.dart | 62 ++++++++++++------- .../repositories/role_repository.dart | 28 +++++---- lib/phonebook/tools/fake_class.dart | 46 +++++++++----- .../admin_page/association_research_bar.dart | 9 +-- .../pages/admin_page/role_research_bar.dart | 11 +--- .../association_editor_page.dart | 2 +- .../member_editable_card.dart | 20 +++--- .../association_page/association_page.dart | 2 +- .../ui/pages/main_page/research_bar.dart | 9 +-- 12 files changed, 134 insertions(+), 92 deletions(-) diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index 1a4fd62d9..c7dc9a184 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -12,8 +12,21 @@ class AssociationListNotifier extends ListNotifier { associationRepository.setToken(token); } - Future>> loadAssociations([String? filter]) async { - return await loadList(() async => associationRepository.getAssociationList(filter!)); + late List associationList; + + Future>> loadAssociations() async { + associationList = await associationRepository.getAssociationList(); + return await loadList(() async => associationRepository.getAssociationList()); + } + + List filterAssociations(String filter) { + if (filter.isEmpty) { + return associationList; + } + return associationList + .where((association) => + association.name.toLowerCase().contains(filter.toLowerCase())) + .toList(); } // Future>> loadAssociationsFromUser(User user) async { diff --git a/lib/phonebook/providers/role_list_provider.dart b/lib/phonebook/providers/role_list_provider.dart index d0ff253c0..52acdf9dc 100644 --- a/lib/phonebook/providers/role_list_provider.dart +++ b/lib/phonebook/providers/role_list_provider.dart @@ -12,8 +12,18 @@ class RoleListNotifier extends ListNotifier { roleRepository.setToken(token); } - Future>> loadRoles([String? filter]) async { - return await loadList(() async => roleRepository.getRoleList(filter!)); + late List roleList; + + Future>> loadRoles() async { + roleList = await roleRepository.getRoleList(); + return await loadList(() async => roleRepository.getRoleList()); + } + + List filterRoles(String filter) { + return roleList + .where((role) => + role.name.toLowerCase().contains(filter.toLowerCase())) + .toList(); } // Future>> loadRolesFromUser(User user) async { diff --git a/lib/phonebook/repositories/association_member_repository.dart b/lib/phonebook/repositories/association_member_repository.dart index 7183d5ec7..c43c97299 100644 --- a/lib/phonebook/repositories/association_member_repository.dart +++ b/lib/phonebook/repositories/association_member_repository.dart @@ -1,4 +1,5 @@ import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/tools/fake_class.dart'; import 'package:myecl/tools/repository/repository.dart'; class AssociationMemberRepository extends Repository { @@ -7,7 +8,8 @@ class AssociationMemberRepository extends Repository { final ext = "phonebook/association/"; Future> getAssociationMemberList(String associationId) async { - return List.from( - (await getList(suffix: "$associationId/members")).map((x) => CompleteMember.fromJSON(x))); + return fakeMembersList.where((element) => element.memberships.map((e) => e.association.id).contains(associationId)).toList(); + //return List.from( + // (await getList(suffix: "$associationId/members")).map((x) => CompleteMember.fromJSON(x))); } } \ No newline at end of file diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index 5f9f35ba5..e5791f920 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -1,6 +1,8 @@ import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/class/role.dart'; +import 'package:myecl/phonebook/tools/fake_class.dart'; import 'package:myecl/tools/repository/repository.dart'; import 'package:myecl/user/class/list_users.dart'; import 'dart:convert'; @@ -12,48 +14,60 @@ class AssociationRepository extends Repository { // ignore: overridden_fields final ext = "phonebook/association/"; - Future> getAssociationList([String? filter]) async { - String suffix = ""; - if (filter != null) { - suffix = "?filter=$filter"; - } - return List.from( - (await getList(suffix: suffix)).map((x) => Association.fromJSON(x))); + Future> getAssociationList() async { + return fakeAssociations; + //return List.from( + // (await getList()).map((x) => Association.fromJSON(x))); } Future getAssociation(String associationId) async { - return Association.fromJSON(await getOne(associationId)); + return fakeAssociations.firstWhere((element) => element.id == associationId); + //return Association.fromJSON(await getOne(associationId)); } Future deleteAssociation(String associationId) async { - return await delete(associationId); + fakeAssociations.removeWhere((element) => element.id == associationId); + return true; + //return await delete(associationId); } Future updateAssociation(Association association) async { - return await update(association.toJSON(), association.id); + fakeAssociations[fakeAssociations.indexWhere((element) => element.id == association.id)] = association; + return true; + //return await update(association.toJSON(), association.id); } Future createAssociation(Association association) async { - return Association.fromJSON(await create(association.toJSON())); + fakeAssociations.add(association); + association.id = fakeAssociations.length.toString(); + return association; + //return Association.fromJSON(await create(association.toJSON())); } Future addMember(Association association, CompleteMember member, Role role) async { - await create({"member_id": member.member.id, "association_id": association.id, "roleId": role.id}, - suffix: "membership"); + fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.member.id)] + .memberships + .add(Membership(association: association, role: role)); + //await create({"member_id": member.member.id, "association_id": association.id, "roleId": role.id}, + // suffix: "membership"); return true; } Future deleteMember(Association association, CompleteMember member) async { - final response = await http.delete( - Uri.parse("$host${ext}membership"), - headers: headers, - body: json.encode({"member_id": member.member.id, "association_id": association.id})); - if (response.statusCode == 204) { - return true; - } else if (response.statusCode == 403) { - throw AppException(ErrorType.tokenExpire, response.body); - } else { - throw AppException(ErrorType.notFound, "Failed to update item"); - } + fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.member.id)] + .memberships + .removeWhere((element) => element.association.id == association.id); + return true; + //final response = await http.delete( + // Uri.parse("$host${ext}membership"), + // headers: headers, + // body: json.encode({"member_id": member.member.id, "association_id": association.id})); + // if (response.statusCode == 204) { + // return true; + // } else if (response.statusCode == 403) { + // throw AppException(ErrorType.tokenExpire, response.body); + // } else { + // throw AppException(ErrorType.notFound, "Failed to update item"); + // } } } diff --git a/lib/phonebook/repositories/role_repository.dart b/lib/phonebook/repositories/role_repository.dart index 4bf87bf01..0452d73c9 100644 --- a/lib/phonebook/repositories/role_repository.dart +++ b/lib/phonebook/repositories/role_repository.dart @@ -1,4 +1,5 @@ import 'package:myecl/phonebook/class/role.dart'; +import 'package:myecl/phonebook/tools/fake_class.dart'; import 'package:myecl/tools/repository/repository.dart'; class RoleRepository extends Repository { @@ -6,28 +7,33 @@ class RoleRepository extends Repository { // ignore: overridden_fields final ext = "phonebook/role/"; - Future> getRoleList([String? filter]) async { - String suffix = ""; - if (filter != null) { - suffix = "?filter=$filter"; - } - return List.from( - (await getList(suffix: suffix)).map((x) => Role.fromJSON(x))); + Future> getRoleList() async { + return fakeRoles; + // return List.from( + // (await getList()).map((x) => Role.fromJSON(x))); } Future getRole(String roleId) async { - return Role.fromJSON(await getOne(roleId)); + return fakeRoles.firstWhere((element) => element.id == roleId); + //return Role.fromJSON(await getOne(roleId)); } Future deleteRole(String roleId) async { - return await delete(roleId); + fakeRoles.removeWhere((element) => element.id == roleId); + return true; + //return await delete(roleId); } Future updateRole(Role role) async { - return await update(role.toJSON(), role.id); + fakeRoles[fakeRoles.indexWhere((element) => element.id == role.id)] = role; + return true; + //return await update(role.toJSON(), role.id); } Future createRole(Role role) async { - return Role.fromJSON(await create(role.toJSON())); + fakeRoles.add(role); + role.id = fakeRoles.length.toString(); + return role; + //return Role.fromJSON(await create(role.toJSON())); } } diff --git a/lib/phonebook/tools/fake_class.dart b/lib/phonebook/tools/fake_class.dart index c9b7a287b..cad04d7dc 100644 --- a/lib/phonebook/tools/fake_class.dart +++ b/lib/phonebook/tools/fake_class.dart @@ -7,11 +7,6 @@ import 'package:myecl/phonebook/class/role.dart'; List fakeAssociations = [ Association(id: '1', name: 'test1', description: 'description test1'), Association(id: '2', name: 'test2', description: 'description test2'), - Association(id: '3', name: 'test3', description: 'description test3'), - Association(id: '4', name: 'test4', description: 'description test4'), - Association(id: '5', name: 'test5', description: 'description test5'), - Association(id: '6', name: 'test6', description: 'description test6'), - Association(id: '7', name: 'test7', description: 'description test7'), ]; List fakeRoles = [ @@ -20,10 +15,14 @@ List fakeRoles = [ Role(id: '3', name: 'SG'), Role(id: '4', name: 'Fillot'), Role(id: '5', name: 'VP Emprunt'), + Role(id: '6', name: 'VP Compta'), + Role(id: '7', name: 'VP Com'), + Role(id: '8', name: 'VP Log'), + Role(id: '9', name: 'VP RH'), + Role(id: '10', name: 'VP Appro'), ]; -List fakeMembersContructor(Association association) { - return [ +List fakeMembersList = [ CompleteMember( member: Member( name: 'Dupond', @@ -31,7 +30,7 @@ List fakeMembersContructor(Association association) { nickname: 'Testouille', id: '1', email: 'test1@useless'), - memberships: [Membership(association: association, role: fakeRoles[0])]), + memberships: [Membership(association: fakeAssociations[0], role: fakeRoles[0])]), CompleteMember( member: Member( name: 'Debouck', @@ -39,7 +38,7 @@ List fakeMembersContructor(Association association) { nickname: 'Chad', id: '2', email: 'test2@useless'), - memberships: [Membership(association: association, role: fakeRoles[1])]), + memberships: [Membership(association: fakeAssociations[0], role: fakeRoles[1])]), CompleteMember( member: Member( name: 'Ray', @@ -47,7 +46,7 @@ List fakeMembersContructor(Association association) { nickname: 'Salut', id: '3', email: 'test3@useless'), - memberships: [Membership(association: association, role: fakeRoles[2])]), + memberships: [Membership(association: fakeAssociations[1], role: fakeRoles[2])]), CompleteMember( member: Member( name: 'Guarriguenc', @@ -56,11 +55,26 @@ List fakeMembersContructor(Association association) { id: '4', email: 'test4@useless'), memberships: [ - Membership(association: association, role: fakeRoles[3]), - Membership( - association: Association( - id: '12', name: 'testTest', description: 'JSP frère'), - role: fakeRoles[4]) + Membership(association: fakeAssociations[1], role: fakeRoles[3]), + Membership(association: fakeAssociations[0], role: fakeRoles[4]), ]), + CompleteMember( + member: Member( + name: 'Boulet', + firstname: 'Jean', + nickname: 'Jean', + id: '5', + email: 'test5@useless'), + memberships: [Membership(association: fakeAssociations[1], role: fakeRoles[5])]), + CompleteMember( + member: Member( + name: 'Sarrazin', + firstname: 'François', + nickname: 'Zarzou', + id: '6', + email: 'test6@useless'), + memberships: [ + Membership(association: fakeAssociations[0], role: fakeRoles[6]), + Membership(association: fakeAssociations[0], role: fakeRoles[7])]), ]; -} + diff --git a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart index 610f06c02..c165dc661 100644 --- a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart +++ b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart @@ -31,14 +31,7 @@ class AssociationResearchBar extends HookConsumerWidget { width: 300, child: TextField( onChanged: (value) { - tokenExpireWrapper(ref, () async { - if (editingController.text.isNotEmpty) { - await associationListNotifier - .loadAssociations(editingController.text); - } else { - await associationListNotifier.loadAssociations(); - } - }); + associationListNotifier.filterAssociations(value); }, focusNode: focusNode, controller: editingController, diff --git a/lib/phonebook/ui/pages/admin_page/role_research_bar.dart b/lib/phonebook/ui/pages/admin_page/role_research_bar.dart index 34618c1f2..e4a6e0a1b 100644 --- a/lib/phonebook/ui/pages/admin_page/role_research_bar.dart +++ b/lib/phonebook/ui/pages/admin_page/role_research_bar.dart @@ -10,7 +10,7 @@ class RoleResearchBar extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final associationListNotifier = + final roleListNotifier = ref.watch(roleListProvider.notifier); final focusNode = useFocusNode(); final editingController = useTextEditingController(); @@ -31,14 +31,7 @@ class RoleResearchBar extends HookConsumerWidget { width: 300, child: TextField( onChanged: (value) { - tokenExpireWrapper(ref, () async { - if (editingController.text.isNotEmpty) { - await associationListNotifier - .loadRoles(editingController.text); - } else { - await associationListNotifier.loadRoles(); - } - }); + roleListNotifier.filterRoles(value); }, focusNode: focusNode, controller: editingController, diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 871004b80..b51167f45 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -131,7 +131,7 @@ class AssociationEditorPage extends HookConsumerWidget { error: (e, s) { //return const Center( // child: Text(PhonebookTextConstants.errorLoadAssociationMember), - List fakeMembers = fakeMembersContructor(association); + List fakeMembers = [CompleteMember.empty()]; return Column( children: fakeMembers.map((member) => MemberEditableCard(member: member) diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index 5b70ffdc9..a2ca5d152 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/user/providers/profile_picture_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; @@ -89,13 +90,16 @@ class MemberEditableCard extends HookConsumerWidget { SizedBox( width: 200, child: Center( - child: Text( - member.memberships.firstWhere((element) => element.association.id == association.id).role.name, - style: const TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - ), - ), + child : Row( + children: member.memberships.where((element) => element.association.id == association.id).map((e) => + Text( + e.role.name, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + ), + )).toList() + ) ) ), const SizedBox(width: 10), @@ -122,7 +126,7 @@ class MemberEditableCard extends HookConsumerWidget { const SizedBox(width: 10), GestureDetector( onTap: (){ - associationNotifier.deleteMember(association ,member); + associationNotifier.deleteMember(association ,member, ); }, child: Container( width: 40, diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index ece35b95f..afe382727 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -95,7 +95,7 @@ class AssociationPage extends HookConsumerWidget { error: (e, s) { //return const Center( // child: Text(PhonebookTextConstants.errorLoadAssociationMember), - List fakeMembers = fakeMembersContructor(association); + List fakeMembers = [CompleteMember.empty()]; return Column( children: fakeMembers.map((member) => MemberCard(member: member) diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart index b545594dc..737899262 100644 --- a/lib/phonebook/ui/pages/main_page/research_bar.dart +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -31,14 +31,7 @@ class ResearchBar extends HookConsumerWidget { width: 300, child: TextField( onChanged: (value) { - tokenExpireWrapper(ref, () async { - if (editingController.text.isNotEmpty) { - await associationListNotifier - .loadAssociations(editingController.text); - } else { - await associationListNotifier.loadAssociations(); - } - }); + associationListNotifier.filterAssociations(value); }, focusNode: focusNode, controller: editingController, From 03de58383c6ed83fc8fe7f181f5fdc1a2f2b35f0 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:00 +0100 Subject: [PATCH 006/123] Change roles and associations researches to be done locally --- .../providers/association_list_provider.dart | 4 +- .../providers/role_list_provider.dart | 4 +- .../repositories/association_repository.dart | 7 +- .../repositories/role_repository.dart | 7 +- lib/phonebook/tools/constants.dart | 7 ++ .../ui/pages/admin_page/admin_page.dart | 78 +++++++++++++++---- .../admin_page/association_research_bar.dart | 4 +- .../ui/pages/admin_page/role_card.dart | 4 + .../pages/admin_page/role_research_bar.dart | 7 +- .../association_editor_page.dart | 16 ++-- .../association_page/association_page.dart | 14 ++-- .../ui/pages/main_page/main_page.dart | 22 +++--- .../ui/pages/main_page/research_bar.dart | 4 +- 13 files changed, 124 insertions(+), 54 deletions(-) diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index c7dc9a184..d0ea214bd 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -55,11 +55,11 @@ class AssociationListNotifier extends ListNotifier { association); } - void setAssociation(Association association) { + void setAssociationList(List associationList) { state.whenData( (d) { state = - AsyncValue.data(d..[d.indexWhere((g) => g.id == association.id)] = association); + AsyncValue.data(associationList); }, ); } diff --git a/lib/phonebook/providers/role_list_provider.dart b/lib/phonebook/providers/role_list_provider.dart index 52acdf9dc..15a801763 100644 --- a/lib/phonebook/providers/role_list_provider.dart +++ b/lib/phonebook/providers/role_list_provider.dart @@ -52,11 +52,11 @@ class RoleListNotifier extends ListNotifier { role); } - void setRole(Role role) { + void setRoleList(List roleList) { state.whenData( (d) { state = - AsyncValue.data(d..[d.indexWhere((g) => g.id == role.id)] = role); + AsyncValue.data(roleList); }, ); } diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index e5791f920..13b201668 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -38,8 +38,13 @@ class AssociationRepository extends Repository { } Future createAssociation(Association association) async { + List ids = fakeAssociations.map((e) => e.id).toList(); + String newId = "1"; + while (ids.contains(newId)) { + newId = (int.parse(newId) + 1).toString(); + } + association.id = newId; fakeAssociations.add(association); - association.id = fakeAssociations.length.toString(); return association; //return Association.fromJSON(await create(association.toJSON())); } diff --git a/lib/phonebook/repositories/role_repository.dart b/lib/phonebook/repositories/role_repository.dart index 0452d73c9..4660ea757 100644 --- a/lib/phonebook/repositories/role_repository.dart +++ b/lib/phonebook/repositories/role_repository.dart @@ -31,8 +31,13 @@ class RoleRepository extends Repository { } Future createRole(Role role) async { + List ids = fakeRoles.map((e) => e.id).toList(); + String newId = "1"; + while (ids.contains(newId)) { + newId = (int.parse(newId) + 1).toString(); + } + role.id = newId; fakeRoles.add(role); - role.id = fakeRoles.length.toString(); return role; //return Role.fromJSON(await create(role.toJSON())); } diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index 4ef5190d8..41ef4927b 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -21,6 +21,8 @@ class PhonebookTextConstants { static const String association = "Association :"; static const String associationPure = "Association"; static const String rolePure = "Rôle"; + static const String associationPureSearch = " Association"; + static const String rolePureSearch = " Rôle"; static const String name = "Nom :"; static const String firstname = "Prénom :"; static const String nickname = "Surnom :"; @@ -45,6 +47,11 @@ class PhonebookTextConstants { static const String deleteRole = "Supprimer le rôle ?"; static const String deletedRole = "Rôle supprimé"; static const String errorLoadProfilePicture = "Erreur"; + static const String newRole = "Nouveau rôle"; + static const String errorRoleNameEmpty = "Veuillez entrer un nom de rôle"; + static const String chooseRoleName = "Entrez le nom du rôle"; + static const String errorRoleNameAlreadyExists = "Ce rôle existe déjà"; + static const String roleCreated = "Rôle créé"; } class PhonebookColorConstants{ diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 1e88f132d..753e8352e 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -1,14 +1,19 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/role.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/providers/role_list_provider.dart'; +import 'package:myecl/phonebook/providers/role_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/tools/fake_class.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/association_research_bar.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/role_research_bar.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/role_card.dart'; import 'package:myecl/phonebook/ui/association_card.dart'; +import 'package:myecl/phonebook/ui/text_input_dialog.dart'; +import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/ui/refresher.dart'; class AdminPage extends HookConsumerWidget { @@ -22,7 +27,14 @@ class AdminPage extends HookConsumerWidget { final rolesNotifier = ref.watch(roleListProvider.notifier); final associations = ref.watch(associationListProvider); final associationsNotifier = ref.watch(associationListProvider.notifier); + final roleNotifier = ref.watch(roleProvider.notifier); final controller = ScrollController(); + final roleCreationController = TextEditingController(); + + void displayToastWithContext(TypeMsg type, String msg) { + displayToast(context, type, msg); + } + return Refresher( onRefresh: () async { await associationsNotifier.loadAssociations(); @@ -39,7 +51,41 @@ class AdminPage extends HookConsumerWidget { child: roles.when( data: (data) { return Row( - children: data.map((e) => RoleCard(role: e)).toList(), + children: [ + GestureDetector( + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) { + return TextInputDialog( + controller: roleCreationController, + title: PhonebookTextConstants.newRole, + text: PhonebookTextConstants.chooseRoleName, + defaultText: "", + onConfirm: (){ + if (roleCreationController.text == ""){ + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.errorRoleNameEmpty); + } + else if (data.any((element) => element.name == roleCreationController.text)){ + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.errorRoleNameAlreadyExists); + } + else { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.roleCreated); + roleNotifier.createRole(Role(name : roleCreationController.text, id: "")); + rolesNotifier.loadRoles(); + Navigator.of(context).pop(); + } + },); + }); + }, + child: const SizedBox( + width: 100, + child: Icon(Icons.add), + ), + )] + data.map((e) => RoleCard(role: e)).toList(), ); }, loading: () { @@ -48,12 +94,12 @@ class AdminPage extends HookConsumerWidget { ); }, error: (e, s) { - //return const Center( - // child: Text(PhonebookTextConstants.errorLoadRoleList), - //); - return Row( - children: fakeRoles.map((e) => RoleCard(role: e)).toList(), + return const Center( + child: Text(PhonebookTextConstants.errorLoadRoleList), ); + // return Row( + // children: fakeRoles.map((e) => RoleCard(role: e)).toList(), + // ); }), ), const SizedBox(width: 10), @@ -74,17 +120,17 @@ class AdminPage extends HookConsumerWidget { ); }, error: (e, s) { - //return const Center( - // child: Text(PhonebookTextConstants.errorLoadAssociationList), - //); - return Column( - children: fakeAssociations.map((association) { - return AssociationCard(association: association, onClicked: () { - associationNotifier.setAssociation(association); - pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); - },); - }).toList(), + return const Center( + child: Text(PhonebookTextConstants.errorLoadAssociationList), ); + // return Column( + // children: fakeAssociations.map((association) { + // return AssociationCard(association: association, onClicked: () { + // associationNotifier.setAssociation(association); + // pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); + // },); + // }).toList(), + // ); }), ], )); diff --git a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart index c165dc661..0e04d41d1 100644 --- a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart +++ b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart @@ -31,13 +31,13 @@ class AssociationResearchBar extends HookConsumerWidget { width: 300, child: TextField( onChanged: (value) { - associationListNotifier.filterAssociations(value); + associationListNotifier.setAssociationList(associationListNotifier.filterAssociations(value)); }, focusNode: focusNode, controller: editingController, cursorColor: PhonebookColorConstants.textDark, decoration: const InputDecoration( - labelText: PhonebookTextConstants.associationPure, + labelText: PhonebookTextConstants.associationPureSearch, labelStyle: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, diff --git a/lib/phonebook/ui/pages/admin_page/role_card.dart b/lib/phonebook/ui/pages/admin_page/role_card.dart index e1594fc02..2b2f730c8 100644 --- a/lib/phonebook/ui/pages/admin_page/role_card.dart +++ b/lib/phonebook/ui/pages/admin_page/role_card.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/role.dart'; +import 'package:myecl/phonebook/providers/role_list_provider.dart'; import 'package:myecl/phonebook/providers/role_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/delete_button.dart'; @@ -19,6 +20,7 @@ class RoleCard extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { + final roleListNotifier = ref.watch(roleListProvider.notifier); final roleNotifier = ref.watch(roleProvider.notifier); final controller = TextEditingController(); void displayToastWithContext(TypeMsg type, String msg) { @@ -60,6 +62,7 @@ class RoleCard extends HookConsumerWidget { defaultText: role.name, onConfirm: (){ roleNotifier.updateRole(role.copyWith(name: controller.text)); + roleListNotifier.loadRoles(); Navigator.of(context).pop(); },); }); @@ -105,6 +108,7 @@ class RoleCard extends HookConsumerWidget { PhonebookTextConstants.deletingError); } }); + roleListNotifier.loadRoles(); }, ); }); diff --git a/lib/phonebook/ui/pages/admin_page/role_research_bar.dart b/lib/phonebook/ui/pages/admin_page/role_research_bar.dart index e4a6e0a1b..169f32df7 100644 --- a/lib/phonebook/ui/pages/admin_page/role_research_bar.dart +++ b/lib/phonebook/ui/pages/admin_page/role_research_bar.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -31,13 +33,14 @@ class RoleResearchBar extends HookConsumerWidget { width: 300, child: TextField( onChanged: (value) { - roleListNotifier.filterRoles(value); + debugPrint('value: $value'); + roleListNotifier.setRoleList(roleListNotifier.filterRoles(value)); }, focusNode: focusNode, controller: editingController, cursorColor: PhonebookColorConstants.textDark, decoration: const InputDecoration( - labelText: PhonebookTextConstants.rolePure, + labelText: PhonebookTextConstants.rolePureSearch, labelStyle: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index b51167f45..b26d0d3a2 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -129,14 +129,14 @@ class AssociationEditorPage extends HookConsumerWidget { ); }, error: (e, s) { - //return const Center( - // child: Text(PhonebookTextConstants.errorLoadAssociationMember), - List fakeMembers = [CompleteMember.empty()]; - return Column( - children: fakeMembers.map((member) => - MemberEditableCard(member: member) - ).toList() - ); + return const Center( + child: Text(PhonebookTextConstants.errorLoadAssociationMember)); + // List fakeMembers = [CompleteMember.empty()]; + // return Column( + // children: fakeMembers.map((member) => + // MemberEditableCard(member: member) + // ).toList() + // ); }, ), Row(children: [ diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index afe382727..73a2846e0 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -93,13 +93,13 @@ class AssociationPage extends HookConsumerWidget { ); }, error: (e, s) { - //return const Center( - // child: Text(PhonebookTextConstants.errorLoadAssociationMember), - List fakeMembers = [CompleteMember.empty()]; - return Column( - children: fakeMembers.map((member) => - MemberCard(member: member) - ).toList() + return const Center( + child: Text(PhonebookTextConstants.errorLoadAssociationMember), + // List fakeMembers = [CompleteMember.empty()]; + // return Column( + // children: fakeMembers.map((member) => + // MemberCard(member: member) + // ).toList() ); }, ) diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 520295657..a2fbee4c5 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -52,18 +52,18 @@ class MainPage extends HookConsumerWidget { ); }, error: (e, s) { - return Column( - children: fakeAssociations.map((association) { - return AssociationCard(association: association, onClicked: () { - associationNotifier.setAssociation(association); - pageNotifier.setPhonebookPage(PhonebookPage.associationPage); - },); - }).toList(), - ); + // return Column( + // children: fakeAssociations.map((association) { + // return AssociationCard(association: association, onClicked: () { + // associationNotifier.setAssociation(association); + // pageNotifier.setPhonebookPage(PhonebookPage.associationPage); + // },); + // }).toList(), + // ); - //return const Center( - // child: Text(PhonebookTextConstants.errorLoadAssociationList), - //); + return const Center( + child: Text(PhonebookTextConstants.errorLoadAssociationList), + ); }, )) ], diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart index 737899262..9e873e8c2 100644 --- a/lib/phonebook/ui/pages/main_page/research_bar.dart +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -31,13 +31,13 @@ class ResearchBar extends HookConsumerWidget { width: 300, child: TextField( onChanged: (value) { - associationListNotifier.filterAssociations(value); + associationListNotifier.setAssociationList(associationListNotifier.filterAssociations(value)); }, focusNode: focusNode, controller: editingController, cursorColor: PhonebookColorConstants.textDark, decoration: const InputDecoration( - labelText: PhonebookTextConstants.associationPure, + labelText: PhonebookTextConstants.associationPureSearch, labelStyle: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, From 380f1c217c5b411d993fdf373c1e22dd3192ea28 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:00 +0100 Subject: [PATCH 007/123] Fix akward line during research --- .../ui/pages/admin_page/association_research_bar.dart | 10 ---------- .../ui/pages/admin_page/role_research_bar.dart | 10 ---------- lib/phonebook/ui/pages/main_page/research_bar.dart | 9 --------- 3 files changed, 29 deletions(-) diff --git a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart index 0e04d41d1..1f5486e61 100644 --- a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart +++ b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart @@ -46,16 +46,6 @@ class AssociationResearchBar extends HookConsumerWidget { Icons.search, color: PhonebookColorConstants.textDark, size: 30, - ), - enabledBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: Colors.transparent, - ), - ), - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: PhonebookColorConstants.textDark, - ), )), )); } diff --git a/lib/phonebook/ui/pages/admin_page/role_research_bar.dart b/lib/phonebook/ui/pages/admin_page/role_research_bar.dart index 169f32df7..275022dc1 100644 --- a/lib/phonebook/ui/pages/admin_page/role_research_bar.dart +++ b/lib/phonebook/ui/pages/admin_page/role_research_bar.dart @@ -49,16 +49,6 @@ class RoleResearchBar extends HookConsumerWidget { Icons.search, color: PhonebookColorConstants.textDark, size: 30, - ), - enabledBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: Colors.transparent, - ), - ), - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: PhonebookColorConstants.textDark, - ), )), )); } diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart index 9e873e8c2..2e56887cb 100644 --- a/lib/phonebook/ui/pages/main_page/research_bar.dart +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -47,16 +47,7 @@ class ResearchBar extends HookConsumerWidget { color: PhonebookColorConstants.textDark, size: 30, ), - enabledBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: Colors.transparent, - ), ), - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: PhonebookColorConstants.textDark, - ), - )), )); } } From d95d7a2486e5c6c8f580dde93ad5d3009335ced8 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:00 +0100 Subject: [PATCH 008/123] apply changes on roles management for classes --- lib/phonebook/class/association.dart | 22 +- lib/phonebook/class/complete_member.dart | 4 +- lib/phonebook/class/membership.dart | 31 +- lib/phonebook/class/role.dart | 38 --- lib/phonebook/class/roles_tags.dart | 22 ++ .../providers/association_list_provider.dart | 18 +- .../providers/association_provider.dart | 9 +- .../providers/phonebook_page_provider.dart | 2 +- .../providers/role_list_provider.dart | 74 ---- lib/phonebook/providers/role_provider.dart | 35 -- .../providers/roles_tags_provider.dart | 27 ++ .../repositories/association_repository.dart | 20 +- .../repositories/role_repository.dart | 44 --- .../repositories/role_tags_repository.dart | 16 + lib/phonebook/tools/constants.dart | 6 + lib/phonebook/tools/fake_class.dart | 50 +-- lib/phonebook/ui/association_card.dart | 8 +- lib/phonebook/ui/edition_button.dart | 36 ++ lib/phonebook/ui/page_switcher.dart | 3 + .../ui/pages/admin_page/admin_page.dart | 100 ++---- .../ui/pages/admin_page/role_card.dart | 121 ------- .../pages/admin_page/role_research_bar.dart | 55 --- .../association_creation_page.dart | 222 ++++++++++++ .../association_editor_page.dart | 318 ++++++++++-------- .../member_editable_card.dart | 2 +- .../association_page/association_page.dart | 17 +- .../pages/association_page/member_card.dart | 2 +- .../member_detail_page.dart | 2 +- .../role_member_page/role_member_page.dart | 72 +--- lib/phonebook/ui/phonebook.dart | 3 + lib/phonebook/ui/text_input_dialog.dart | 1 + lib/phonebook/ui/top_bar.dart | 3 + 32 files changed, 666 insertions(+), 717 deletions(-) delete mode 100644 lib/phonebook/class/role.dart create mode 100644 lib/phonebook/class/roles_tags.dart delete mode 100644 lib/phonebook/providers/role_list_provider.dart delete mode 100644 lib/phonebook/providers/role_provider.dart create mode 100644 lib/phonebook/providers/roles_tags_provider.dart delete mode 100644 lib/phonebook/repositories/role_repository.dart create mode 100644 lib/phonebook/repositories/role_tags_repository.dart create mode 100644 lib/phonebook/ui/edition_button.dart delete mode 100644 lib/phonebook/ui/pages/admin_page/role_card.dart delete mode 100644 lib/phonebook/ui/pages/admin_page/role_research_bar.dart create mode 100644 lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart diff --git a/lib/phonebook/class/association.dart b/lib/phonebook/class/association.dart index 4787bee7f..8e2f77feb 100644 --- a/lib/phonebook/class/association.dart +++ b/lib/phonebook/class/association.dart @@ -3,16 +3,22 @@ class Association{ required this.id, required this.name, required this.description, + required this.kind, + required this.mandateYear, }); late final String id; late final String name; late final String description; + late final String kind; + late final String mandateYear; Association.fromJSON(Map json){ id = json['id']; name = json['name']; description = json['description']; + kind = json['kind']; + mandateYear = json['mandateYear']; } Map toJSON(){ @@ -20,6 +26,8 @@ class Association{ 'id': id, 'name': name, 'description': description, + 'kind': kind, + 'mandate_year': mandateYear, }; return data; } @@ -28,11 +36,15 @@ class Association{ String? id, String? name, String? description, + String? kind, + String? mandateYear, }) { return Association( id: id ?? this.id, name: name ?? this.name, description: description ?? this.description, + kind: kind ?? this.kind, + mandateYear: mandateYear ?? this.mandateYear, ); } @@ -40,10 +52,18 @@ class Association{ id = ""; name = ""; description = ""; + kind = ""; + mandateYear = ""; + } + + void newMandate(){ + mandateYear = (int.parse(mandateYear) + 1).toString(); } @override String toString(){ - return "Nom : $name, id : $id, description : $description"; + return "Nom : $name, id : $id, description : $description, kind : $kind, mandate_year : $mandateYear"; } + + } \ No newline at end of file diff --git a/lib/phonebook/class/complete_member.dart b/lib/phonebook/class/complete_member.dart index 4d9192b7a..89e128888 100644 --- a/lib/phonebook/class/complete_member.dart +++ b/lib/phonebook/class/complete_member.dart @@ -19,7 +19,7 @@ class CompleteMember{ Map toJSON(){ final data = { 'member': member.id, - 'membership': memberships.map((e) => [e.association.id, e.role.id]), + 'membership': memberships.map((e) => e.toJSON()).toList(), }; return data; } @@ -30,7 +30,7 @@ class CompleteMember{ }) { return CompleteMember( member: member ?? this.member, - memberships: membership ?? this.memberships, + memberships: membership ?? memberships, ); } diff --git a/lib/phonebook/class/membership.dart b/lib/phonebook/class/membership.dart index c3d3f457a..4da9646e7 100644 --- a/lib/phonebook/class/membership.dart +++ b/lib/phonebook/class/membership.dart @@ -1,48 +1,59 @@ import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/class/role.dart'; +import 'package:myecl/phonebook/class/roles_tags.dart'; class Membership{ Membership({ required this.association, - required this.role, + required this.rolesTags, + required this.apparentName, }); late final Association association; - late final Role role; + late final List rolesTags; + late final String apparentName; Membership.fromJSON(Map json){ association = json['association']; - role = json['role']; + rolesTags = json['role']; + apparentName = json['apparentName']; } Map toJSON(){ final data = { 'association': association.id, - 'role': role.id, + 'rolesTags': rolesTags, + 'apparentName': apparentName, }; return data; } Membership copyWith({ Association? association, - Role? role, + List? rolesTags, + String? apparentName, }) { return Membership( association: association ?? this.association, - role: role ?? this.role, + rolesTags: rolesTags ?? this.rolesTags, + apparentName: apparentName ?? this.apparentName, ); } Membership.empty(){ association = Association.empty(); - role = Role.empty(); + rolesTags = []; + apparentName = ""; } Membership setAssociation(String name, String id) { return copyWith(association: association.copyWith(name: name, id: id)); } - Membership setRole(String name, String id) { - return copyWith(role: role.copyWith(name: name, id: id)); + Membership setRolesTags(List rolesTags) { + return copyWith(rolesTags: rolesTags); + } + + Membership setApparentName(String apparentName) { + return copyWith(apparentName: apparentName); } } \ No newline at end of file diff --git a/lib/phonebook/class/role.dart b/lib/phonebook/class/role.dart deleted file mode 100644 index 262ff5217..000000000 --- a/lib/phonebook/class/role.dart +++ /dev/null @@ -1,38 +0,0 @@ -class Role{ - Role({ - required this.id, - required this.name, - }); - - late final String id; - late final String name; - - Role.fromJSON(Map json){ - id = json['id']; - name = json['name']; - } - - Map toJSON(){ - final data = { - 'id': id, - 'name': name, - }; - return data; - } - - Role copyWith({ - String? id, - String? name, - }) { - return Role( - id: id ?? this.id, - name: name ?? this.name, - ); - } - - Role.empty(){ - id = ""; - name = ""; - } - -} \ No newline at end of file diff --git a/lib/phonebook/class/roles_tags.dart b/lib/phonebook/class/roles_tags.dart new file mode 100644 index 000000000..d3d3adde6 --- /dev/null +++ b/lib/phonebook/class/roles_tags.dart @@ -0,0 +1,22 @@ +class RolesTags{ + RolesTags({ + required this.tags, + }); + + late final List tags; + + RolesTags.fromJSON(Map json){ + tags = json['tags']; + } + + Map toJSON(){ + final data = { + 'tags': tags, + }; + return data; + } + + RolesTags empty(){ + return RolesTags(tags: []); + } +} \ No newline at end of file diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index d0ea214bd..6637e0b86 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -1,3 +1,4 @@ +import 'package:flutter/rendering.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/repositories/association_repository.dart'; @@ -12,21 +13,23 @@ class AssociationListNotifier extends ListNotifier { associationRepository.setToken(token); } - late List associationList; Future>> loadAssociations() async { - associationList = await associationRepository.getAssociationList(); return await loadList(() async => associationRepository.getAssociationList()); } List filterAssociations(String filter) { if (filter.isEmpty) { - return associationList; + return state.maybeWhen( + data: (associations) => associations, + orElse: () => []); } - return associationList - .where((association) => - association.name.toLowerCase().contains(filter.toLowerCase())) - .toList(); + return state.maybeWhen( + data: (associations) => associations + .where((association) => + association.name.toLowerCase().contains(filter.toLowerCase())) + .toList(), + orElse: () => []); } // Future>> loadAssociationsFromUser(User user) async { @@ -36,6 +39,7 @@ class AssociationListNotifier extends ListNotifier { // } Future createAssociation(Association association) async { + debugPrint("createAssociation"); return await add(associationRepository.createAssociation, association); } diff --git a/lib/phonebook/providers/association_provider.dart b/lib/phonebook/providers/association_provider.dart index 72dfaf1a2..349bbb578 100644 --- a/lib/phonebook/providers/association_provider.dart +++ b/lib/phonebook/providers/association_provider.dart @@ -2,14 +2,14 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; -import 'package:myecl/phonebook/class/role.dart'; import 'package:myecl/phonebook/repositories/association_repository.dart'; import 'package:myecl/tools/providers/single_notifier.dart'; class AssociationNotifier extends SingleNotifier { final AssociationRepository associationRepository = AssociationRepository(); - AssociationNotifier({required String token}) : super(const AsyncValue.loading()) { + AssociationNotifier({required String token}) + : super(const AsyncValue.loading()) { associationRepository.setToken(token); } @@ -17,9 +17,9 @@ class AssociationNotifier extends SingleNotifier { return await load(() async => associationRepository.getAssociation(associationId)); } - Future addMember(Association association, CompleteMember user, Role role) async { + Future addMember(Association association, CompleteMember user, List rolesTags, String apparentName) async { return await update( - (association) async => associationRepository.addMember(association, user, role), association); + (association) async => associationRepository.addMember(association, user, rolesTags, apparentName), association); } Future deleteMember(Association association, CompleteMember user) async { @@ -30,6 +30,7 @@ class AssociationNotifier extends SingleNotifier { void setAssociation(Association association) { state = AsyncValue.data(association); } + } final asyncAssociationProvider = diff --git a/lib/phonebook/providers/phonebook_page_provider.dart b/lib/phonebook/providers/phonebook_page_provider.dart index 55be99c9d..c17950604 100644 --- a/lib/phonebook/providers/phonebook_page_provider.dart +++ b/lib/phonebook/providers/phonebook_page_provider.dart @@ -1,6 +1,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; -enum PhonebookPage { main, admin, memberDetail, addEditRoleMember, editRole, associationEditor, associationPage} +enum PhonebookPage { main, admin, memberDetail, addEditRoleMember, editRole, associationEditor, associationPage, associationCreation} final phonebookPageProvider = StateNotifierProvider((ref) { diff --git a/lib/phonebook/providers/role_list_provider.dart b/lib/phonebook/providers/role_list_provider.dart deleted file mode 100644 index 15a801763..000000000 --- a/lib/phonebook/providers/role_list_provider.dart +++ /dev/null @@ -1,74 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:myecl/phonebook/class/role.dart'; -import 'package:myecl/phonebook/repositories/role_repository.dart'; -import 'package:myecl/auth/providers/openid_provider.dart'; -import 'package:myecl/tools/providers/list_notifier.dart'; -import 'package:myecl/tools/token_expire_wrapper.dart'; - -class RoleListNotifier extends ListNotifier { - final RoleRepository roleRepository = RoleRepository(); - RoleListNotifier({required String token}) - : super(const AsyncValue.loading()) { - roleRepository.setToken(token); - } - - late List roleList; - - Future>> loadRoles() async { - roleList = await roleRepository.getRoleList(); - return await loadList(() async => roleRepository.getRoleList()); - } - - List filterRoles(String filter) { - return roleList - .where((role) => - role.name.toLowerCase().contains(filter.toLowerCase())) - .toList(); - } - -// Future>> loadRolesFromUser(User user) async { -// return await loadList(() async { -// return user.roles; -// }); -// } - - Future createRole(Role role) async { - return await add(roleRepository.createRole, role); - } - - Future updateRole(Role role) async { - return await update( - roleRepository.updateRole, - (roles, role) => - roles..[roles.indexWhere((g) => g.id == role.id)] = role, - role); - } - - Future deleteRole(Role role) async { - return await delete( - roleRepository.deleteRole, - (roles, role) => roles..removeWhere((i) => i.id == role.id), - role.id, - role); - } - - void setRoleList(List roleList) { - state.whenData( - (d) { - state = - AsyncValue.data(roleList); - }, - ); - } -} - -final roleListProvider = - StateNotifierProvider>>( - (ref) { - final token = ref.watch(tokenProvider); - RoleListNotifier provider = RoleListNotifier(token: token); - tokenExpireWrapperAuth(ref, () async { - await provider.loadRoles(); - }); - return provider; -}); diff --git a/lib/phonebook/providers/role_provider.dart b/lib/phonebook/providers/role_provider.dart deleted file mode 100644 index 7d46baab3..000000000 --- a/lib/phonebook/providers/role_provider.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:myecl/auth/providers/openid_provider.dart'; -import 'package:myecl/phonebook/class/role.dart'; -import 'package:myecl/phonebook/repositories/role_repository.dart'; -import 'package:myecl/tools/providers/single_notifier.dart'; - - -class RoleNotifier extends SingleNotifier { - final RoleRepository roleRepository = RoleRepository(); - RoleNotifier({required String token}) - : super(const AsyncValue.loading()) { - roleRepository.setToken(token); - } - - void setRole(Role i) { - state = AsyncValue.data(i); - } - - Future updateRole(Role role) async { - return update((role) async => roleRepository.updateRole(role), role); - } - - Future deleteRole(Role role) async { - return delete((role) async => roleRepository.deleteRole(role), role, role.id); - } - - Future createRole(Role role) async { - return add((role) async => roleRepository.createRole(role), role); - } -} - -final roleProvider = StateNotifierProvider>((ref) { - final token = ref.watch(tokenProvider); - return RoleNotifier(token: token); -}); \ No newline at end of file diff --git a/lib/phonebook/providers/roles_tags_provider.dart b/lib/phonebook/providers/roles_tags_provider.dart new file mode 100644 index 000000000..cbbbbeb9d --- /dev/null +++ b/lib/phonebook/providers/roles_tags_provider.dart @@ -0,0 +1,27 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/auth/providers/openid_provider.dart'; +import 'package:myecl/phonebook/class/roles_tags.dart'; +import 'package:myecl/phonebook/repositories/role_tags_repository.dart'; +import 'package:myecl/tools/providers/single_notifier.dart'; + + +class RolesTagsNotifier extends SingleNotifier { + final RolesTagsRepository rolesTagsRepository = RolesTagsRepository(); + RolesTagsNotifier({required String token}) + : super(const AsyncValue.loading()) { + rolesTagsRepository.setToken(token); + } + + void setRole(RolesTags i) { + state = AsyncValue.data(i); + } + + Future> loadRolesTags() async { + return await load(() async => rolesTagsRepository.getRolesTags()); + } +} + +final rolesTagsProvider = StateNotifierProvider>((ref) { + final token = ref.watch(tokenProvider); + return RolesTagsNotifier(token: token); +}); \ No newline at end of file diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index 13b201668..2770bceaa 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -1,7 +1,7 @@ +import 'package:flutter/material.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/membership.dart'; -import 'package:myecl/phonebook/class/role.dart'; import 'package:myecl/phonebook/tools/fake_class.dart'; import 'package:myecl/tools/repository/repository.dart'; import 'package:myecl/user/class/list_users.dart'; @@ -12,7 +12,7 @@ import 'package:myecl/tools/exception.dart'; class AssociationRepository extends Repository { @override // ignore: overridden_fields - final ext = "phonebook/association/"; + final ext = "phonebook/associations/"; Future> getAssociationList() async { return fakeAssociations; @@ -26,33 +26,37 @@ class AssociationRepository extends Repository { } Future deleteAssociation(String associationId) async { - fakeAssociations.removeWhere((element) => element.id == associationId); + //fakeAssociations.removeWhere((element) => element.id == associationId); return true; //return await delete(associationId); } Future updateAssociation(Association association) async { - fakeAssociations[fakeAssociations.indexWhere((element) => element.id == association.id)] = association; + //fakeAssociations[fakeAssociations.indexWhere((element) => element.id == association.id)] = association; return true; //return await update(association.toJSON(), association.id); } Future createAssociation(Association association) async { + debugPrint("createAssociation2"); List ids = fakeAssociations.map((e) => e.id).toList(); + debugPrint("createAssociation3"); String newId = "1"; + debugPrint("createAssociation4"); while (ids.contains(newId)) { newId = (int.parse(newId) + 1).toString(); } - association.id = newId; - fakeAssociations.add(association); + debugPrint("createAssociation5"); + association = association.copyWith(id: newId); + debugPrint("newId: $newId"); return association; //return Association.fromJSON(await create(association.toJSON())); } - Future addMember(Association association, CompleteMember member, Role role) async { + Future addMember(Association association, CompleteMember member, List rolesTags, String apparentName) async { fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.member.id)] .memberships - .add(Membership(association: association, role: role)); + .add(Membership(association: association, rolesTags: rolesTags, apparentName: apparentName)); //await create({"member_id": member.member.id, "association_id": association.id, "roleId": role.id}, // suffix: "membership"); return true; diff --git a/lib/phonebook/repositories/role_repository.dart b/lib/phonebook/repositories/role_repository.dart deleted file mode 100644 index 4660ea757..000000000 --- a/lib/phonebook/repositories/role_repository.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:myecl/phonebook/class/role.dart'; -import 'package:myecl/phonebook/tools/fake_class.dart'; -import 'package:myecl/tools/repository/repository.dart'; - -class RoleRepository extends Repository { - @override - // ignore: overridden_fields - final ext = "phonebook/role/"; - - Future> getRoleList() async { - return fakeRoles; - // return List.from( - // (await getList()).map((x) => Role.fromJSON(x))); - } - - Future getRole(String roleId) async { - return fakeRoles.firstWhere((element) => element.id == roleId); - //return Role.fromJSON(await getOne(roleId)); - } - - Future deleteRole(String roleId) async { - fakeRoles.removeWhere((element) => element.id == roleId); - return true; - //return await delete(roleId); - } - - Future updateRole(Role role) async { - fakeRoles[fakeRoles.indexWhere((element) => element.id == role.id)] = role; - return true; - //return await update(role.toJSON(), role.id); - } - -Future createRole(Role role) async { - List ids = fakeRoles.map((e) => e.id).toList(); - String newId = "1"; - while (ids.contains(newId)) { - newId = (int.parse(newId) + 1).toString(); - } - role.id = newId; - fakeRoles.add(role); - return role; - //return Role.fromJSON(await create(role.toJSON())); - } -} diff --git a/lib/phonebook/repositories/role_tags_repository.dart b/lib/phonebook/repositories/role_tags_repository.dart new file mode 100644 index 000000000..8c0110d3a --- /dev/null +++ b/lib/phonebook/repositories/role_tags_repository.dart @@ -0,0 +1,16 @@ +import 'package:myecl/phonebook/class/roles_tags.dart'; +import 'package:myecl/phonebook/tools/fake_class.dart'; +import 'package:myecl/tools/repository/repository.dart'; + +class RolesTagsRepository extends Repository { + @override + // ignore: overridden_fields + final ext = "phonebook/role/"; + + Future getRolesTags() async { + return fakeRolesTags; + // return RolesTags.fromJSON(await getList()); + } +} + + diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index 41ef4927b..c862246c9 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -46,12 +46,18 @@ class PhonebookTextConstants { static const String editRoleName = "Modifier le nom du rôle"; static const String deleteRole = "Supprimer le rôle ?"; static const String deletedRole = "Rôle supprimé"; + static const String updatedRole = "Rôle modifié"; + static const String updatingError = "Erreur lors de la modification"; static const String errorLoadProfilePicture = "Erreur"; static const String newRole = "Nouveau rôle"; static const String errorRoleNameEmpty = "Veuillez entrer un nom de rôle"; static const String chooseRoleName = "Entrez le nom du rôle"; static const String errorRoleNameAlreadyExists = "Ce rôle existe déjà"; static const String roleCreated = "Rôle créé"; + static const String updatedAssociationName = "Nom de l'association modifié"; + static const String errorAssociationLoading = "Erreur lors du chargement de l'association"; + static const String errorAssociationNameEmpty = "Veuillez entrer un nom d'association"; + static const String addedAssociation = "Association ajoutée"; } class PhonebookColorConstants{ diff --git a/lib/phonebook/tools/fake_class.dart b/lib/phonebook/tools/fake_class.dart index cad04d7dc..0d777aa29 100644 --- a/lib/phonebook/tools/fake_class.dart +++ b/lib/phonebook/tools/fake_class.dart @@ -2,25 +2,29 @@ import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/member.dart'; import 'package:myecl/phonebook/class/membership.dart'; -import 'package:myecl/phonebook/class/role.dart'; +import 'package:myecl/phonebook/class/roles_tags.dart'; + +String printFakeAssociations() { + String result = ''; + for (Association association in fakeAssociations) { + result += association.toString() + '\n'; + } + return result; +} + List fakeAssociations = [ - Association(id: '1', name: 'test1', description: 'description test1'), - Association(id: '2', name: 'test2', description: 'description test2'), + Association(id: '1', name: 'test1', description: 'description test1', kind: 'Section', mandateYear: "2023"), + Association(id: '2', name: 'test2', description: 'description test2', kind: 'Club', mandateYear: "2023"), ]; -List fakeRoles = [ - Role(id: '1', name: 'Prez\''), - Role(id: '2', name: 'Trez\''), - Role(id: '3', name: 'SG'), - Role(id: '4', name: 'Fillot'), - Role(id: '5', name: 'VP Emprunt'), - Role(id: '6', name: 'VP Compta'), - Role(id: '7', name: 'VP Com'), - Role(id: '8', name: 'VP Log'), - Role(id: '9', name: 'VP RH'), - Role(id: '10', name: 'VP Appro'), -]; +RolesTags fakeRolesTags = RolesTags(tags: [ + 'Prez\'', + 'Trez\'', + 'SG', + 'VP com', + 'VP sponsor', +]); List fakeMembersList = [ CompleteMember( @@ -30,7 +34,7 @@ List fakeMembersList = [ nickname: 'Testouille', id: '1', email: 'test1@useless'), - memberships: [Membership(association: fakeAssociations[0], role: fakeRoles[0])]), + memberships: [Membership(association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[0]], apparentName: 'Prez\'')]), CompleteMember( member: Member( name: 'Debouck', @@ -38,7 +42,7 @@ List fakeMembersList = [ nickname: 'Chad', id: '2', email: 'test2@useless'), - memberships: [Membership(association: fakeAssociations[0], role: fakeRoles[1])]), + memberships: [Membership(association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[1]], apparentName: 'Trez\'')]), CompleteMember( member: Member( name: 'Ray', @@ -46,7 +50,7 @@ List fakeMembersList = [ nickname: 'Salut', id: '3', email: 'test3@useless'), - memberships: [Membership(association: fakeAssociations[1], role: fakeRoles[2])]), + memberships: [Membership(association: fakeAssociations[1], rolesTags: [fakeRolesTags.tags[2]], apparentName: 'SG')]), CompleteMember( member: Member( name: 'Guarriguenc', @@ -55,8 +59,8 @@ List fakeMembersList = [ id: '4', email: 'test4@useless'), memberships: [ - Membership(association: fakeAssociations[1], role: fakeRoles[3]), - Membership(association: fakeAssociations[0], role: fakeRoles[4]), + Membership(association: fakeAssociations[1], rolesTags: [fakeRolesTags.tags[0]], apparentName: 'Prez\''), + Membership(association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[4]], apparentName: 'VP sponsor'), ]), CompleteMember( member: Member( @@ -65,7 +69,7 @@ List fakeMembersList = [ nickname: 'Jean', id: '5', email: 'test5@useless'), - memberships: [Membership(association: fakeAssociations[1], role: fakeRoles[5])]), + memberships: [Membership(association: fakeAssociations[1], rolesTags: [], apparentName: 'VP Emprunt')]), CompleteMember( member: Member( name: 'Sarrazin', @@ -74,7 +78,7 @@ List fakeMembersList = [ id: '6', email: 'test6@useless'), memberships: [ - Membership(association: fakeAssociations[0], role: fakeRoles[6]), - Membership(association: fakeAssociations[0], role: fakeRoles[7])]), + Membership(association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[3]], apparentName: 'VP com'), + Membership(association: fakeAssociations[0], rolesTags: [], apparentName: 'VP Event')]), ]; diff --git a/lib/phonebook/ui/association_card.dart b/lib/phonebook/ui/association_card.dart index 99e556bf2..c9451b691 100644 --- a/lib/phonebook/ui/association_card.dart +++ b/lib/phonebook/ui/association_card.dart @@ -16,7 +16,6 @@ class AssociationCard extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final pageNotifier = ref.watch(phonebookPageProvider.notifier); final associationPicture = ref.watch(associationPictureProvider); return GestureDetector( @@ -77,6 +76,13 @@ class AssociationCard extends HookConsumerWidget { ), ), ), + const Spacer(flex: 1), + Text(association.kind, + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), ], ) ) diff --git a/lib/phonebook/ui/edition_button.dart b/lib/phonebook/ui/edition_button.dart new file mode 100644 index 000000000..2d2588166 --- /dev/null +++ b/lib/phonebook/ui/edition_button.dart @@ -0,0 +1,36 @@ + +import 'package:flutter/material.dart'; +import 'package:heroicons/heroicons.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +class EditionButton extends HookConsumerWidget { + const EditionButton({Key? key, required this.onEdition}) : super(key: key); + final Future Function() onEdition; + + @override + Widget build(BuildContext context, WidgetRef ref) { + + return GestureDetector( + onTap: (){ + onEdition(); + }, + child: Container( + width: 40, + height: 40, + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.grey.shade200, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 10, + offset: const Offset(2, 3)) + ], + ), + child: const HeroIcon(HeroIcons.pencil, + color: Colors.black), + ), + ); + } +} \ No newline at end of file diff --git a/lib/phonebook/ui/page_switcher.dart b/lib/phonebook/ui/page_switcher.dart index f4bdc5e3c..dc9fbf5f8 100644 --- a/lib/phonebook/ui/page_switcher.dart +++ b/lib/phonebook/ui/page_switcher.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/admin_page.dart'; +import 'package:myecl/phonebook/ui/pages/association_creation_page/association_creation_page.dart'; import 'package:myecl/phonebook/ui/pages/association_editor_page/association_editor_page.dart'; import 'package:myecl/phonebook/ui/pages/association_page/association_page.dart'; import 'package:myecl/phonebook/ui/pages/main_page/main_page.dart'; @@ -30,6 +31,8 @@ class PageSwitcher extends ConsumerWidget { return const AssociationEditorPage(); case PhonebookPage.associationPage: return const AssociationPage(); + case PhonebookPage.associationCreation: + return const AssociationCreationPage(); default: return const Text('Unknown page'); } diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 753e8352e..0661c9d38 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -1,16 +1,13 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/class/role.dart'; +import 'package:myecl/phonebook/class/roles_tags.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; -import 'package:myecl/phonebook/providers/role_list_provider.dart'; -import 'package:myecl/phonebook/providers/role_provider.dart'; +import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/tools/fake_class.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/association_research_bar.dart'; -import 'package:myecl/phonebook/ui/pages/admin_page/role_research_bar.dart'; -import 'package:myecl/phonebook/ui/pages/admin_page/role_card.dart'; import 'package:myecl/phonebook/ui/association_card.dart'; import 'package:myecl/phonebook/ui/text_input_dialog.dart'; import 'package:myecl/tools/functions.dart'; @@ -23,13 +20,9 @@ class AdminPage extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final pageNotifier = ref.watch(phonebookPageProvider.notifier); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); - final roles = ref.watch(roleListProvider); - final rolesNotifier = ref.watch(roleListProvider.notifier); final associations = ref.watch(associationListProvider); final associationsNotifier = ref.watch(associationListProvider.notifier); - final roleNotifier = ref.watch(roleProvider.notifier); - final controller = ScrollController(); - final roleCreationController = TextEditingController(); + final roleNotifier = ref.watch(rolesTagsProvider.notifier); void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); @@ -38,77 +31,32 @@ class AdminPage extends HookConsumerWidget { return Refresher( onRefresh: () async { await associationsNotifier.loadAssociations(); - await rolesNotifier.loadRoles(); + await roleNotifier.loadRolesTags(); }, child: Column( children: [ - const RoleResearchBar(), - const SizedBox(width: 10), - SingleChildScrollView( - scrollDirection: Axis.horizontal, - physics: const BouncingScrollPhysics(), - controller: controller, - child: roles.when( - data: (data) { - return Row( - children: [ - GestureDetector( - onTap: () { - showDialog( - context: context, - builder: (BuildContext context) { - return TextInputDialog( - controller: roleCreationController, - title: PhonebookTextConstants.newRole, - text: PhonebookTextConstants.chooseRoleName, - defaultText: "", - onConfirm: (){ - if (roleCreationController.text == ""){ - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.errorRoleNameEmpty); - } - else if (data.any((element) => element.name == roleCreationController.text)){ - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.errorRoleNameAlreadyExists); - } - else { - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.roleCreated); - roleNotifier.createRole(Role(name : roleCreationController.text, id: "")); - rolesNotifier.loadRoles(); - Navigator.of(context).pop(); - } - },); - }); - }, - child: const SizedBox( - width: 100, - child: Icon(Icons.add), - ), - )] + data.map((e) => RoleCard(role: e)).toList(), - ); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: Text(PhonebookTextConstants.errorLoadRoleList), - ); - // return Row( - // children: fakeRoles.map((e) => RoleCard(role: e)).toList(), - // ); - }), - ), const SizedBox(width: 10), const AssociationResearchBar(), const SizedBox(width: 10), associations.when( data: (data) { return Column( - children: data.map((association) => AssociationCard(association: association, onClicked: () { + children: + [ + GestureDetector( + onTap: () { + pageNotifier.setPhonebookPage(PhonebookPage.associationCreation); + }, + child: Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.black), + borderRadius: const BorderRadius.all(Radius.circular(20)), + ), + height: 58, + margin: const EdgeInsets.all(10), + child: Row(children: const [Spacer(), Icon(Icons.add), Spacer()]) + ), + )] + data.map((association) => AssociationCard(association: association, onClicked: () { associationNotifier.setAssociation(association); pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); },)).toList(), @@ -123,14 +71,6 @@ class AdminPage extends HookConsumerWidget { return const Center( child: Text(PhonebookTextConstants.errorLoadAssociationList), ); - // return Column( - // children: fakeAssociations.map((association) { - // return AssociationCard(association: association, onClicked: () { - // associationNotifier.setAssociation(association); - // pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); - // },); - // }).toList(), - // ); }), ], )); diff --git a/lib/phonebook/ui/pages/admin_page/role_card.dart b/lib/phonebook/ui/pages/admin_page/role_card.dart deleted file mode 100644 index 2b2f730c8..000000000 --- a/lib/phonebook/ui/pages/admin_page/role_card.dart +++ /dev/null @@ -1,121 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:heroicons/heroicons.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/class/role.dart'; -import 'package:myecl/phonebook/providers/role_list_provider.dart'; -import 'package:myecl/phonebook/providers/role_provider.dart'; -import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/ui/delete_button.dart'; -import 'package:myecl/phonebook/ui/text_input_dialog.dart'; -import 'package:myecl/tools/functions.dart'; -import 'package:myecl/tools/token_expire_wrapper.dart'; -import 'package:myecl/tools/ui/dialog.dart'; - -class RoleCard extends HookConsumerWidget { - const RoleCard({super.key, - required this.role - }); - - final Role role; - - @override - Widget build(BuildContext context, WidgetRef ref) { - final roleListNotifier = ref.watch(roleListProvider.notifier); - final roleNotifier = ref.watch(roleProvider.notifier); - final controller = TextEditingController(); - void displayToastWithContext(TypeMsg type, String msg) { - displayToast(context, type, msg); - } - - return Container( - margin: const EdgeInsets.all(10), - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - border: Border.all(), - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(20)), - ), - - child: Row( - children: [ - const SizedBox(width: 10), - SizedBox( - width: 200, - child: Text( - role.name, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - GestureDetector( - onTap: (){ - roleNotifier.setRole(role); - showDialog( - context: context, - builder: (BuildContext context) { - return TextInputDialog( - controller: controller, - title: role.name, - text: PhonebookTextConstants.editRoleName, - defaultText: role.name, - onConfirm: (){ - roleNotifier.updateRole(role.copyWith(name: controller.text)); - roleListNotifier.loadRoles(); - Navigator.of(context).pop(); - },); - }); - }, - child: Container( - width: 40, - height: 40, - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.grey.shade200, - borderRadius: BorderRadius.circular(30), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.2), - blurRadius: 10, - offset: const Offset(2, 3)) - ], - ), - child: const HeroIcon(HeroIcons.pencil, - color: Colors.black), - ), - ), - const SizedBox(width: 10), - DeleteButton( - onDelete: () async { - await showDialog( - context: context, - builder: (context) { - return CustomDialogBox( - title: PhonebookTextConstants.deleting, - descriptions: - PhonebookTextConstants.deleteRole, - onYes: () async { - tokenExpireWrapper(ref, () async { - final value = await roleNotifier - .deleteRole(role); - if (value) { - displayToastWithContext( - TypeMsg.msg, - PhonebookTextConstants.deletedRole); - } else { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.deletingError); - } - }); - roleListNotifier.loadRoles(); - }, - ); - }); - }, - ), - ], - ) - ); - } -} \ No newline at end of file diff --git a/lib/phonebook/ui/pages/admin_page/role_research_bar.dart b/lib/phonebook/ui/pages/admin_page/role_research_bar.dart deleted file mode 100644 index 275022dc1..000000000 --- a/lib/phonebook/ui/pages/admin_page/role_research_bar.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'dart:math'; - -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/providers/role_list_provider.dart'; -import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/tools/token_expire_wrapper.dart'; - -class RoleResearchBar extends HookConsumerWidget { - const RoleResearchBar({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final roleListNotifier = - ref.watch(roleListProvider.notifier); - final focusNode = useFocusNode(); - final editingController = useTextEditingController(); - return Container( - decoration: BoxDecoration( - border: Border.all(), - color: Colors.white, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 1, - blurRadius: 7, - offset: const Offset(0, 3), // changes position of shadow - ), - ], - ), - width: 300, - child: TextField( - onChanged: (value) { - debugPrint('value: $value'); - roleListNotifier.setRoleList(roleListNotifier.filterRoles(value)); - }, - focusNode: focusNode, - controller: editingController, - cursorColor: PhonebookColorConstants.textDark, - decoration: const InputDecoration( - labelText: PhonebookTextConstants.rolePureSearch, - labelStyle: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: PhonebookColorConstants.textDark), - suffixIcon: Icon( - Icons.search, - color: PhonebookColorConstants.textDark, - size: 30, - )), - )); - } -} diff --git a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart new file mode 100644 index 000000000..d32641507 --- /dev/null +++ b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart @@ -0,0 +1,222 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/admin/tools/constants.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/providers/association_list_provider.dart'; +import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/tools/constants.dart'; +import 'package:myecl/tools/functions.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; +import 'package:myecl/tools/ui/shrink_button.dart'; + +class AssociationCreationPage extends HookConsumerWidget { + const AssociationCreationPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final key = GlobalKey(); + final name = useTextEditingController(); + final description = useTextEditingController(); + final pageNotifier = ref.watch(phonebookPageProvider.notifier); + final associationListNotifier = ref.watch(associationListProvider.notifier); + final associations = ref.watch(associationListProvider); + final associationNotifier = ref.watch(asyncAssociationProvider.notifier); + void displayToastWithContext(TypeMsg type, String msg) { + displayToast(context, type, msg); + } + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics( + parent: BouncingScrollPhysics(), + ), + child: Form( + key: key, + child: Column(children: [ + const Align( + alignment: Alignment.centerLeft, + child: Text(AdminTextConstants.addAssociation, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w700, + color: ColorConstants.gradient1)), + ), + const SizedBox( + height: 30, + ), + Container( + margin: const EdgeInsets.symmetric( + vertical: 20, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + alignment: Alignment.centerLeft, + margin: const EdgeInsets.only(bottom: 3), + child: const Text( + AdminTextConstants.name, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + color: Color.fromARGB(255, 158, 158, 158), + ), + ), + ), + SizedBox( + child: TextFormField( + controller: name, + decoration: const InputDecoration( + contentPadding: EdgeInsets.all(10), + isDense: true, + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: ColorConstants.gradient1))), + validator: (value) { + if (value == null) { + return AdminTextConstants.emptyFieldError; + } else if (value.isEmpty) { + return AdminTextConstants.emptyFieldError; + } else { + return null; + } + }, + ), + ), + ], + )), + Container( + margin: const EdgeInsets.symmetric(vertical: 20), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + alignment: Alignment.centerLeft, + margin: const EdgeInsets.only(bottom: 3), + child: const Text( + AdminTextConstants.description, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + color: Color.fromARGB(255, 158, 158, 158), + ), + ), + ), + SizedBox( + child: TextFormField( + controller: description, + decoration: const InputDecoration( + contentPadding: EdgeInsets.all(10), + isDense: true, + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: ColorConstants.gradient1))), + validator: (value) { + if (value == null) { + return AdminTextConstants.emptyFieldError; + } else if (value.isEmpty) { + return AdminTextConstants.emptyFieldError; + } else { + return null; + } + }, + ), + ), + ], + )), + ShrinkButton( + waitChild: Container( + width: double.infinity, + margin: const EdgeInsets.symmetric(vertical: 20), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), + ], + borderRadius: BorderRadius.circular(15), + ), + child: const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + color: Colors.white, + ), + ), + ), + onTap: () async { + await tokenExpireWrapper(ref, () async { + final value = await associationListNotifier.createAssociation( + Association.empty().copyWith( + name: name.text, + description: description.text,)); + if (value) { + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.addedAssociation); + associations.when(data: (d) { + associationNotifier.setAssociation(d.last); + pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); + }, + error: (e, s) => displayToastWithContext( + TypeMsg.error, PhonebookTextConstants.errorAssociationLoading), + loading: () {}); + + } else { + displayToastWithContext( + TypeMsg.error, AdminTextConstants.addingError); + } + }); + }, + child: Container( + width: double.infinity, + margin: const EdgeInsets.symmetric(vertical: 20), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), + ], + borderRadius: BorderRadius.circular(15), + ), + child: const Text( + AdminTextConstants.add, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), + ), + ), + ), + ) + ]), + ))); + } +} diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index b26d0d3a2..744339b7b 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -3,13 +3,16 @@ import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:image_picker/image_picker.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/tools/fake_class.dart'; +import 'package:myecl/phonebook/ui/edition_button.dart'; import 'package:myecl/phonebook/ui/pages/association_editor_page/member_editable_card.dart'; +import 'package:myecl/phonebook/ui/text_input_dialog.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/ui/refresher.dart'; @@ -20,155 +23,202 @@ class AssociationEditorPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final association = ref.watch(associationProvider); - final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); + final associationMemberListNotifier = + ref.watch(associationMemberListProvider.notifier); final associationMemberList = ref.watch(associationMemberListProvider); final associationPicture = ref.watch(associationPictureProvider); - final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); - - + final associationPictureNotifier = + ref.watch(associationPictureProvider.notifier); + final controller = TextEditingController(); + final associationListNotifier = ref.watch(associationListProvider.notifier); + final associationNotifier = ref.watch(asyncAssociationProvider.notifier); + + void displayToastWithContext(TypeMsg type, String msg) { + displayToast(context, type, msg); + } + String text = ""; if (association.id == "") { text = "Ajouter une association"; - } - else { + } else { text = "Modifier une association"; + } - void displayToastWithContext(TypeMsg type, String msg) { - displayToast(context, type, msg); - } + return Refresher( - onRefresh: () async { - await associationMemberListNotifier.loadMembers(association.id); - await associationPictureNotifier.getAssociationPicture(association.id); - }, - child: Column(children: [ - Center( - child : Text(text, style: const TextStyle(fontSize: 20))), + onRefresh: () async { + await associationMemberListNotifier.loadMembers(association.id); + await associationPictureNotifier + .getAssociationPicture(association.id); + }, + child: Center( + child: Column(children: [ + Text(text, style: const TextStyle(fontSize: 30)), + const SizedBox(height: 10), Row( - children: const [ - Text("Nom de l'association", style: TextStyle(fontSize: 20)), - Expanded( - child: TextField( - decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: 'Nom de l\'association', + children: [ + Spacer(), + Text(association.name, style: const TextStyle(fontSize: 40)), + const SizedBox(width: 10), + EditionButton(onEdition: () async { + showDialog( + context: context, + builder: (BuildContext context) { + return TextInputDialog( + controller: controller, + title: association.name, + text: PhonebookTextConstants.editRoleName, + defaultText: association.name, + onConfirm: () async { + final done = await associationListNotifier + .updateAssociation(association.copyWith( + name: controller.text)); + if (done) { + displayToastWithContext( + TypeMsg.msg, + PhonebookTextConstants + .updatedAssociationName); + associationNotifier.setAssociation( + association.copyWith(name: controller.text)); + } else { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.updatingError); + } + }); + }); + }) + ], + ), + const SizedBox(height: 10), + Stack( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + spreadRadius: 5, + blurRadius: 10, + offset: const Offset(2, 3), ), - ), + ], ), - ], - ), - Container( - margin: const EdgeInsets.all(10), - width: MediaQuery.of(context).size.width, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(50), - color: Colors.red + child: associationPicture.when( + data: (picture) { + return CircleAvatar( + radius: 120, + backgroundImage: picture.isEmpty + ? const AssetImage('assets/images/logo_alpha.png') + : Image.memory(picture).image, + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return const Center( + child: Text(PhonebookTextConstants.errorLoadAssociationPicture), + ); + }, ), - child: GestureDetector( - onTap: () async { - final value = await associationPictureNotifier - .setAssociationPicture(ImageSource.gallery, association.id); - if (value != null) { - if (value) { - displayToastWithContext( - TypeMsg.msg, - PhonebookTextConstants - .updatedAssociationPicture); - } else { - displayToastWithContext( - TypeMsg.error, - PhonebookTextConstants - .tooHeavyAssociationPicture); - } - } else { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.errorAssociationPicture); - } - }, - child: Container( - height: 40, - width: 40, - padding: const EdgeInsets.all(7), - decoration: BoxDecoration( - shape: BoxShape.circle, - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2 - .withOpacity(0.3), - spreadRadius: 2, - blurRadius: 4, - offset: const Offset(2, 3), + ), + Positioned( + bottom: 0, + child: GestureDetector( + onTap: () async { + final value = + await associationPictureNotifier.setAssociationPicture( + ImageSource.gallery, association.id); + if (value != null) { + if (value) { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.updatedAssociationPicture); + } else { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.tooHeavyAssociationPicture); + } + } else { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.errorAssociationPicture); + } + }, + child: Container( + padding: const EdgeInsets.all(7), + decoration: BoxDecoration( + shape: BoxShape.circle, + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.3), + spreadRadius: 2, + blurRadius: 4, + offset: const Offset(2, 3), + ), + ], ), - ], - ), - child: const HeroIcon( - HeroIcons.photo, - color: Colors.white, + child: const HeroIcon( + HeroIcons.photo, + color: Colors.white, + ), + ), ), ), - ),), - associationMemberList.when( - data: (members) { - return Column( - children: members.map((member) => - MemberEditableCard(member: member) - ).toList() - ); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: Text(PhonebookTextConstants.errorLoadAssociationMember)); - // List fakeMembers = [CompleteMember.empty()]; - // return Column( - // children: fakeMembers.map((member) => - // MemberEditableCard(member: member) - // ).toList() - // ); + ]),] + associationMemberList.when( + data: (members) { + return members + .map((member) => MemberEditableCard(member: member)) + .toList(); + }, + loading: () { + return [const Center( + child: CircularProgressIndicator(), + )]; + }, + error: (e, s) { + return [const Center( + child: + Text(PhonebookTextConstants.errorLoadAssociationMember))]; + }, + ) + [Row(children: [ + GestureDetector( + child: Container( + margin: const EdgeInsets.all(10), + width: MediaQuery.of(context).size.width / 2.3, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50), color: Colors.red), + child: const Center( + child: Text(PhonebookTextConstants.cancel, + style: TextStyle(fontSize: 20))), + ), + onTap: () { + //to complete }, ), - Row(children: [ - GestureDetector( - child: Container( - margin: const EdgeInsets.all(10), - width: MediaQuery.of(context).size.width/2.3, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(50), - color: Colors.red - ), - child: const Center(child : Text(PhonebookTextConstants.cancel, style: TextStyle(fontSize: 20))),), - onTap: () { - //to complete - }, - ), - GestureDetector( - child: Container( - margin: const EdgeInsets.all(10), - width: MediaQuery.of(context).size.width/2.3, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(50), - color: Colors.red - ), - child: const Center(child : Text(PhonebookTextConstants.validation, style: TextStyle(fontSize: 20))), - ), - onTap: () { - //to complete - }, - ) - - ]), - ])); + GestureDetector( + child: Container( + margin: const EdgeInsets.all(10), + width: MediaQuery.of(context).size.width / 2.3, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50), color: Colors.red), + child: const Center( + child: Text(PhonebookTextConstants.validation, + style: TextStyle(fontSize: 20))), + ), + onTap: () { + //to complete + }, + ) + ]),] + ))); } -} \ No newline at end of file +} diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index a2ca5d152..cd652a3bd 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -93,7 +93,7 @@ class MemberEditableCard extends HookConsumerWidget { child : Row( children: member.memberships.where((element) => element.association.id == association.id).map((e) => Text( - e.role.name, + e.apparentName, style: const TextStyle( fontSize: 15, fontWeight: FontWeight.bold, diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index 73a2846e0..7b887cd75 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -29,7 +29,7 @@ class AssociationPage extends HookConsumerWidget { }, child: Column( children: [ - const Text(PhonebookTextConstants.associationDetail), + const Text(PhonebookTextConstants.associationDetail, style: TextStyle(fontSize: 30)), const SizedBox(height: 20,), Container( decoration: BoxDecoration( @@ -46,7 +46,7 @@ class AssociationPage extends HookConsumerWidget { child: associationPicture.when( data: (picture) { return CircleAvatar( - radius: 80, + radius: 120, backgroundImage: picture.isEmpty ? const AssetImage('assets/images/logo_alpha.png') : Image.memory(picture).image, @@ -64,14 +64,21 @@ class AssociationPage extends HookConsumerWidget { }, ), ), - const SizedBox(height: 20,), + const SizedBox(height: 20), Text(association.name, style: const TextStyle( - fontSize: 20, + fontSize: 40, color: Colors.black ), ), - const SizedBox(height: 10,), + const SizedBox(height: 10), + Text(association.kind, + style: const TextStyle( + fontSize: 20, + color: Colors.black + ) + ), + const SizedBox(height: 10), Text(association.description, style: const TextStyle( fontSize: 15, diff --git a/lib/phonebook/ui/pages/association_page/member_card.dart b/lib/phonebook/ui/pages/association_page/member_card.dart index 5c8b26457..d1bc16f68 100644 --- a/lib/phonebook/ui/pages/association_page/member_card.dart +++ b/lib/phonebook/ui/pages/association_page/member_card.dart @@ -99,7 +99,7 @@ class MemberCard extends HookConsumerWidget { width: 100, child: Center( child: Text( - member.memberships.firstWhere((element) => element.association.id == association.id).role.name, + member.memberships.firstWhere((element) => element.association.id == association.id).apparentName, style: const TextStyle( fontSize: 15, fontWeight: FontWeight.bold, diff --git a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart index e33c45879..25bd5c57d 100644 --- a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart +++ b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart @@ -38,7 +38,7 @@ class MemberDetailPage extends HookConsumerWidget { child: Row( children: [ const Spacer(flex: 1), - Text("${membership.association.name} : ${membership.role.name}", + Text("${membership.association.name} : ${membership.apparentName}", style: const TextStyle(fontSize: 20)), const Spacer(flex: 1), ])) diff --git a/lib/phonebook/ui/pages/role_member_page/role_member_page.dart b/lib/phonebook/ui/pages/role_member_page/role_member_page.dart index 91873d682..2196f8a95 100644 --- a/lib/phonebook/ui/pages/role_member_page/role_member_page.dart +++ b/lib/phonebook/ui/pages/role_member_page/role_member_page.dart @@ -1,81 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/class/membership.dart'; -import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; -import 'package:myecl/phonebook/providers/membership_provider.dart'; -import 'package:myecl/phonebook/tools/constants.dart'; - class RoleMemberPage extends HookConsumerWidget { const RoleMemberPage({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { - final membership = ref.watch(membershipProvider); - final membershipNotifier = ref.watch(membershipProvider.notifier); - final pageNotifier = ref.watch(phonebookPageProvider.notifier); - Membership newMembership = membership; - final associationList = useState([["Association 1","1"], ["Association 2","2"], ["Association 3","3"]]); - final roleList = useState([["Rôle 1","1"], ["Rôle 2","2"], ["Rôle 3","3"]]); - return Column( - children: [ - const Text(PhonebookTextConstants.membershipAssociation), - const SizedBox(width: 10), - SizedBox( - width: 200, - child: Autocomplete( - initialValue: TextEditingValue(text: membership.association.name), - optionsBuilder: (TextEditingValue textValue) { - if (textValue.text == "") { - return associationList.value.map((e) => e[0]).toList(); - } - return associationList.value.map((e) => e[0]).toList().where((String option) { - return option.toLowerCase().contains(textValue.text.toLowerCase()); - }); - }, - onSelected: (String selection) { - String id = associationList.value.firstWhere((element) => element[0] == selection)[1]; - newMembership = newMembership.setAssociation(selection,id); - },)), - - const SizedBox(width: 30), - const Text(PhonebookTextConstants.membershipRole), - const SizedBox(width: 10), - SizedBox( - width: 200, - child: Autocomplete( - initialValue: TextEditingValue(text: membership.role.name), - optionsBuilder: (TextEditingValue textValue) { - if (textValue.text == "") { - return roleList.value.map((e) => e[0]).toList(); - } - return roleList.value.map((e) => e[0]).toList().where((String option) { - return option.toLowerCase().contains(textValue.text.toLowerCase()); - }); - }, - onSelected: (String selection) { - String id = roleList.value.firstWhere((element) => element[0] == selection)[1]; - newMembership = newMembership.setRole(selection,id); - },)), - ElevatedButton( - onPressed: () { - if (newMembership.association.name == "") { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text(PhonebookTextConstants.membershipAssociationError))); - return; - } - else if (newMembership.role.name == "") { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text(PhonebookTextConstants.membershipRoleError))); - return; - } - else { - membershipNotifier.setMembership(newMembership); - pageNotifier.setPhonebookPage(PhonebookPage.memberDetail); - } - }, - child: const Text(PhonebookTextConstants.validation), - ) - ], - ); + return SizedBox(); } } \ No newline at end of file diff --git a/lib/phonebook/ui/phonebook.dart b/lib/phonebook/ui/phonebook.dart index 6fba7517a..af7f38a32 100644 --- a/lib/phonebook/ui/phonebook.dart +++ b/lib/phonebook/ui/phonebook.dart @@ -45,6 +45,9 @@ class PhonebookHomePage extends HookConsumerWidget { case PhonebookPage.associationPage: pageNotifier.setPhonebookPage(PhonebookPage.main); break; + case PhonebookPage.associationCreation: + pageNotifier.setPhonebookPage(PhonebookPage.admin); + break; } return false; }, diff --git a/lib/phonebook/ui/text_input_dialog.dart b/lib/phonebook/ui/text_input_dialog.dart index 2eda50fd4..eccafffe5 100644 --- a/lib/phonebook/ui/text_input_dialog.dart +++ b/lib/phonebook/ui/text_input_dialog.dart @@ -54,6 +54,7 @@ class TextInputDialog extends HookConsumerWidget{ ), TextButton( onPressed: () { + Navigator.of(context).pop(); onConfirm(); }, child: const Text(PhonebookTextConstants.validation), diff --git a/lib/phonebook/ui/top_bar.dart b/lib/phonebook/ui/top_bar.dart index 731535256..6d52d82d4 100644 --- a/lib/phonebook/ui/top_bar.dart +++ b/lib/phonebook/ui/top_bar.dart @@ -49,6 +49,9 @@ class TopBar extends HookConsumerWidget { case PhonebookPage.associationPage: pageNotifier.setPhonebookPage(PhonebookPage.main); break; + case PhonebookPage.associationCreation: + pageNotifier.setPhonebookPage(PhonebookPage.admin); + break; } }, icon: HeroIcon( From e51a1bdb0ed93ac12dba6e5c413380a6ef0de7ef Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:00 +0100 Subject: [PATCH 009/123] Complete UI --- lib/phonebook/class/association_kinds.dart | 22 + lib/phonebook/class/complete_member.dart | 8 + lib/phonebook/class/member.dart | 10 + lib/phonebook/class/membership.dart | 1 - .../providers/association_kind_provider.dart | 14 + .../providers/association_kinds_provider.dart | 33 ++ .../providers/association_list_provider.dart | 25 +- .../providers/association_provider.dart | 10 +- .../filtered_association_list_provider.dart | 54 +++ .../providers/member_role_tags_provider.dart | 20 + .../providers/research_filter_provider.dart | 20 + .../providers/roles_tags_provider.dart | 7 +- .../association_kind_repository.dart | 14 + .../association_member_repository.dart | 2 +- .../association_picture_repository.dart | 2 +- .../repositories/association_repository.dart | 21 +- .../repositories/role_tags_repository.dart | 4 +- lib/phonebook/tools/constants.dart | 30 +- lib/phonebook/tools/fake_class.dart | 11 + .../ui/pages/admin_page/admin_page.dart | 89 ++-- .../ui/pages/admin_page/asso_ui.dart | 165 ------- .../admin_page/association_research_bar.dart | 11 +- .../admin_page/editable_association_card.dart | 85 ++++ .../association_creation_page.dart | 51 +- .../association_creation_page/kind_chip.dart | 33 ++ .../association_editor_page.dart | 436 +++++++++++------- .../member_editable_card.dart | 117 +++-- .../membership_dialog.dart | 136 ++++++ .../search_result.dart | 52 +++ .../pages/association_page/member_card.dart | 20 +- .../ui/pages/main_page/main_page.dart | 67 ++- .../ui/pages/main_page/research_bar.dart | 8 +- 32 files changed, 1041 insertions(+), 537 deletions(-) create mode 100644 lib/phonebook/class/association_kinds.dart create mode 100644 lib/phonebook/providers/association_kind_provider.dart create mode 100644 lib/phonebook/providers/association_kinds_provider.dart create mode 100644 lib/phonebook/providers/filtered_association_list_provider.dart create mode 100644 lib/phonebook/providers/member_role_tags_provider.dart create mode 100644 lib/phonebook/providers/research_filter_provider.dart create mode 100644 lib/phonebook/repositories/association_kind_repository.dart delete mode 100644 lib/phonebook/ui/pages/admin_page/asso_ui.dart create mode 100644 lib/phonebook/ui/pages/admin_page/editable_association_card.dart create mode 100644 lib/phonebook/ui/pages/association_creation_page/kind_chip.dart create mode 100644 lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart create mode 100644 lib/phonebook/ui/pages/association_editor_page/search_result.dart diff --git a/lib/phonebook/class/association_kinds.dart b/lib/phonebook/class/association_kinds.dart new file mode 100644 index 000000000..fef0a7775 --- /dev/null +++ b/lib/phonebook/class/association_kinds.dart @@ -0,0 +1,22 @@ +class AssociationKinds { + AssociationKinds({ + required this.kinds, + }); + + late final List kinds; + + AssociationKinds.fromJSON(Map json){ + kinds = json['kinds']; + } + + Map toJSON(){ + final data = { + 'kinds': kinds, + }; + return data; + } + + AssociationKinds empty(){ + return AssociationKinds(kinds: []); + } +} \ No newline at end of file diff --git a/lib/phonebook/class/complete_member.dart b/lib/phonebook/class/complete_member.dart index 89e128888..78812d2cb 100644 --- a/lib/phonebook/class/complete_member.dart +++ b/lib/phonebook/class/complete_member.dart @@ -39,4 +39,12 @@ class CompleteMember{ memberships = []; } + Member toMember(){ + return Member( + name: member.name, + firstname: member.firstname, + nickname: member.nickname, + id: member.id, + email: member.email); + } } diff --git a/lib/phonebook/class/member.dart b/lib/phonebook/class/member.dart index 5aab73cc3..2da43b3e9 100644 --- a/lib/phonebook/class/member.dart +++ b/lib/phonebook/class/member.dart @@ -1,3 +1,5 @@ +import 'package:myecl/user/class/list_users.dart'; + class Member{ Member({ required this.name, @@ -55,4 +57,12 @@ class Member{ id = ""; email = "email.test@empty.useless"; } + + Member.fromUser(SimpleUser user){ + name = user.name; + firstname = user.firstname; + nickname = user.nickname; + id = user.id; + email = ""; + } } \ No newline at end of file diff --git a/lib/phonebook/class/membership.dart b/lib/phonebook/class/membership.dart index 4da9646e7..1f31f4ac1 100644 --- a/lib/phonebook/class/membership.dart +++ b/lib/phonebook/class/membership.dart @@ -1,5 +1,4 @@ import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/class/roles_tags.dart'; class Membership{ Membership({ diff --git a/lib/phonebook/providers/association_kind_provider.dart b/lib/phonebook/providers/association_kind_provider.dart new file mode 100644 index 000000000..891404b2e --- /dev/null +++ b/lib/phonebook/providers/association_kind_provider.dart @@ -0,0 +1,14 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; + + +final kindProvider = StateNotifierProvider((ref) { + return KindNotifier(); +}); + +class KindNotifier extends StateNotifier { + KindNotifier() : super(""); + + void setKind(String i) { + state = i; + } +} \ No newline at end of file diff --git a/lib/phonebook/providers/association_kinds_provider.dart b/lib/phonebook/providers/association_kinds_provider.dart new file mode 100644 index 000000000..cef7cd6c6 --- /dev/null +++ b/lib/phonebook/providers/association_kinds_provider.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/auth/providers/openid_provider.dart'; +import 'package:myecl/phonebook/class/association_kinds.dart'; +import 'package:myecl/phonebook/repositories/association_kind_repository.dart'; +import 'package:myecl/tools/providers/single_notifier.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; + + +class AssociationKindsNotifier extends SingleNotifier { + final AssociationKindsRepository associationKindsRepository = AssociationKindsRepository(); + AssociationKindsNotifier({required String token}) + : super(const AsyncValue.loading()) { + associationKindsRepository.setToken(token); + } + + void setRole(AssociationKinds i) { + state = AsyncValue.data(i); + } + + Future> loadAssociationKinds() async { + return await load(() async => associationKindsRepository.getAssociationKinds()); + } +} + +final associationKindsProvider = StateNotifierProvider>((ref) { + final token = ref.watch(tokenProvider); + AssociationKindsNotifier notifier = AssociationKindsNotifier(token: token); + tokenExpireWrapperAuth(ref, () async { + await notifier.loadAssociationKinds(); + }); + return notifier; +}); \ No newline at end of file diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index 6637e0b86..e6f5e72bb 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -1,6 +1,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/repositories/association_repository.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/tools/providers/list_notifier.dart'; @@ -8,7 +9,8 @@ import 'package:myecl/tools/token_expire_wrapper.dart'; class AssociationListNotifier extends ListNotifier { final AssociationRepository associationRepository = AssociationRepository(); - AssociationListNotifier({required String token}) + AssociationListNotifier({ + required String token,}) : super(const AsyncValue.loading()) { associationRepository.setToken(token); } @@ -18,28 +20,7 @@ class AssociationListNotifier extends ListNotifier { return await loadList(() async => associationRepository.getAssociationList()); } - List filterAssociations(String filter) { - if (filter.isEmpty) { - return state.maybeWhen( - data: (associations) => associations, - orElse: () => []); - } - return state.maybeWhen( - data: (associations) => associations - .where((association) => - association.name.toLowerCase().contains(filter.toLowerCase())) - .toList(), - orElse: () => []); - } - -// Future>> loadAssociationsFromUser(User user) async { -// return await loadList(() async { -// return user.associations; -// }); -// } - Future createAssociation(Association association) async { - debugPrint("createAssociation"); return await add(associationRepository.createAssociation, association); } diff --git a/lib/phonebook/providers/association_provider.dart b/lib/phonebook/providers/association_provider.dart index 349bbb578..a1d75aade 100644 --- a/lib/phonebook/providers/association_provider.dart +++ b/lib/phonebook/providers/association_provider.dart @@ -2,6 +2,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/member.dart'; import 'package:myecl/phonebook/repositories/association_repository.dart'; import 'package:myecl/tools/providers/single_notifier.dart'; @@ -17,9 +18,9 @@ class AssociationNotifier extends SingleNotifier { return await load(() async => associationRepository.getAssociation(associationId)); } - Future addMember(Association association, CompleteMember user, List rolesTags, String apparentName) async { + Future addMember(Association association, Member member, List rolesTags, String apparentName) async { return await update( - (association) async => associationRepository.addMember(association, user, rolesTags, apparentName), association); + (association) async => associationRepository.addMember(association, member, rolesTags, apparentName), association); } Future deleteMember(Association association, CompleteMember user) async { @@ -27,6 +28,11 @@ class AssociationNotifier extends SingleNotifier { (association) async => associationRepository.deleteMember(association, user), association); } + Future updateMember(Association association, Member user, List rolesTags, String apparentName) async { + return await update( + (association) async => associationRepository.updateMember(association, user, rolesTags, apparentName), association); + } + void setAssociation(Association association) { state = AsyncValue.data(association); } diff --git a/lib/phonebook/providers/filtered_association_list_provider.dart b/lib/phonebook/providers/filtered_association_list_provider.dart new file mode 100644 index 000000000..cae927d53 --- /dev/null +++ b/lib/phonebook/providers/filtered_association_list_provider.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/auth/providers/openid_provider.dart'; +import 'package:myecl/phonebook/providers/association_list_provider.dart'; +import 'package:myecl/phonebook/repositories/association_repository.dart'; +import 'package:myecl/tools/providers/list_notifier.dart'; +import 'package:myecl/tools/providers/single_notifier.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; + +class FilteredAssociationListNotifier extends ListNotifier { + final AssociationRepository associationRepository = AssociationRepository(); + FilteredAssociationListNotifier({ + required String token, + required this.associationList,}) + : super(const AsyncValue.loading()) { + associationRepository.setToken(token); + } + + late final AsyncValue> associationList; + + Future>> loadAssociations() async { + return await loadList(() async => associationRepository.getAssociationList()); + } + + void filterAssociationList(String filter) async { + associationList.maybeWhen( + data: (d) { + state = AsyncValue.data(d.where((association) => association.name.toLowerCase().contains(filter.toLowerCase())).toList()); + }, + orElse: () => state = const AsyncLoading()); + } + + void setAssociationList(List associationList) { + state.whenData( + (d) { + state = + AsyncValue.data(associationList); + }, + ); + } +} + +final filteredAssociationListProvider = + StateNotifierProvider>>( + (ref) { + final token = ref.watch(tokenProvider); + final associationList = ref.watch(associationListProvider); + FilteredAssociationListNotifier notifier = FilteredAssociationListNotifier(token: token, associationList: associationList); + tokenExpireWrapperAuth(ref, () async { + await notifier.loadAssociations(); + }); + return notifier; +}); diff --git a/lib/phonebook/providers/member_role_tags_provider.dart b/lib/phonebook/providers/member_role_tags_provider.dart new file mode 100644 index 000000000..9bdcf51b1 --- /dev/null +++ b/lib/phonebook/providers/member_role_tags_provider.dart @@ -0,0 +1,20 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; + + +final memberRolesTagsProvider = StateNotifierProvider>((ref) { + return MemberRolesTagsProvider(); +}); + +class MemberRolesTagsProvider extends StateNotifier> { + MemberRolesTagsProvider() : super([]); + + void setRoleTagsWithFilter(List i, List filter) { + List newRoleTags = []; + for (int i = 0; i < filter.length; i++) { + if (filter[i]) { + newRoleTags.add(state[i]); + } + } + state = newRoleTags; + } +} \ No newline at end of file diff --git a/lib/phonebook/providers/research_filter_provider.dart b/lib/phonebook/providers/research_filter_provider.dart new file mode 100644 index 000000000..e276ceab5 --- /dev/null +++ b/lib/phonebook/providers/research_filter_provider.dart @@ -0,0 +1,20 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/phonebook/providers/filtered_association_list_provider.dart'; + + +final filterProvider = StateNotifierProvider((ref) { + final filteredAssociationListNotifier = ref.watch(filteredAssociationListProvider.notifier); + return FilterNotifier(filteredAssociationListNotifier); +}); + +class FilterNotifier extends StateNotifier { + FilterNotifier(this.filteredAssociationListNotifier + ) : super(""); + + late final FilteredAssociationListNotifier filteredAssociationListNotifier; + + void setFilter(String i) { + state = i; + filteredAssociationListNotifier.filterAssociationList(i); + } +} \ No newline at end of file diff --git a/lib/phonebook/providers/roles_tags_provider.dart b/lib/phonebook/providers/roles_tags_provider.dart index cbbbbeb9d..f3e59cb82 100644 --- a/lib/phonebook/providers/roles_tags_provider.dart +++ b/lib/phonebook/providers/roles_tags_provider.dart @@ -3,6 +3,7 @@ import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/roles_tags.dart'; import 'package:myecl/phonebook/repositories/role_tags_repository.dart'; import 'package:myecl/tools/providers/single_notifier.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; class RolesTagsNotifier extends SingleNotifier { @@ -23,5 +24,9 @@ class RolesTagsNotifier extends SingleNotifier { final rolesTagsProvider = StateNotifierProvider>((ref) { final token = ref.watch(tokenProvider); - return RolesTagsNotifier(token: token); + RolesTagsNotifier notifier = RolesTagsNotifier(token: token); + tokenExpireWrapperAuth(ref, () async { + await notifier.loadRolesTags(); + }); + return notifier; }); \ No newline at end of file diff --git a/lib/phonebook/repositories/association_kind_repository.dart b/lib/phonebook/repositories/association_kind_repository.dart new file mode 100644 index 000000000..44eebe655 --- /dev/null +++ b/lib/phonebook/repositories/association_kind_repository.dart @@ -0,0 +1,14 @@ +import 'package:myecl/phonebook/class/association_kinds.dart'; +import 'package:myecl/phonebook/tools/fake_class.dart'; +import 'package:myecl/tools/repository/repository.dart'; + +class AssociationKindsRepository extends Repository { + @override + // ignore: overridden_fields + final ext = "phonebook/associations"; + + Future getAssociationKinds() async { + return fakeAssociationKinds ; + // return AssociationKinds.fromJSON(await getOne("kinds")); + } +} \ No newline at end of file diff --git a/lib/phonebook/repositories/association_member_repository.dart b/lib/phonebook/repositories/association_member_repository.dart index c43c97299..a0b14c877 100644 --- a/lib/phonebook/repositories/association_member_repository.dart +++ b/lib/phonebook/repositories/association_member_repository.dart @@ -5,7 +5,7 @@ import 'package:myecl/tools/repository/repository.dart'; class AssociationMemberRepository extends Repository { @override // ignore: overridden_fields - final ext = "phonebook/association/"; + final ext = "phonebook/associations/"; Future> getAssociationMemberList(String associationId) async { return fakeMembersList.where((element) => element.memberships.map((e) => e.association.id).contains(associationId)).toList(); diff --git a/lib/phonebook/repositories/association_picture_repository.dart b/lib/phonebook/repositories/association_picture_repository.dart index b24a47d81..00aeae50f 100644 --- a/lib/phonebook/repositories/association_picture_repository.dart +++ b/lib/phonebook/repositories/association_picture_repository.dart @@ -4,7 +4,7 @@ import 'package:myecl/tools/repository/logo_repository.dart'; class AssociationPictureRepository extends LogoRepository { @override // ignore: overridden_fields - final ext = 'phonebook/association/'; + final ext = 'phonebook/associations/'; Future getAssociationPicture(String associationId) async { return await getLogo(associationId, suffix: "/picture"); diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index 2770bceaa..2b343ca89 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/member.dart'; import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/tools/fake_class.dart'; import 'package:myecl/tools/repository/repository.dart'; @@ -38,26 +39,21 @@ class AssociationRepository extends Repository { } Future createAssociation(Association association) async { - debugPrint("createAssociation2"); List ids = fakeAssociations.map((e) => e.id).toList(); - debugPrint("createAssociation3"); String newId = "1"; - debugPrint("createAssociation4"); while (ids.contains(newId)) { newId = (int.parse(newId) + 1).toString(); } - debugPrint("createAssociation5"); association = association.copyWith(id: newId); - debugPrint("newId: $newId"); return association; //return Association.fromJSON(await create(association.toJSON())); } - Future addMember(Association association, CompleteMember member, List rolesTags, String apparentName) async { - fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.member.id)] + Future addMember(Association association, Member member, List rolesTags, String apparentName) async { + fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.id)] .memberships .add(Membership(association: association, rolesTags: rolesTags, apparentName: apparentName)); - //await create({"member_id": member.member.id, "association_id": association.id, "roleId": role.id}, + //await create({"member_id": member.id, "association_id": association.id, "rolesTags": rolesTags, "apparentName": apparentName"}, // suffix: "membership"); return true; } @@ -79,4 +75,13 @@ class AssociationRepository extends Repository { // throw AppException(ErrorType.notFound, "Failed to update item"); // } } + + Future updateMember(Association association, Member member, List rolesTags, String apparentName) async { + fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.id)] + .memberships + .add(Membership(association: association, rolesTags: rolesTags, apparentName: apparentName)); + //await update({"member_id": member.id, "association_id": association.id, "rolesTags": rolesTags, "apparentName": apparentName"}, + // suffix: "membership"); + return true; + } } diff --git a/lib/phonebook/repositories/role_tags_repository.dart b/lib/phonebook/repositories/role_tags_repository.dart index 8c0110d3a..6a1214899 100644 --- a/lib/phonebook/repositories/role_tags_repository.dart +++ b/lib/phonebook/repositories/role_tags_repository.dart @@ -5,11 +5,11 @@ import 'package:myecl/tools/repository/repository.dart'; class RolesTagsRepository extends Repository { @override // ignore: overridden_fields - final ext = "phonebook/role/"; + final ext = "phonebook/"; Future getRolesTags() async { return fakeRolesTags; - // return RolesTags.fromJSON(await getList()); + // return RolesTags.fromJSON(await getOne("rolesTags")); } } diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index c862246c9..4add155e6 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -12,7 +12,6 @@ class PhonebookTextConstants { static const String updatedAssociationPicture = "La photo d'association a été changée"; static const String tooHeavyAssociationPicture = "L'image est trop lourde (max 4Mo)"; - static const String membershipAssociation = "Association :"; static const String membershipRole = "Rôle :"; static const String membershipAssociationError = "Veuillez choisir une association"; static const String membershipRoleError = "Veuillez choisir un rôle"; @@ -22,7 +21,6 @@ class PhonebookTextConstants { static const String associationPure = "Association"; static const String rolePure = "Rôle"; static const String associationPureSearch = " Association"; - static const String rolePureSearch = " Rôle"; static const String name = "Nom :"; static const String firstname = "Prénom :"; static const String nickname = "Surnom :"; @@ -30,8 +28,6 @@ class PhonebookTextConstants { static const String detail = "Détail :"; static const String addRole = "Ajouter un rôle"; static const String adminPage = "Page Administrateur"; - static const String addEditAssociation = "Ajouter/Modifier une association"; - static const String editRole = "Modifier un rôle"; static const String admin = "Admin"; static const String addAssociation = "Ajouter une association"; static const String errorLoadAssociationPicture = "Erreur lors du chargement de la photo d'association"; @@ -42,22 +38,26 @@ class PhonebookTextConstants { static const String errorLoadAssociationList = "Erreur lors du chargement de la liste des associations"; static const String associationDetail = "Détail de l'association :"; static const String errorLoadAssociationMember = "Erreur lors du chargement des membres de l'association"; - static const String errorLoadRoleList = "Erreur lors du chargement de la liste des rôles"; - static const String editRoleName = "Modifier le nom du rôle"; - static const String deleteRole = "Supprimer le rôle ?"; - static const String deletedRole = "Rôle supprimé"; - static const String updatedRole = "Rôle modifié"; static const String updatingError = "Erreur lors de la modification"; static const String errorLoadProfilePicture = "Erreur"; - static const String newRole = "Nouveau rôle"; - static const String errorRoleNameEmpty = "Veuillez entrer un nom de rôle"; - static const String chooseRoleName = "Entrez le nom du rôle"; - static const String errorRoleNameAlreadyExists = "Ce rôle existe déjà"; - static const String roleCreated = "Rôle créé"; - static const String updatedAssociationName = "Nom de l'association modifié"; + static const String updatedAssociation = "Association modifiée"; static const String errorAssociationLoading = "Erreur lors du chargement de l'association"; static const String errorAssociationNameEmpty = "Veuillez entrer un nom d'association"; static const String addedAssociation = "Association ajoutée"; + static const String deletedMember = "Membre supprimé"; + static const String associationKind = "Type d'association :"; + static const String errorKindsLoading = "Erreur lors du chargement des types d'association"; + static const String emptyFieldError = "Un champ n'est pas rempli"; + static const String emptyKindError = "Veuillez choisir un type d'association"; + static const String edit = "Modifier"; + static const String members = "Membres"; + static const String member = "Membre"; + static const String apparentName = "Nom public du rôle:"; + static const String editMembership = "Modifier le rôle"; + static const String addedMember = "Membre ajouté"; + static const String addingError = "Erreur lors de l'ajout"; + static const String addMember = "Ajouter un membre"; + static const String updatedMember = "Membre modifié"; } class PhonebookColorConstants{ diff --git a/lib/phonebook/tools/fake_class.dart b/lib/phonebook/tools/fake_class.dart index 0d777aa29..0e8ac2076 100644 --- a/lib/phonebook/tools/fake_class.dart +++ b/lib/phonebook/tools/fake_class.dart @@ -1,4 +1,5 @@ import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/class/association_kinds.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/member.dart'; import 'package:myecl/phonebook/class/membership.dart'; @@ -26,6 +27,16 @@ RolesTags fakeRolesTags = RolesTags(tags: [ 'VP sponsor', ]); +AssociationKinds fakeAssociationKinds = AssociationKinds(kinds: [ + 'Section', + 'Club', + 'Comité', + 'Fédération', + 'Association', + 'Autre', +]); + + List fakeMembersList = [ CompleteMember( member: Member( diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 0661c9d38..786b13366 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -1,15 +1,15 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/class/roles_tags.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; +import 'package:myecl/phonebook/providers/filtered_association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/tools/fake_class.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/association_research_bar.dart'; import 'package:myecl/phonebook/ui/association_card.dart'; -import 'package:myecl/phonebook/ui/text_input_dialog.dart'; +import 'package:myecl/phonebook/ui/pages/admin_page/editable_association_card.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/ui/refresher.dart'; @@ -20,9 +20,12 @@ class AdminPage extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final pageNotifier = ref.watch(phonebookPageProvider.notifier); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); - final associations = ref.watch(associationListProvider); final associationsNotifier = ref.watch(associationListProvider.notifier); + final filteredAssociations = ref.watch(filteredAssociationListProvider); + final associations = ref.watch(associationListProvider); final roleNotifier = ref.watch(rolesTagsProvider.notifier); + final filterNotifier = ref.watch(filterProvider.notifier); + final filteredAssociationListNotifier = ref.watch(filteredAssociationListProvider.notifier); void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); @@ -32,47 +35,53 @@ class AdminPage extends HookConsumerWidget { onRefresh: () async { await associationsNotifier.loadAssociations(); await roleNotifier.loadRolesTags(); + await filteredAssociationListNotifier.loadAssociations(); }, child: Column( - children: [ - const SizedBox(width: 10), + children: + [const SizedBox(width: 10), const AssociationResearchBar(), const SizedBox(width: 10), - associations.when( - data: (data) { - return Column( - children: - [ - GestureDetector( - onTap: () { - pageNotifier.setPhonebookPage(PhonebookPage.associationCreation); - }, - child: Container( - decoration: BoxDecoration( - border: Border.all(color: Colors.black), - borderRadius: const BorderRadius.all(Radius.circular(20)), - ), - height: 58, - margin: const EdgeInsets.all(10), - child: Row(children: const [Spacer(), Icon(Icons.add), Spacer()]) - ), - )] + data.map((association) => AssociationCard(association: association, onClicked: () { + Column( + children: [ + GestureDetector( + onTap: () { + pageNotifier.setPhonebookPage(PhonebookPage.associationCreation); + }, + child: Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.black), + borderRadius: const BorderRadius.all(Radius.circular(20)), + ), + height: 58, + margin: const EdgeInsets.all(10), + child: Row(children: const [Spacer(), Icon(Icons.add), Spacer()]) + ), + )] + + associations.when( + data: (associations) { + return associations.map((association) => EditableAssociationCard( + association: association, + onEdit: () { associationNotifier.setAssociation(association); pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); - },)).toList(), - ); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: Text(PhonebookTextConstants.errorLoadAssociationList), - ); - }), - ], - )); + }, + onDelete: () async { + final result = await associationsNotifier.deleteAssociation(association); + if (result) { + displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.deletedAssociation); + } else { + displayToastWithContext(TypeMsg.error, PhonebookTextConstants.deletingError); + } + associationsNotifier.loadAssociations(); + + },) + ).toList();}, + loading: () => const [Center(child: CircularProgressIndicator())], + error: (error, stack) => [const Center(child: Text(PhonebookTextConstants.errorLoadAssociationList))]) + ), + ]) + + ); } } diff --git a/lib/phonebook/ui/pages/admin_page/asso_ui.dart b/lib/phonebook/ui/pages/admin_page/asso_ui.dart deleted file mode 100644 index ef4e28c43..000000000 --- a/lib/phonebook/ui/pages/admin_page/asso_ui.dart +++ /dev/null @@ -1,165 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:heroicons/heroicons.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/providers/association_picture_provider.dart'; -import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/tools/constants.dart'; -import 'package:myecl/tools/ui/shrink_button.dart'; - -class AssoUi extends HookConsumerWidget { - final Association association; - final void Function() onEdit; - final Future Function() onDelete; - const AssoUi( - {super.key, - required this.association, - required this.onEdit, - required this.onDelete}); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final associationPicture = - ref.watch(associationPictureProvider); - return Container( - margin: const EdgeInsets.symmetric(vertical: 10), - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.2), - blurRadius: 5, - spreadRadius: 2) - ]), - child: Row( - children: [ - const SizedBox( - width: 10, - ), - associationPicture.when(data: (picture){ - return CircleAvatar( - radius: 80, - backgroundImage: picture.isEmpty ? - const AssetImage('assets/images/profile.png') : - Image.memory(picture).image, - ); - }, loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, error: (e, s) { - return const Center( - child: Text(PhonebookTextConstants.errorLoadAssociationPicture), - ); - }, - ), - Expanded( - child: Text( - association.name, - style: const TextStyle( - color: Colors.black, - fontSize: 20, - fontWeight: FontWeight.bold), - ), - ), - const SizedBox( - width: 10, - ), - Row( - children: [ - GestureDetector( - onTap: onEdit, - child: Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - Colors.grey.shade800, - Colors.grey.shade900, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - boxShadow: [ - BoxShadow( - color: Colors.grey.shade900.withOpacity(0.3), - spreadRadius: 2, - blurRadius: 4, - offset: const Offset(2, 3), - ), - ], - borderRadius: BorderRadius.circular(10), - ), - child: const HeroIcon( - HeroIcons.eye, - color: Colors.white, - ), - ), - ), - const SizedBox( - width: 10, - ), - ShrinkButton( - waitChild: Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.3), - spreadRadius: 2, - blurRadius: 4, - offset: const Offset(2, 3), - ), - ], - borderRadius: BorderRadius.circular(10), - ), - child: const Center( - child: CircularProgressIndicator( - color: Colors.white, - ), - ), - ), - onTap: onDelete, - child: Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.3), - spreadRadius: 2, - blurRadius: 4, - offset: const Offset(2, 3), - ), - ], - borderRadius: BorderRadius.circular(10), - ), - child: const HeroIcon( - HeroIcons.xMark, - color: Colors.white, - ), - )), - ], - ) - ], - ), - ); - } -} diff --git a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart index 1f5486e61..c41abc396 100644 --- a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart +++ b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart @@ -2,8 +2,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; +import 'package:myecl/phonebook/providers/filtered_association_list_provider.dart'; +import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/tools/token_expire_wrapper.dart'; class AssociationResearchBar extends HookConsumerWidget { const AssociationResearchBar({Key? key}) : super(key: key); @@ -12,8 +13,12 @@ class AssociationResearchBar extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final associationListNotifier = ref.watch(associationListProvider.notifier); + final filteredAssociationListNotifier = + ref.watch(filteredAssociationListProvider.notifier); final focusNode = useFocusNode(); final editingController = useTextEditingController(); + final filterNotifier = ref.watch(filterProvider.notifier); + return Container( decoration: BoxDecoration( border: Border.all(), @@ -30,8 +35,8 @@ class AssociationResearchBar extends HookConsumerWidget { ), width: 300, child: TextField( - onChanged: (value) { - associationListNotifier.setAssociationList(associationListNotifier.filterAssociations(value)); + onChanged: (value) async { + filterNotifier.setFilter(value); }, focusNode: focusNode, controller: editingController, diff --git a/lib/phonebook/ui/pages/admin_page/editable_association_card.dart b/lib/phonebook/ui/pages/admin_page/editable_association_card.dart new file mode 100644 index 000000000..cb140cd88 --- /dev/null +++ b/lib/phonebook/ui/pages/admin_page/editable_association_card.dart @@ -0,0 +1,85 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/providers/association_picture_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/phonebook/ui/delete_button.dart'; +import 'package:myecl/phonebook/ui/edition_button.dart'; + +class EditableAssociationCard extends HookConsumerWidget { + final Association association; + final void Function() onEdit; + final Future Function() onDelete; + const EditableAssociationCard( + {super.key, + required this.association, + required this.onEdit, + required this.onDelete}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final associationPicture = + ref.watch(associationPictureProvider); + return Container( + margin: const EdgeInsets.symmetric(vertical: 10), + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 5, + spreadRadius: 2) + ]), + child: Row( + children: [ + const SizedBox( + width: 10, + ), + associationPicture.when(data: (picture){ + return CircleAvatar( + radius: 80, + backgroundImage: picture.isEmpty ? + const AssetImage('assets/images/profile.png') : + Image.memory(picture).image, + ); + }, loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, error: (e, s) { + return const Center( + child: Text(PhonebookTextConstants.errorLoadAssociationPicture), + ); + }, + ), + const SizedBox(width: 10), + Text( + association.name, + style: const TextStyle( + color: Colors.black, + fontSize: 20, + fontWeight: FontWeight.bold), + ), + const Spacer(), + Text(association.kind, + style: const TextStyle( + color: Colors.black, + fontSize: 20, + fontWeight: FontWeight.bold)), + const Spacer(), + EditionButton(onEdition: () async { + onEdit(); + }), + const SizedBox(width: 10), + DeleteButton(onDelete: () async { + await onDelete(); + }), + + + ], + ), + ); + } +} diff --git a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart index d32641507..32b78e13d 100644 --- a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart +++ b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart @@ -3,10 +3,13 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/admin/tools/constants.dart'; import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/providers/association_kind_provider.dart'; +import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/phonebook/ui/pages/association_creation_page/kind_chip.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; @@ -24,10 +27,14 @@ class AssociationCreationPage extends HookConsumerWidget { final associationListNotifier = ref.watch(associationListProvider.notifier); final associations = ref.watch(associationListProvider); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); + final associationKinds = ref.watch(associationKindsProvider); + final kind = useState(''); + void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); } + return Padding( padding: const EdgeInsets.symmetric(horizontal: 30.0), child: SingleChildScrollView( @@ -37,8 +44,7 @@ class AssociationCreationPage extends HookConsumerWidget { child: Form( key: key, child: Column(children: [ - const Align( - alignment: Alignment.centerLeft, + const Center( child: Text(AdminTextConstants.addAssociation, style: TextStyle( fontSize: 20, @@ -48,6 +54,32 @@ class AssociationCreationPage extends HookConsumerWidget { const SizedBox( height: 30, ), + associationKinds.when( + data: (value) { + return SingleChildScrollView( + child: Row( + children: [ + const Spacer(), + ...value.kinds.map( + (e) => KindChip( + label: e, + selected: e == kind.value, + onTap: () async { + kind.value = e; + }, + )).toList(), + const Spacer(), + ] + ) + ); + }, + error: (error, stack) { + return const Text(PhonebookTextConstants.errorKindsLoading); + }, + loading: () { + return const CircularProgressIndicator(); + }, + ), Container( margin: const EdgeInsets.symmetric( vertical: 20, @@ -129,7 +161,9 @@ class AssociationCreationPage extends HookConsumerWidget { ), ), ], - )), + ) + ), + ShrinkButton( waitChild: Container( width: double.infinity, @@ -162,11 +196,20 @@ class AssociationCreationPage extends HookConsumerWidget { ), ), onTap: () async { + if (!key.currentState!.validate()) { + displayToastWithContext(TypeMsg.error, PhonebookTextConstants.emptyFieldError); + return; + } + if (kind.value == '') { + displayToastWithContext(TypeMsg.error, PhonebookTextConstants.emptyKindError); + return; + } await tokenExpireWrapper(ref, () async { final value = await associationListNotifier.createAssociation( Association.empty().copyWith( name: name.text, - description: description.text,)); + description: description.text, + kind: kind.value)); if (value) { displayToastWithContext( TypeMsg.msg, PhonebookTextConstants.addedAssociation); diff --git a/lib/phonebook/ui/pages/association_creation_page/kind_chip.dart b/lib/phonebook/ui/pages/association_creation_page/kind_chip.dart new file mode 100644 index 000000000..33f6ec04d --- /dev/null +++ b/lib/phonebook/ui/pages/association_creation_page/kind_chip.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; + +class KindChip extends StatelessWidget { + final bool selected; + final String label; + final Function() onTap; + const KindChip( + {super.key, + required this.label, + required this.selected, + required this.onTap}); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onTap, + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 10.0), + child: Chip( + label: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + label, + style: TextStyle( + color: selected ? Colors.white : Colors.black, + fontWeight: FontWeight.bold), + ), + ), + backgroundColor: selected ? Colors.black : Colors.grey.shade200, + )), + ); + } +} diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 744339b7b..82364cd82 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -1,27 +1,33 @@ import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:image_picker/image_picker.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; +import 'package:myecl/phonebook/providers/member_provider.dart'; +import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/tools/fake_class.dart'; -import 'package:myecl/phonebook/ui/edition_button.dart'; +import 'package:myecl/phonebook/ui/pages/association_creation_page/kind_chip.dart'; import 'package:myecl/phonebook/ui/pages/association_editor_page/member_editable_card.dart'; -import 'package:myecl/phonebook/ui/text_input_dialog.dart'; +import 'package:myecl/phonebook/ui/pages/association_editor_page/membership_dialog.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:myecl/tools/ui/refresher.dart'; +import 'package:myecl/tools/ui/shrink_button.dart'; class AssociationEditorPage extends HookConsumerWidget { const AssociationEditorPage({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { + final key = GlobalKey(); final association = ref.watch(associationProvider); final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); @@ -29,196 +35,306 @@ class AssociationEditorPage extends HookConsumerWidget { final associationPicture = ref.watch(associationPictureProvider); final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); - final controller = TextEditingController(); final associationListNotifier = ref.watch(associationListProvider.notifier); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); + final associationKinds = ref.watch(associationKindsProvider); + final kind = useState(association.kind); + final name = useTextEditingController(text: association.name); + final description = useTextEditingController(text: association.description); + final controller = TextEditingController(); + final member = ref.watch(memberProvider); + final memberRoleTags = ref.watch(memberRolesTagsProvider); void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); } - String text = ""; - if (association.id == "") { - text = "Ajouter une association"; - } else { - text = "Modifier une association"; - - } - - return Refresher( - onRefresh: () async { - await associationMemberListNotifier.loadMembers(association.id); - await associationPictureNotifier - .getAssociationPicture(association.id); - }, - child: Center( - child: Column(children: [ - Text(text, style: const TextStyle(fontSize: 30)), - const SizedBox(height: 10), - Row( - children: [ - Spacer(), - Text(association.name, style: const TextStyle(fontSize: 40)), - const SizedBox(width: 10), - EditionButton(onEdition: () async { - showDialog( - context: context, - builder: (BuildContext context) { - return TextInputDialog( - controller: controller, - title: association.name, - text: PhonebookTextConstants.editRoleName, - defaultText: association.name, - onConfirm: () async { - final done = await associationListNotifier - .updateAssociation(association.copyWith( - name: controller.text)); - if (done) { - displayToastWithContext( - TypeMsg.msg, - PhonebookTextConstants - .updatedAssociationName); - associationNotifier.setAssociation( - association.copyWith(name: controller.text)); - } else { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.updatingError); - } - }); - }); - }) - ], - ), - const SizedBox(height: 10), - Stack( - children: [ - Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - spreadRadius: 5, - blurRadius: 10, - offset: const Offset(2, 3), + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Refresher( + onRefresh: () async { + await associationMemberListNotifier.loadMembers(association.id); + await associationPictureNotifier + .getAssociationPicture(association.id); + }, + child: Column(children: [ + const Align( + alignment: Alignment.center, + child: Text(PhonebookTextConstants.edit, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w700, + color: ColorConstants.gradient1)), + ), + const SizedBox( + height: 20, + ), + Form( + key: key, + child: Column(children: [ + associationKinds.when( + data: (value) { + return SingleChildScrollView( + child: Row(children: [ + const Spacer(), + ...value.kinds + .map((e) => KindChip( + label: e, + selected: e == kind.value, + onTap: () async { + kind.value = e; + }, + )) + .toList(), + const Spacer(), + ])); + }, + error: (error, stack) { + return const Text( + PhonebookTextConstants.errorKindsLoading); + }, + loading: () { + return const CircularProgressIndicator(); + }, + ), + Container( + margin: const EdgeInsets.symmetric(vertical: 10), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + child: TextFormField( + controller: name, + cursorColor: ColorConstants.gradient1, + decoration: InputDecoration( + labelText: "Name", + labelStyle: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + suffixIcon: Container( + padding: const EdgeInsets.all(10), + child: const HeroIcon( + HeroIcons.pencil, + ), + ), + enabledBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: Colors.transparent, + ), + ), + focusedBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: ColorConstants.gradient1))), + validator: (value) { + if (value == null) { + return PhonebookTextConstants.emptyFieldError; + } else if (value.isEmpty) { + return PhonebookTextConstants.emptyFieldError; + } else { + return null; + } + }, + ), + ), + ], + )), + Container( + margin: const EdgeInsets.symmetric(vertical: 10), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + child: TextFormField( + controller: description, + cursorColor: ColorConstants.gradient1, + decoration: InputDecoration( + labelText: "Description", + labelStyle: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + suffixIcon: Container( + padding: const EdgeInsets.all(10), + child: const HeroIcon( + HeroIcons.pencil, + ), + ), + enabledBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: Colors.transparent, + ), + ), + focusedBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: ColorConstants.gradient1))), + validator: (value) { + if (value == null) { + return PhonebookTextConstants.emptyFieldError; + } else if (value.isEmpty) { + return PhonebookTextConstants.emptyFieldError; + } else { + return null; + } + }, + ), + ), + ], + )), + const SizedBox( + height: 20, + ), + ShrinkButton( + waitChild: Container( + width: double.infinity, + margin: const EdgeInsets.symmetric(vertical: 20), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), + ], + borderRadius: BorderRadius.circular(15), + ), + child: const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + color: Colors.white, + ), + ), ), - ], - ), - child: associationPicture.when( - data: (picture) { - return CircleAvatar( - radius: 120, - backgroundImage: picture.isEmpty - ? const AssetImage('assets/images/logo_alpha.png') - : Image.memory(picture).image, - ); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: Text(PhonebookTextConstants.errorLoadAssociationPicture), - ); - }, - ), - ), - Positioned( - bottom: 0, - child: GestureDetector( onTap: () async { - final value = - await associationPictureNotifier.setAssociationPicture( - ImageSource.gallery, association.id); - if (value != null) { + if (!key.currentState!.validate()) { + return; + } + if (kind.value == '') { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.emptyKindError); + return; + } + await tokenExpireWrapper(ref, () async { + final value = await associationListNotifier + .updateAssociation(association.copyWith( + name: name.text, + description: description.text, + kind: kind.value)); if (value) { displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.updatedAssociationPicture); + PhonebookTextConstants.updatedAssociation); } else { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.tooHeavyAssociationPicture); + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.updatingError); } - } else { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.errorAssociationPicture); - } + }); }, child: Container( - padding: const EdgeInsets.all(7), + width: double.infinity, + margin: const EdgeInsets.symmetric(vertical: 20), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, decoration: BoxDecoration( - shape: BoxShape.circle, gradient: const LinearGradient( colors: [ ColorConstants.gradient1, ColorConstants.gradient2, ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, ), boxShadow: [ BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.3), + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), spreadRadius: 2, - blurRadius: 4, - offset: const Offset(2, 3), ), ], + borderRadius: BorderRadius.circular(15), ), - child: const HeroIcon( - HeroIcons.photo, - color: Colors.white, + child: const Text( + PhonebookTextConstants.edit, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), + ), ), ), ), + ])), + const SizedBox(height: 20), + Row( + children: [ + const Text(PhonebookTextConstants.members), + const Spacer(), + ShrinkButton( + onTap: () async { + await tokenExpireWrapper(ref, () async { + showDialog( + context: context, + builder: (BuildContext context) { + return MembershipDialog( + apparentNameController: controller, + title: PhonebookTextConstants.addMember, + defaultText: "", + onConfirm: () async { + final value = await associationNotifier + .addMember(association, member, memberRoleTags, controller.text); + if (value) { + associationMemberListNotifier + .loadMembers(association.id); + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.addedMember); + } else { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.addingError); + } + }); + }); + + }); + }, + child: Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: ColorConstants.gradient1, + borderRadius: BorderRadius.circular(10), + ), + child: const Icon( + Icons.add, + color: Colors.white, + ), + ), ), - ]),] + associationMemberList.when( - data: (members) { - return members - .map((member) => MemberEditableCard(member: member)) - .toList(); - }, - loading: () { - return [const Center( - child: CircularProgressIndicator(), - )]; - }, - error: (e, s) { - return [const Center( - child: - Text(PhonebookTextConstants.errorLoadAssociationMember))]; - }, - ) + [Row(children: [ - GestureDetector( - child: Container( - margin: const EdgeInsets.all(10), - width: MediaQuery.of(context).size.width / 2.3, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(50), color: Colors.red), - child: const Center( - child: Text(PhonebookTextConstants.cancel, - style: TextStyle(fontSize: 20))), - ), - onTap: () { - //to complete - }, + ], ), - GestureDetector( - child: Container( - margin: const EdgeInsets.all(10), - width: MediaQuery.of(context).size.width / 2.3, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(50), color: Colors.red), - child: const Center( - child: Text(PhonebookTextConstants.validation, - style: TextStyle(fontSize: 20))), - ), - onTap: () { - //to complete + ...associationMemberList.when( + data: (data) { + return data + .map((member) => MemberEditableCard(member: member)).toList(); + }, + error: (error, stackTrace) { + return const [Text(PhonebookTextConstants.errorLoadAssociationMember),]; }, - ) - ]),] - ))); + loading: () => [ + const Center( + child: CircularProgressIndicator(), + ), + ],) + ]), + )); } } diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index cd652a3bd..27cae2385 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -2,8 +2,16 @@ import 'package:flutter/material.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/member.dart'; import 'package:myecl/phonebook/class/membership.dart'; +import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; +import 'package:myecl/phonebook/ui/delete_button.dart'; +import 'package:myecl/phonebook/ui/edition_button.dart'; +import 'package:myecl/phonebook/ui/pages/association_editor_page/membership_dialog.dart'; +import 'package:myecl/phonebook/ui/text_input_dialog.dart'; +import 'package:myecl/tools/functions.dart'; import 'package:myecl/user/providers/profile_picture_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; @@ -19,7 +27,16 @@ class MemberEditableCard extends HookConsumerWidget { final profilePicture = ref.watch(profilePictureProvider); final association = ref.watch(associationProvider); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); - + final controller = TextEditingController(); + final associationMembersNotifier = + ref.watch(associationMemberListProvider.notifier); + final memberRoleTags = ref.watch(memberRolesTagsProvider); + + void displayToastWithContext(TypeMsg type, String msg) { + displayToast(context, type, msg); + } + + return Container( margin: const EdgeInsets.all(10), padding: const EdgeInsets.all(10), @@ -87,65 +104,47 @@ class MemberEditableCard extends HookConsumerWidget { ], ), ), - SizedBox( - width: 200, - child: Center( - child : Row( - children: member.memberships.where((element) => element.association.id == association.id).map((e) => - Text( - e.apparentName, - style: const TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - ), - )).toList() - ) - ) - ), - const SizedBox(width: 10), - GestureDetector( - onTap: (){}, - child: Container( - width: 40, - height: 40, - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.grey.shade200, - borderRadius: BorderRadius.circular(30), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.2), - blurRadius: 10, - offset: const Offset(2, 3)) - ], - ), - child: const HeroIcon(HeroIcons.pencil, - color: Colors.black), - ), - ), + const Spacer(), + Text(member.memberships.firstWhere((element) => element.association.id == association.id).apparentName, + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + )), + const Spacer(), + EditionButton(onEdition: () async { + showDialog( + context: context, + builder: (BuildContext context) { + return MembershipDialog( + apparentNameController: controller, + title: PhonebookTextConstants.editMembership, + defaultText: member.memberships.firstWhere((element) => element.association.id == association.id).apparentName, + onConfirm: () async { + final result = await associationNotifier.updateMember( + association, + member.toMember(), + memberRoleTags, + controller.text); + if (result) { + await associationMembersNotifier.loadMembers(association.id); + displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.updatedMember); + } else { + displayToastWithContext(TypeMsg.error, PhonebookTextConstants.updatingError); + } + }); + }); + }), const SizedBox(width: 10), - GestureDetector( - onTap: (){ - associationNotifier.deleteMember(association ,member, ); - }, - child: Container( - width: 40, - height: 40, - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.grey.shade200, - borderRadius: BorderRadius.circular(30), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.2), - blurRadius: 10, - offset: const Offset(2, 3)) - ], - ), - child: const HeroIcon(HeroIcons.trash, - color: Colors.black), - ), - ), + DeleteButton(onDelete: + () async { + final result = await associationNotifier.deleteMember(association, member); + await associationMembersNotifier.loadMembers(association.id); + if (result) { + displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.deletedMember); + } else { + displayToastWithContext(TypeMsg.error, PhonebookTextConstants.deletingError); + } + },) ], )); } diff --git a/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart b/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart new file mode 100644 index 000000000..ed603310c --- /dev/null +++ b/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart @@ -0,0 +1,136 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; +import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/phonebook/ui/pages/association_editor_page/search_result.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; +import 'package:myecl/user/providers/user_list_provider.dart'; + +class MembershipDialog extends HookConsumerWidget{ + const MembershipDialog({ + Key? key, + required this.apparentNameController, + required this.title, + required this.defaultText, + required this.onConfirm, + }) : super(key: key); + + final String title; + final String defaultText; + final VoidCallback onConfirm; + final TextEditingController apparentNameController; + + String nameConstructor (List names, List checked) { + String name = ''; + for (int i = 0; i < names.length; i++) { + if (checked[i]) { + name ="$name, ${names[i]}"; + } + } + return name.substring(1, name.length); + } + + @override + Widget build(BuildContext context, WidgetRef ref) { + final rolesTags = ref.watch(rolesTagsProvider); + final apparentName = useState(defaultText); + final queryController = + useTextEditingController(text: ''); + final usersNotifier = ref.watch(userList.notifier); + final memberRoleTagsNotifier = ref.watch(memberRolesTagsProvider.notifier); + + List checked = []; + apparentNameController.text = apparentName.value; + return AlertDialog( + title: Center( + child: Container( + decoration: const BoxDecoration( + border: Border(bottom: BorderSide(color: Colors.black)), + color: Colors.white, + ), + child: Text(title, style: const TextStyle(fontSize: 20)) + ) + ), + content: SizedBox( + height: 400, + child: Column( + children: [ + const SizedBox(height: 25), + const Text(PhonebookTextConstants.member), + const SizedBox(height: 5), + TextFormField( + onChanged: (value) { + tokenExpireWrapper(ref, () async { + if (queryController.text.isNotEmpty) { + await usersNotifier.filterUsers(queryController.text); + } else { + usersNotifier.clear(); + } + }); + }, + cursorColor: Colors.black, + controller: queryController, + decoration: const InputDecoration( + labelText: PhonebookTextConstants.member, + floatingLabelStyle: TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + ), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.black, width: 2.0), + ), + ), + ), + const SizedBox( + height: 10, + ), + SearchResult(queryController: queryController), + ...rolesTags.when( + data: (data) { + checked = List.filled(data.tags.length, false); + return data.tags.map((e) => Row( + children: [ + Text(e), + const Spacer(), + Checkbox( + value: false, + fillColor: MaterialStateProperty.all(Colors.black), + onChanged: (value) { + checked[data.tags.indexOf(e)] = value!; + debugPrint(checked.toString()); + apparentName.value = nameConstructor(data.tags, checked); + apparentNameController.text = apparentName.value; + memberRoleTagsNotifier.setRoleTagsWithFilter(data.tags, checked); + }, + )])).toList(); + }, + error: (e,s) => [const Text('Error')], + loading: () => [const Text('Loading')],), + const SizedBox(height: 5), + const Text(PhonebookTextConstants.apparentName), + TextField( + controller: apparentNameController, + ) + + ], + )), + actions: [ + TextButton( + onPressed: (){ + Navigator.of(context).pop(); + }, + child: const Text(PhonebookTextConstants.cancel), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + onConfirm(); + }, + child: const Text(PhonebookTextConstants.validation), + ), + ], + ); + } +} \ No newline at end of file diff --git a/lib/phonebook/ui/pages/association_editor_page/search_result.dart b/lib/phonebook/ui/pages/association_editor_page/search_result.dart new file mode 100644 index 000000000..dfb04f004 --- /dev/null +++ b/lib/phonebook/ui/pages/association_editor_page/search_result.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/member.dart'; +import 'package:myecl/phonebook/providers/member_provider.dart'; +import 'package:myecl/user/providers/user_list_provider.dart'; + +class SearchResult extends HookConsumerWidget { + final TextEditingController queryController; + const SearchResult( + {super.key, required this.queryController}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final users = ref.watch(userList); + final usersNotifier = ref.watch(userList.notifier); + final memberNotifier = ref.watch(memberProvider.notifier); + + return users.when( + data: (u) { + return Column( + children: u + .map((e) => GestureDetector( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + width: 20, + ), + Expanded( + child: Text( + e.getName(), + style: const TextStyle( + fontSize: 13, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ]), + ), + onTap: () { + memberNotifier.setMember(Member.fromUser(e)); + queryController.text = e.getName(); + usersNotifier.clear(); + })) + .toList()); + }, + loading: () => const Center(child: CircularProgressIndicator()), + error: (e, s) => Text(e.toString())); + } +} diff --git a/lib/phonebook/ui/pages/association_page/member_card.dart b/lib/phonebook/ui/pages/association_page/member_card.dart index d1bc16f68..67a5e186e 100644 --- a/lib/phonebook/ui/pages/association_page/member_card.dart +++ b/lib/phonebook/ui/pages/association_page/member_card.dart @@ -74,7 +74,6 @@ class MemberCard extends HookConsumerWidget { ), const SizedBox(width: 10), SizedBox( - width: 200, child: Column( children: [ Text( @@ -95,18 +94,13 @@ class MemberCard extends HookConsumerWidget { ], ), ), - SizedBox( - width: 100, - child: Center( - child: Text( - member.memberships.firstWhere((element) => element.association.id == association.id).apparentName, - style: const TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - ), - ), - ) - ) + const Spacer(), + Text(member.memberships.firstWhere((element) => element.association.id == association.id).apparentName, + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + )), + const Spacer(), ], ))); } diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index a2fbee4c5..bbeb08ebf 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -1,12 +1,15 @@ import 'package:flutter/material.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/providers/filtered_association_list_provider.dart'; +import 'package:myecl/phonebook/providers/research_filter_provider.dart'; +import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/admin/providers/is_admin.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; -import 'package:myecl/phonebook/tools/fake_class.dart'; import 'package:myecl/phonebook/ui/association_card.dart'; import 'package:myecl/phonebook/ui/pages/main_page/research_bar.dart'; import 'package:myecl/tools/ui/refresher.dart'; @@ -15,59 +18,45 @@ class MainPage extends HookConsumerWidget { const MainPage({Key? key}) : super(key: key); @override - Widget build(BuildContext context, WidgetRef ref) { + Widget build(BuildContext context, WidgetRef ref) { final isAdmin = ref.watch(isAdminProvider); final pageNotifier = ref.watch(phonebookPageProvider.notifier); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationListNotifier = ref.watch(associationListProvider.notifier); + final filteredAssociationList = ref.watch(filteredAssociationListProvider); + final filterNotifier = ref.watch(filterProvider.notifier); + final filteredAssociationListNotifier = ref.watch(filteredAssociationListProvider.notifier); final associationList = ref.watch(associationListProvider); + final associationKindsNotifier = ref.watch(associationKindsProvider.notifier); + final rolesTagsNotifier = ref.watch(rolesTagsProvider.notifier); + return Stack( children: [ Refresher( onRefresh: () async { + await rolesTagsNotifier.loadRolesTags(); + await associationKindsNotifier.loadAssociationKinds(); await associationListNotifier.loadAssociations(); + await filteredAssociationListNotifier.loadAssociations(); }, child: Column( children: [ const SizedBox(height: 70), const ResearchBar(), - const SizedBox(width: 10), - SingleChildScrollView( - scrollDirection: Axis.vertical, - physics: const BouncingScrollPhysics(), - child: associationList.when( - data: (data) { - return Column( - children: data.map((association) { - return AssociationCard(association: association, onClicked: () { - associationNotifier.setAssociation(association); - pageNotifier.setPhonebookPage(PhonebookPage.associationPage); - },); - }).toList(), - ); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - // return Column( - // children: fakeAssociations.map((association) { - // return AssociationCard(association: association, onClicked: () { - // associationNotifier.setAssociation(association); - // pageNotifier.setPhonebookPage(PhonebookPage.associationPage); - // },); - // }).toList(), - // ); - - return const Center( - child: Text(PhonebookTextConstants.errorLoadAssociationList), - ); - }, - )) - ], - )), + const SizedBox(width: 10),] + + associationList.when( + data: (associations) { + return associations.map((association) => AssociationCard( + association: association, + onClicked: () { + associationNotifier.setAssociation(association); + pageNotifier.setPhonebookPage(PhonebookPage.associationPage); + },) + ).toList();}, + loading: () => const [Center(child: CircularProgressIndicator())], + error: (error, stack) => [const Center(child: Text(PhonebookTextConstants.errorLoadAssociationList))] + ) + )), if (isAdmin) Positioned( top: 15, diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart index 2e56887cb..5a92e41c7 100644 --- a/lib/phonebook/ui/pages/main_page/research_bar.dart +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; +import 'package:myecl/phonebook/providers/filtered_association_list_provider.dart'; +import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; @@ -12,8 +14,12 @@ class ResearchBar extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final associationListNotifier = ref.watch(associationListProvider.notifier); + final filteredAssociationListNotifier = + ref.watch(filteredAssociationListProvider.notifier); final focusNode = useFocusNode(); final editingController = useTextEditingController(); + final filterNotifier = ref.watch(filterProvider.notifier); + return Container( decoration: BoxDecoration( border: Border.all(), @@ -31,7 +37,7 @@ class ResearchBar extends HookConsumerWidget { width: 300, child: TextField( onChanged: (value) { - associationListNotifier.setAssociationList(associationListNotifier.filterAssociations(value)); + filterNotifier.setFilter(value); }, focusNode: focusNode, controller: editingController, From 3be3b61f537204ee7ec4cf6cda0a6d2d1e8f336d Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:00 +0100 Subject: [PATCH 010/123] fix membership modification checkboxes --- lib/phonebook/class/member.dart | 6 +++++ lib/phonebook/providers/member_provider.dart | 5 ---- .../providers/member_role_tags_provider.dart | 14 ++++++++--- .../providers/roles_tags_provider.dart | 14 ++++++++--- .../repositories/role_tags_repository.dart | 8 +++--- .../association_editor_page.dart | 1 + .../membership_dialog.dart | 25 +++++++++++-------- .../search_result.dart | 4 +++ 8 files changed, 51 insertions(+), 26 deletions(-) diff --git a/lib/phonebook/class/member.dart b/lib/phonebook/class/member.dart index 2da43b3e9..f583d0e0b 100644 --- a/lib/phonebook/class/member.dart +++ b/lib/phonebook/class/member.dart @@ -1,3 +1,4 @@ +import 'package:flutter/material.dart'; import 'package:myecl/user/class/list_users.dart'; class Member{ @@ -65,4 +66,9 @@ class Member{ id = user.id; email = ""; } + + @override + String toString() { + return 'Member(name: $name, firstname: $firstname, nickname: $nickname, id: $id, email: $email)'; + } } \ No newline at end of file diff --git a/lib/phonebook/providers/member_provider.dart b/lib/phonebook/providers/member_provider.dart index dc499e6ed..71311c3bf 100644 --- a/lib/phonebook/providers/member_provider.dart +++ b/lib/phonebook/providers/member_provider.dart @@ -1,6 +1,5 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/phonebook/class/member.dart'; -import 'package:myecl/phonebook/repositories/member_repository.dart'; final memberProvider = StateNotifierProvider((ref) { @@ -13,8 +12,4 @@ class MemberProvider extends StateNotifier { void setMember(Member i) { state = i; } - - void getMember(String id) async { - state = await MemberRepository().getMember(id); - } } \ No newline at end of file diff --git a/lib/phonebook/providers/member_role_tags_provider.dart b/lib/phonebook/providers/member_role_tags_provider.dart index 9bdcf51b1..7fbaf8a20 100644 --- a/lib/phonebook/providers/member_role_tags_provider.dart +++ b/lib/phonebook/providers/member_role_tags_provider.dart @@ -1,4 +1,7 @@ +import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/phonebook/class/roles_tags.dart'; +import 'package:tuple/tuple.dart'; final memberRolesTagsProvider = StateNotifierProvider>((ref) { @@ -8,13 +11,16 @@ final memberRolesTagsProvider = StateNotifierProvider> { MemberRolesTagsProvider() : super([]); - void setRoleTagsWithFilter(List i, List filter) { + void setRoleTagsWithFilter(Tuple2> data) { + debugPrint(data.item1.tags.toString()); + debugPrint(data.item2.toString()); List newRoleTags = []; - for (int i = 0; i < filter.length; i++) { - if (filter[i]) { - newRoleTags.add(state[i]); + for (int i = 0; i < data.item2.length; i++) { + if (data.item2[i]) { + newRoleTags.add(data.item1.tags[i]); } } state = newRoleTags; + debugPrint(state.toString()); } } \ No newline at end of file diff --git a/lib/phonebook/providers/roles_tags_provider.dart b/lib/phonebook/providers/roles_tags_provider.dart index f3e59cb82..08d1d7ca7 100644 --- a/lib/phonebook/providers/roles_tags_provider.dart +++ b/lib/phonebook/providers/roles_tags_provider.dart @@ -4,9 +4,10 @@ import 'package:myecl/phonebook/class/roles_tags.dart'; import 'package:myecl/phonebook/repositories/role_tags_repository.dart'; import 'package:myecl/tools/providers/single_notifier.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; +import 'package:tuple/tuple.dart'; -class RolesTagsNotifier extends SingleNotifier { +class RolesTagsNotifier extends SingleNotifier>> { final RolesTagsRepository rolesTagsRepository = RolesTagsRepository(); RolesTagsNotifier({required String token}) : super(const AsyncValue.loading()) { @@ -14,15 +15,20 @@ class RolesTagsNotifier extends SingleNotifier { } void setRole(RolesTags i) { - state = AsyncValue.data(i); + state = AsyncValue.data(Tuple2(i, state.value!.item2)); } - Future> loadRolesTags() async { + Future>>> loadRolesTags() async { return await load(() async => rolesTagsRepository.getRolesTags()); } + + void resetChecked() { + final checked = state.value!.item2; + state = AsyncValue.data(Tuple2(state.value!.item1, List.filled(checked.length, false))); + } } -final rolesTagsProvider = StateNotifierProvider>((ref) { +final rolesTagsProvider = StateNotifierProvider>>>((ref) { final token = ref.watch(tokenProvider); RolesTagsNotifier notifier = RolesTagsNotifier(token: token); tokenExpireWrapperAuth(ref, () async { diff --git a/lib/phonebook/repositories/role_tags_repository.dart b/lib/phonebook/repositories/role_tags_repository.dart index 6a1214899..a7ab8201d 100644 --- a/lib/phonebook/repositories/role_tags_repository.dart +++ b/lib/phonebook/repositories/role_tags_repository.dart @@ -1,15 +1,17 @@ import 'package:myecl/phonebook/class/roles_tags.dart'; import 'package:myecl/phonebook/tools/fake_class.dart'; import 'package:myecl/tools/repository/repository.dart'; +import 'package:tuple/tuple.dart'; class RolesTagsRepository extends Repository { @override // ignore: overridden_fields final ext = "phonebook/"; - Future getRolesTags() async { - return fakeRolesTags; - // return RolesTags.fromJSON(await getOne("rolesTags")); + Future>> getRolesTags() async { + return Tuple2(fakeRolesTags,List.filled(fakeRolesTags.tags.length, false)); + // RolesTags rolesTags = RolesTags.fromJSON(await getOne("rolesTags")); + // return Tuple2(rolesTags,List.filled(rolesTags.tags.length, false)); } } diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 82364cd82..c85043755 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -290,6 +290,7 @@ class AssociationEditorPage extends HookConsumerWidget { title: PhonebookTextConstants.addMember, defaultText: "", onConfirm: () async { + debugPrint("assciation: $association,\n member: ${member.toString()},\n memberRoleTags: $memberRoleTags,\n controller: ${controller.text}"); final value = await associationNotifier .addMember(association, member, memberRoleTags, controller.text); if (value) { diff --git a/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart b/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart index ed603310c..b8f8d9dc5 100644 --- a/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart +++ b/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart @@ -1,12 +1,14 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/roles_tags.dart'; import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/pages/association_editor_page/search_result.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:myecl/user/providers/user_list_provider.dart'; +import 'package:tuple/tuple.dart'; class MembershipDialog extends HookConsumerWidget{ const MembershipDialog({ @@ -22,13 +24,14 @@ class MembershipDialog extends HookConsumerWidget{ final VoidCallback onConfirm; final TextEditingController apparentNameController; - String nameConstructor (List names, List checked) { + String nameConstructor (Tuple2> data) { String name = ''; - for (int i = 0; i < names.length; i++) { - if (checked[i]) { - name ="$name, ${names[i]}"; + for (int i = 0; i < data.item2.length; i++) { + if (data.item2[i]) { + name ="$name, ${data.item1.tags[i]}"; } } + if (name == "") {return "";}; return name.substring(1, name.length); } @@ -40,6 +43,7 @@ class MembershipDialog extends HookConsumerWidget{ useTextEditingController(text: ''); final usersNotifier = ref.watch(userList.notifier); final memberRoleTagsNotifier = ref.watch(memberRolesTagsProvider.notifier); + final rolesTagsNotifier = ref.watch(rolesTagsProvider.notifier); List checked = []; apparentNameController.text = apparentName.value; @@ -89,20 +93,20 @@ class MembershipDialog extends HookConsumerWidget{ SearchResult(queryController: queryController), ...rolesTags.when( data: (data) { - checked = List.filled(data.tags.length, false); - return data.tags.map((e) => Row( + return data.item1.tags.map((e) => Row( children: [ Text(e), const Spacer(), Checkbox( - value: false, + value: data.item2[data.item1.tags.indexOf(e)], fillColor: MaterialStateProperty.all(Colors.black), onChanged: (value) { - checked[data.tags.indexOf(e)] = value!; + checked = data.item2; + checked[data.item1.tags.indexOf(e)] = value!; debugPrint(checked.toString()); - apparentName.value = nameConstructor(data.tags, checked); + apparentName.value = nameConstructor(data); apparentNameController.text = apparentName.value; - memberRoleTagsNotifier.setRoleTagsWithFilter(data.tags, checked); + memberRoleTagsNotifier.setRoleTagsWithFilter(data); }, )])).toList(); }, @@ -127,6 +131,7 @@ class MembershipDialog extends HookConsumerWidget{ onPressed: () { Navigator.of(context).pop(); onConfirm(); + rolesTagsNotifier.resetChecked(); }, child: const Text(PhonebookTextConstants.validation), ), diff --git a/lib/phonebook/ui/pages/association_editor_page/search_result.dart b/lib/phonebook/ui/pages/association_editor_page/search_result.dart index dfb04f004..eebc4aaa6 100644 --- a/lib/phonebook/ui/pages/association_editor_page/search_result.dart +++ b/lib/phonebook/ui/pages/association_editor_page/search_result.dart @@ -14,6 +14,7 @@ class SearchResult extends HookConsumerWidget { final users = ref.watch(userList); final usersNotifier = ref.watch(userList.notifier); final memberNotifier = ref.watch(memberProvider.notifier); + final member = ref.watch(memberProvider); return users.when( data: (u) { @@ -40,7 +41,10 @@ class SearchResult extends HookConsumerWidget { ]), ), onTap: () { + debugPrint(e.toString()); + debugPrint(Member.fromUser(e).toString()); memberNotifier.setMember(Member.fromUser(e)); + debugPrint(member.toString()); queryController.text = e.getName(); usersNotifier.clear(); })) From 2938c5351329f3c49ae6b0bfd6c2bd87ba5e1307 Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:00 +0100 Subject: [PATCH 011/123] Updating association editing page --- lib/phonebook/class/member.dart | 1 - .../providers/association_kinds_provider.dart | 1 - .../providers/association_list_provider.dart | 2 - .../association_editor_page.dart | 546 +++++++++--------- .../member_editable_card.dart | 224 +++---- .../membership_dialog.dart | 184 +++--- 6 files changed, 494 insertions(+), 464 deletions(-) diff --git a/lib/phonebook/class/member.dart b/lib/phonebook/class/member.dart index f583d0e0b..7c7839791 100644 --- a/lib/phonebook/class/member.dart +++ b/lib/phonebook/class/member.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:myecl/user/class/list_users.dart'; class Member{ diff --git a/lib/phonebook/providers/association_kinds_provider.dart b/lib/phonebook/providers/association_kinds_provider.dart index cef7cd6c6..7a7c597c2 100644 --- a/lib/phonebook/providers/association_kinds_provider.dart +++ b/lib/phonebook/providers/association_kinds_provider.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/association_kinds.dart'; diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index e6f5e72bb..6b6cb7776 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -1,7 +1,5 @@ -import 'package:flutter/rendering.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/repositories/association_repository.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/tools/providers/list_notifier.dart'; diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index c85043755..7a53b03fe 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -49,293 +49,313 @@ class AssociationEditorPage extends HookConsumerWidget { displayToast(context, type, msg); } - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Refresher( - onRefresh: () async { - await associationMemberListNotifier.loadMembers(association.id); - await associationPictureNotifier - .getAssociationPicture(association.id); - }, - child: Column(children: [ - const Align( - alignment: Alignment.center, - child: Text(PhonebookTextConstants.edit, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.w700, - color: ColorConstants.gradient1)), - ), - const SizedBox( - height: 20, - ), - Form( - key: key, - child: Column(children: [ - associationKinds.when( - data: (value) { - return SingleChildScrollView( - child: Row(children: [ - const Spacer(), - ...value.kinds - .map((e) => KindChip( - label: e, - selected: e == kind.value, - onTap: () async { - kind.value = e; - }, - )) - .toList(), - const Spacer(), - ])); - }, - error: (error, stack) { - return const Text( - PhonebookTextConstants.errorKindsLoading); - }, - loading: () { - return const CircularProgressIndicator(); - }, - ), - Container( - margin: const EdgeInsets.symmetric(vertical: 10), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - child: TextFormField( - controller: name, - cursorColor: ColorConstants.gradient1, - decoration: InputDecoration( - labelText: "Name", - labelStyle: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - suffixIcon: Container( - padding: const EdgeInsets.all(10), - child: const HeroIcon( - HeroIcons.pencil, + return Refresher( + onRefresh: () async { + await associationMemberListNotifier.loadMembers(association.id); + await associationPictureNotifier.getAssociationPicture(association.id); + }, + child: Column(children: [ + const SizedBox( + height: 20, + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 30), + alignment: Alignment.centerLeft, + child: const Text(PhonebookTextConstants.edit, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w700, + color: ColorConstants.gradient1)), + ), + const SizedBox( + height: 20, + ), + Form( + key: key, + child: Column(children: [ + associationKinds.when( + data: (value) { + return SingleChildScrollView( + physics: const BouncingScrollPhysics(), + scrollDirection: Axis.horizontal, + child: Row( + children: value.kinds + .map((e) => KindChip( + label: e, + selected: e == kind.value, + onTap: () async { + kind.value = e; + }, + )) + .toList())); + }, + error: (error, stack) { + return const Text(PhonebookTextConstants.errorKindsLoading); + }, + loading: () { + return const CircularProgressIndicator(); + }, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: Column( + children: [ + Container( + margin: const EdgeInsets.symmetric(vertical: 10), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + child: TextFormField( + controller: name, + cursorColor: ColorConstants.gradient1, + decoration: InputDecoration( + labelText: "Name", + labelStyle: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, ), - ), - enabledBorder: const UnderlineInputBorder( - borderSide: BorderSide( - color: Colors.transparent, + suffixIcon: Container( + padding: const EdgeInsets.all(10), + child: const HeroIcon( + HeroIcons.pencil, + ), ), - ), - focusedBorder: const UnderlineInputBorder( + enabledBorder: const UnderlineInputBorder( borderSide: BorderSide( - color: ColorConstants.gradient1))), - validator: (value) { - if (value == null) { - return PhonebookTextConstants.emptyFieldError; - } else if (value.isEmpty) { - return PhonebookTextConstants.emptyFieldError; - } else { - return null; - } - }, + color: Colors.transparent, + ), + ), + focusedBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: ColorConstants.gradient1))), + validator: (value) { + if (value == null) { + return PhonebookTextConstants + .emptyFieldError; + } else if (value.isEmpty) { + return PhonebookTextConstants + .emptyFieldError; + } else { + return null; + } + }, + ), ), - ), - ], - )), - Container( - margin: const EdgeInsets.symmetric(vertical: 10), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - child: TextFormField( - controller: description, - cursorColor: ColorConstants.gradient1, - decoration: InputDecoration( - labelText: "Description", - labelStyle: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - suffixIcon: Container( - padding: const EdgeInsets.all(10), - child: const HeroIcon( - HeroIcons.pencil, + ], + )), + Container( + margin: const EdgeInsets.symmetric(vertical: 10), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + child: TextFormField( + controller: description, + cursorColor: ColorConstants.gradient1, + decoration: InputDecoration( + labelText: "Description", + labelStyle: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, ), - ), - enabledBorder: const UnderlineInputBorder( - borderSide: BorderSide( - color: Colors.transparent, + suffixIcon: Container( + padding: const EdgeInsets.all(10), + child: const HeroIcon( + HeroIcons.pencil, + ), ), - ), - focusedBorder: const UnderlineInputBorder( + enabledBorder: const UnderlineInputBorder( borderSide: BorderSide( - color: ColorConstants.gradient1))), - validator: (value) { - if (value == null) { - return PhonebookTextConstants.emptyFieldError; - } else if (value.isEmpty) { - return PhonebookTextConstants.emptyFieldError; - } else { - return null; - } - }, + color: Colors.transparent, + ), + ), + focusedBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: ColorConstants.gradient1))), + validator: (value) { + if (value == null) { + return PhonebookTextConstants + .emptyFieldError; + } else if (value.isEmpty) { + return PhonebookTextConstants + .emptyFieldError; + } else { + return null; + } + }, + ), ), + ], + )), + ShrinkButton( + waitChild: Container( + width: double.infinity, + margin: const EdgeInsets.symmetric(vertical: 20), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], ), - ], - )), - const SizedBox( - height: 20, - ), - ShrinkButton( - waitChild: Container( - width: double.infinity, - margin: const EdgeInsets.symmetric(vertical: 20), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), ], + borderRadius: BorderRadius.circular(15), ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, + child: const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + color: Colors.white, ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: const SizedBox( - height: 20, - width: 20, - child: CircularProgressIndicator( - color: Colors.white, ), ), - ), - onTap: () async { - if (!key.currentState!.validate()) { - return; - } - if (kind.value == '') { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.emptyKindError); - return; - } - await tokenExpireWrapper(ref, () async { - final value = await associationListNotifier - .updateAssociation(association.copyWith( - name: name.text, - description: description.text, - kind: kind.value)); - if (value) { - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.updatedAssociation); - } else { - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.updatingError); + onTap: () async { + if (!key.currentState!.validate()) { + return; } - }); - }, - child: Container( - width: double.infinity, - margin: const EdgeInsets.symmetric(vertical: 20), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, + if (kind.value == '') { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.emptyKindError); + return; + } + await tokenExpireWrapper(ref, () async { + final value = await associationListNotifier + .updateAssociation(association.copyWith( + name: name.text, + description: description.text, + kind: kind.value)); + if (value) { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.updatedAssociation); + } else { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.updatingError); + } + }); + }, + child: Container( + width: double.infinity, + margin: const EdgeInsets.symmetric(vertical: 20), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), ], + borderRadius: BorderRadius.circular(15), ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, + child: const Text( + PhonebookTextConstants.edit, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: const Text( - PhonebookTextConstants.edit, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color.fromARGB(255, 255, 255, 255), ), ), - ), - ), - ])), - const SizedBox(height: 20), - Row( - children: [ - const Text(PhonebookTextConstants.members), - const Spacer(), - ShrinkButton( - onTap: () async { - await tokenExpireWrapper(ref, () async { - showDialog( + ) + ], + ), + ) + ])), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: Row( + children: [ + const Text(PhonebookTextConstants.members), + const Spacer(), + ShrinkButton( + onTap: () async { + await tokenExpireWrapper(ref, () async { + showDialog( context: context, builder: (BuildContext context) { - return MembershipDialog( - apparentNameController: controller, - title: PhonebookTextConstants.addMember, - defaultText: "", - onConfirm: () async { - debugPrint("assciation: $association,\n member: ${member.toString()},\n memberRoleTags: $memberRoleTags,\n controller: ${controller.text}"); - final value = await associationNotifier - .addMember(association, member, memberRoleTags, controller.text); - if (value) { - associationMemberListNotifier - .loadMembers(association.id); - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.addedMember); - } else { - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.addingError); - } - }); - }); - - }); - }, - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: ColorConstants.gradient1, - borderRadius: BorderRadius.circular(10), - ), - child: const Icon( - Icons.add, - color: Colors.white, - ), + return MembershipDialog( + apparentNameController: controller, + title: PhonebookTextConstants.addMember, + defaultText: "", + onConfirm: () async { + debugPrint( + "assciation: $association,\n member: ${member.toString()},\n memberRoleTags: $memberRoleTags,\n controller: ${controller.text}"); + final value = + await associationNotifier.addMember( + association, + member, + memberRoleTags, + controller.text); + if (value) { + associationMemberListNotifier + .loadMembers(association.id); + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.addedMember); + } else { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.addingError); + } + }); + }); + }); + }, + child: Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: ColorConstants.gradient1, + borderRadius: BorderRadius.circular(10), + ), + child: const Icon( + Icons.add, + color: Colors.white, ), ), - ], + ), + ], + ), + ), + ...associationMemberList.when( + data: (data) { + return data + .map((member) => MemberEditableCard(member: member)) + .toList(); + }, + error: (error, stackTrace) { + return const [ + Text(PhonebookTextConstants.errorLoadAssociationMember), + ]; + }, + loading: () => [ + const Center( + child: CircularProgressIndicator(), ), - ...associationMemberList.when( - data: (data) { - return data - .map((member) => MemberEditableCard(member: member)).toList(); - }, - error: (error, stackTrace) { - return const [Text(PhonebookTextConstants.errorLoadAssociationMember),]; - }, - loading: () => [ - const Center( - child: CircularProgressIndicator(), - ), - ],) - ]), - )); + ], + ), + const SizedBox( + height: 10, + ) + ]), + ); } } diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index 27cae2385..c1fbf4ecb 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -36,116 +36,128 @@ class MemberEditableCard extends HookConsumerWidget { displayToast(context, type, msg); } - return Container( - margin: const EdgeInsets.all(10), - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - border: Border.all(), - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(20)), - ), - child: Row( - children: [ - Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - spreadRadius: 5, - blurRadius: 10, - offset: const Offset(2, 3), - ), - ], - ), - child: profilePicture.when( - data: (picture) { - return CircleAvatar( - radius: 20, - backgroundImage: picture.isEmpty - ? const AssetImage('assets/images/logo_alpha.png') - : Image.memory(picture).image, - ); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: Text( - PhonebookTextConstants.errorLoadAssociationPicture), - ); - }, + padding: const EdgeInsets.all(10), + margin: const EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: BoxDecoration( + border: Border.all(), + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(20)), + ), + child: Row( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + spreadRadius: 5, + blurRadius: 10, + offset: const Offset(2, 3), ), - ), - const SizedBox(width: 10), - SizedBox( - width: 400, - child: Column( - children: [ - Text( - "${member.member.name} ${member.member.firstname} (${member.member.nickname})", - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 5), - Text( - member.member.email, - style: const TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - ), - const Spacer(), - Text(member.memberships.firstWhere((element) => element.association.id == association.id).apparentName, + ], + ), + child: profilePicture.when( + data: (picture) { + return CircleAvatar( + radius: 20, + backgroundImage: picture.isEmpty + ? const AssetImage('assets/images/logo_alpha.png') + : Image.memory(picture).image, + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return const Center( + child: Text("Error"), + ); + }, + ), + ), + const SizedBox(width: 10), + SizedBox( + width: 400, + child: Column( + children: [ + Text( + "${member.member.name} ${member.member.firstname} (${member.member.nickname})", style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, - )), - const Spacer(), - EditionButton(onEdition: () async { - showDialog( - context: context, - builder: (BuildContext context) { - return MembershipDialog( - apparentNameController: controller, - title: PhonebookTextConstants.editMembership, - defaultText: member.memberships.firstWhere((element) => element.association.id == association.id).apparentName, - onConfirm: () async { - final result = await associationNotifier.updateMember( - association, - member.toMember(), - memberRoleTags, - controller.text); - if (result) { - await associationMembersNotifier.loadMembers(association.id); - displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.updatedMember); - } else { - displayToastWithContext(TypeMsg.error, PhonebookTextConstants.updatingError); - } - }); - }); - }), - const SizedBox(width: 10), - DeleteButton(onDelete: - () async { - final result = await associationNotifier.deleteMember(association, member); - await associationMembersNotifier.loadMembers(association.id); - if (result) { - displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.deletedMember); - } else { - displayToastWithContext(TypeMsg.error, PhonebookTextConstants.deletingError); - } - },) - ], - )); + ), + ), + const SizedBox(height: 5), + Text( + member.member.email, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + const Spacer(), + Text( + member.memberships + .firstWhere( + (element) => element.association.id == association.id) + .apparentName, + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + )), + const Spacer(), + EditionButton(onEdition: () async { + showDialog( + context: context, + builder: (BuildContext context) { + return MembershipDialog( + apparentNameController: controller, + title: PhonebookTextConstants.editMembership, + defaultText: member.memberships + .firstWhere((element) => + element.association.id == association.id) + .apparentName, + onConfirm: () async { + final result = await associationNotifier.updateMember( + association, + member.toMember(), + memberRoleTags, + controller.text); + if (result) { + await associationMembersNotifier + .loadMembers(association.id); + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.updatedMember); + } else { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.updatingError); + } + }); + }); + }), + const SizedBox(width: 10), + DeleteButton( + onDelete: () async { + final result = + await associationNotifier.deleteMember(association, member); + await associationMembersNotifier.loadMembers(association.id); + if (result) { + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.deletedMember); + } else { + displayToastWithContext( + TypeMsg.error, PhonebookTextConstants.deletingError); + } + }, + ) + ], + )); } } diff --git a/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart b/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart index b8f8d9dc5..d4e379fc3 100644 --- a/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart +++ b/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart @@ -10,7 +10,7 @@ import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:myecl/user/providers/user_list_provider.dart'; import 'package:tuple/tuple.dart'; -class MembershipDialog extends HookConsumerWidget{ +class MembershipDialog extends HookConsumerWidget { const MembershipDialog({ Key? key, required this.apparentNameController, @@ -24,14 +24,17 @@ class MembershipDialog extends HookConsumerWidget{ final VoidCallback onConfirm; final TextEditingController apparentNameController; - String nameConstructor (Tuple2> data) { + String nameConstructor(Tuple2> data) { String name = ''; for (int i = 0; i < data.item2.length; i++) { if (data.item2[i]) { - name ="$name, ${data.item1.tags[i]}"; + name = "$name, ${data.item1.tags[i]}"; } } - if (name == "") {return "";}; + if (name == "") { + return ""; + } + ; return name.substring(1, name.length); } @@ -39,103 +42,102 @@ class MembershipDialog extends HookConsumerWidget{ Widget build(BuildContext context, WidgetRef ref) { final rolesTags = ref.watch(rolesTagsProvider); final apparentName = useState(defaultText); - final queryController = - useTextEditingController(text: ''); + final queryController = useTextEditingController(text: ''); final usersNotifier = ref.watch(userList.notifier); final memberRoleTagsNotifier = ref.watch(memberRolesTagsProvider.notifier); final rolesTagsNotifier = ref.watch(rolesTagsProvider.notifier); List checked = []; apparentNameController.text = apparentName.value; - return AlertDialog( - title: Center( + return AlertDialog( + title: Center( child: Container( - decoration: const BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.black)), - color: Colors.white, + decoration: const BoxDecoration( + border: Border(bottom: BorderSide(color: Colors.black)), + color: Colors.white, ), - child: Text(title, style: const TextStyle(fontSize: 20)) - ) - ), - content: SizedBox( - height: 400, + child: Text(title, style: const TextStyle(fontSize: 20)))), + content: SizedBox( + height: 390, + child: SingleChildScrollView( child: Column( - children: [ - const SizedBox(height: 25), - const Text(PhonebookTextConstants.member), - const SizedBox(height: 5), - TextFormField( - onChanged: (value) { - tokenExpireWrapper(ref, () async { - if (queryController.text.isNotEmpty) { - await usersNotifier.filterUsers(queryController.text); - } else { - usersNotifier.clear(); - } - }); - }, - cursorColor: Colors.black, - controller: queryController, - decoration: const InputDecoration( - labelText: PhonebookTextConstants.member, - floatingLabelStyle: TextStyle( - color: Colors.black, - fontWeight: FontWeight.bold, - ), - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide(color: Colors.black, width: 2.0), - ), - ), + children: [ + TextFormField( + onChanged: (value) { + tokenExpireWrapper(ref, () async { + if (queryController.text.isNotEmpty) { + await usersNotifier.filterUsers(queryController.text); + } else { + usersNotifier.clear(); + } + }); + }, + cursorColor: Colors.black, + controller: queryController, + decoration: const InputDecoration( + labelText: PhonebookTextConstants.member, + floatingLabelStyle: TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, ), - const SizedBox( - height: 10, + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.black, width: 2.0), ), - SearchResult(queryController: queryController), - ...rolesTags.when( - data: (data) { - return data.item1.tags.map((e) => Row( - children: [ - Text(e), - const Spacer(), - Checkbox( - value: data.item2[data.item1.tags.indexOf(e)], - fillColor: MaterialStateProperty.all(Colors.black), - onChanged: (value) { - checked = data.item2; - checked[data.item1.tags.indexOf(e)] = value!; - debugPrint(checked.toString()); - apparentName.value = nameConstructor(data); - apparentNameController.text = apparentName.value; - memberRoleTagsNotifier.setRoleTagsWithFilter(data); - }, - )])).toList(); - }, - error: (e,s) => [const Text('Error')], - loading: () => [const Text('Loading')],), - const SizedBox(height: 5), - const Text(PhonebookTextConstants.apparentName), - TextField( - controller: apparentNameController, - ) - - ], + ), + ), + const SizedBox( + height: 10, + ), + SearchResult(queryController: queryController), + ...rolesTags.when( + data: (data) { + return data.item1.tags + .map((e) => Row(children: [ + Text(e), + const Spacer(), + Checkbox( + value: data.item2[data.item1.tags.indexOf(e)], + fillColor: MaterialStateProperty.all(Colors.black), + onChanged: (value) { + checked = data.item2; + checked[data.item1.tags.indexOf(e)] = value!; + debugPrint(checked.toString()); + apparentName.value = nameConstructor(data); + apparentNameController.text = apparentName.value; + memberRoleTagsNotifier + .setRoleTagsWithFilter(data); + }, + ) + ])) + .toList(); + }, + error: (e, s) => [const Text('Error')], + loading: () => [const Text('Loading')], + ), + const SizedBox(height: 5), + const Text(PhonebookTextConstants.apparentName), + TextField( + controller: apparentNameController, + ) + ], )), - actions: [ - TextButton( - onPressed: (){ - Navigator.of(context).pop(); - }, - child: const Text(PhonebookTextConstants.cancel), - ), - TextButton( - onPressed: () { - Navigator.of(context).pop(); - onConfirm(); - rolesTagsNotifier.resetChecked(); - }, - child: const Text(PhonebookTextConstants.validation), - ), - ], - ); + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text(PhonebookTextConstants.cancel), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + onConfirm(); + rolesTagsNotifier.resetChecked(); + }, + child: const Text(PhonebookTextConstants.validation), + ), + ], + ); } -} \ No newline at end of file +} From f2df2a62371d25260d500d70fda70552aabc7d59 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:00 +0100 Subject: [PATCH 012/123] Complete association research system --- .../providers/association_list_provider.dart | 28 ++++++++++++++++--- .../repositories/association_repository.dart | 3 +- .../ui/pages/admin_page/admin_page.dart | 11 ++++---- .../admin_page/association_research_bar.dart | 3 +- .../ui/pages/main_page/research_bar.dart | 3 +- 5 files changed, 36 insertions(+), 12 deletions(-) diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index 6b6cb7776..d6c211153 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -7,6 +7,7 @@ import 'package:myecl/tools/token_expire_wrapper.dart'; class AssociationListNotifier extends ListNotifier { final AssociationRepository associationRepository = AssociationRepository(); + AsyncValue> associationList = const AsyncValue.loading(); AssociationListNotifier({ required String token,}) : super(const AsyncValue.loading()) { @@ -15,29 +16,48 @@ class AssociationListNotifier extends ListNotifier { Future>> loadAssociations() async { - return await loadList(() async => associationRepository.getAssociationList()); + associationList = await loadList(() async => associationRepository.getAssociationList()); + return associationList; } Future createAssociation(Association association) async { - return await add(associationRepository.createAssociation, association); + final result = await add(associationRepository.createAssociation, association); + if (result) { + associationList = state; + } + return result; } Future updateAssociation(Association association) async { - return await update( + final result = await update( associationRepository.updateAssociation, (associations, association) => associations..[associations.indexWhere((g) => g.id == association.id)] = association, association); + if (result) { + associationList = state; + } + return result; } Future deleteAssociation(Association association) async { - return await delete( + final result = await delete( associationRepository.deleteAssociation, (associations, association) => associations..removeWhere((i) => i.id == association.id), association.id, association); + if (result) { + associationList = state; + } + return result; } + void filterAssociationList(String filter) async { + associationList.maybeWhen( + data: (data) => state = AsyncValue.data(data.where((element) => element.name.toLowerCase().contains(filter.toLowerCase())).toList()), + orElse: () => state = const AsyncLoading(),); + } + void setAssociationList(List associationList) { state.whenData( (d) { diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index 2b343ca89..d22b7d2b5 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -79,7 +79,8 @@ class AssociationRepository extends Repository { Future updateMember(Association association, Member member, List rolesTags, String apparentName) async { fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.id)] .memberships - .add(Membership(association: association, rolesTags: rolesTags, apparentName: apparentName)); + .where((element) => element.association.id == association.id).toList()[0] = + Membership(association: association, rolesTags: rolesTags, apparentName: apparentName); //await update({"member_id": member.id, "association_id": association.id, "rolesTags": rolesTags, "apparentName": apparentName"}, // suffix: "membership"); return true; diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 786b13366..c36cdfc3e 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/filtered_association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; @@ -21,7 +23,7 @@ class AdminPage extends HookConsumerWidget { final pageNotifier = ref.watch(phonebookPageProvider.notifier); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationsNotifier = ref.watch(associationListProvider.notifier); - final filteredAssociations = ref.watch(filteredAssociationListProvider); + final filteredAssociations = useState(AsyncValue>); final associations = ref.watch(associationListProvider); final roleNotifier = ref.watch(rolesTagsProvider.notifier); final filterNotifier = ref.watch(filterProvider.notifier); @@ -35,7 +37,6 @@ class AdminPage extends HookConsumerWidget { onRefresh: () async { await associationsNotifier.loadAssociations(); await roleNotifier.loadRolesTags(); - await filteredAssociationListNotifier.loadAssociations(); }, child: Column( children: @@ -57,8 +58,8 @@ class AdminPage extends HookConsumerWidget { margin: const EdgeInsets.all(10), child: Row(children: const [Spacer(), Icon(Icons.add), Spacer()]) ), - )] + - associations.when( + ), + ...associations.when( data: (associations) { return associations.map((association) => EditableAssociationCard( association: association, @@ -79,7 +80,7 @@ class AdminPage extends HookConsumerWidget { ).toList();}, loading: () => const [Center(child: CircularProgressIndicator())], error: (error, stack) => [const Center(child: Text(PhonebookTextConstants.errorLoadAssociationList))]) - ), + ],), ]) ); diff --git a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart index c41abc396..d3036abe8 100644 --- a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart +++ b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart @@ -18,6 +18,7 @@ class AssociationResearchBar extends HookConsumerWidget { final focusNode = useFocusNode(); final editingController = useTextEditingController(); final filterNotifier = ref.watch(filterProvider.notifier); + final associationsNotifier = ref.watch(associationListProvider.notifier); return Container( decoration: BoxDecoration( @@ -36,7 +37,7 @@ class AssociationResearchBar extends HookConsumerWidget { width: 300, child: TextField( onChanged: (value) async { - filterNotifier.setFilter(value); + associationsNotifier.filterAssociationList(value); }, focusNode: focusNode, controller: editingController, diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart index 5a92e41c7..4e9f1dd15 100644 --- a/lib/phonebook/ui/pages/main_page/research_bar.dart +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -19,6 +19,7 @@ class ResearchBar extends HookConsumerWidget { final focusNode = useFocusNode(); final editingController = useTextEditingController(); final filterNotifier = ref.watch(filterProvider.notifier); + final associationsNotifier = ref.watch(associationListProvider.notifier); return Container( decoration: BoxDecoration( @@ -37,7 +38,7 @@ class ResearchBar extends HookConsumerWidget { width: 300, child: TextField( onChanged: (value) { - filterNotifier.setFilter(value); + associationsNotifier.filterAssociationList(value); }, focusNode: focusNode, controller: editingController, From e7e8d057c01226a746b2e0c1585b14b21c15a45a Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:00 +0100 Subject: [PATCH 013/123] Cleanup --- .../filtered_association_list_provider.dart | 2 - .../repositories/association_repository.dart | 5 - lib/phonebook/tools/fake_class.dart | 2 +- lib/phonebook/ui/association_card.dart | 1 - .../ui/pages/admin_page/admin_page.dart | 4 - .../admin_page/association_research_bar.dart | 6 - .../association_creation_page.dart | 1 - .../association_editor_page.dart | 4 - .../member_editable_card.dart | 6 - .../membership_dialog.dart | 1 - .../association_page/association_page.dart | 161 +++++++++--------- .../ui/pages/main_page/main_page.dart | 126 +++++++------- .../ui/pages/main_page/research_bar.dart | 32 ++-- .../role_member_page/role_member_page.dart | 2 +- 14 files changed, 159 insertions(+), 194 deletions(-) diff --git a/lib/phonebook/providers/filtered_association_list_provider.dart b/lib/phonebook/providers/filtered_association_list_provider.dart index cae927d53..1eb6c0f62 100644 --- a/lib/phonebook/providers/filtered_association_list_provider.dart +++ b/lib/phonebook/providers/filtered_association_list_provider.dart @@ -1,11 +1,9 @@ -import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/repositories/association_repository.dart'; import 'package:myecl/tools/providers/list_notifier.dart'; -import 'package:myecl/tools/providers/single_notifier.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; class FilteredAssociationListNotifier extends ListNotifier { diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index d22b7d2b5..f952eb8fa 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -1,14 +1,9 @@ -import 'package:flutter/material.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/member.dart'; import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/tools/fake_class.dart'; import 'package:myecl/tools/repository/repository.dart'; -import 'package:myecl/user/class/list_users.dart'; -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:myecl/tools/exception.dart'; class AssociationRepository extends Repository { @override diff --git a/lib/phonebook/tools/fake_class.dart b/lib/phonebook/tools/fake_class.dart index 0e8ac2076..f2649b9f2 100644 --- a/lib/phonebook/tools/fake_class.dart +++ b/lib/phonebook/tools/fake_class.dart @@ -8,7 +8,7 @@ import 'package:myecl/phonebook/class/roles_tags.dart'; String printFakeAssociations() { String result = ''; for (Association association in fakeAssociations) { - result += association.toString() + '\n'; + result += '$association\n'; } return result; } diff --git a/lib/phonebook/ui/association_card.dart b/lib/phonebook/ui/association_card.dart index c9451b691..929371279 100644 --- a/lib/phonebook/ui/association_card.dart +++ b/lib/phonebook/ui/association_card.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; -import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; class AssociationCard extends HookConsumerWidget { diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index c36cdfc3e..92a25c9fd 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -6,11 +6,9 @@ import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/filtered_association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; -import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/association_research_bar.dart'; -import 'package:myecl/phonebook/ui/association_card.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/editable_association_card.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/ui/refresher.dart'; @@ -23,10 +21,8 @@ class AdminPage extends HookConsumerWidget { final pageNotifier = ref.watch(phonebookPageProvider.notifier); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationsNotifier = ref.watch(associationListProvider.notifier); - final filteredAssociations = useState(AsyncValue>); final associations = ref.watch(associationListProvider); final roleNotifier = ref.watch(rolesTagsProvider.notifier); - final filterNotifier = ref.watch(filterProvider.notifier); final filteredAssociationListNotifier = ref.watch(filteredAssociationListProvider.notifier); void displayToastWithContext(TypeMsg type, String msg) { diff --git a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart index d3036abe8..84ecf8355 100644 --- a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart +++ b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart @@ -1,8 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/providers/association_list_provider.dart'; -import 'package:myecl/phonebook/providers/filtered_association_list_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; @@ -11,10 +9,6 @@ class AssociationResearchBar extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final associationListNotifier = - ref.watch(associationListProvider.notifier); - final filteredAssociationListNotifier = - ref.watch(filteredAssociationListProvider.notifier); final focusNode = useFocusNode(); final editingController = useTextEditingController(); final filterNotifier = ref.watch(filterProvider.notifier); diff --git a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart index 32b78e13d..9d7140ab2 100644 --- a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart +++ b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart @@ -3,7 +3,6 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/admin/tools/constants.dart'; import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 7a53b03fe..a3bef140f 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -2,8 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; @@ -11,7 +9,6 @@ import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/member_provider.dart'; import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; -import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/pages/association_creation_page/kind_chip.dart'; import 'package:myecl/phonebook/ui/pages/association_editor_page/member_editable_card.dart'; @@ -32,7 +29,6 @@ class AssociationEditorPage extends HookConsumerWidget { final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); final associationMemberList = ref.watch(associationMemberListProvider); - final associationPicture = ref.watch(associationPictureProvider); final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); final associationListNotifier = ref.watch(associationListProvider.notifier); diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index c1fbf4ecb..e2ffadeda 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -1,19 +1,14 @@ import 'package:flutter/material.dart'; -import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; -import 'package:myecl/phonebook/class/member.dart'; -import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; import 'package:myecl/phonebook/ui/delete_button.dart'; import 'package:myecl/phonebook/ui/edition_button.dart'; import 'package:myecl/phonebook/ui/pages/association_editor_page/membership_dialog.dart'; -import 'package:myecl/phonebook/ui/text_input_dialog.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/user/providers/profile_picture_provider.dart'; -import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; class MemberEditableCard extends HookConsumerWidget { @@ -23,7 +18,6 @@ class MemberEditableCard extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final memberNotifier = ref.watch(completeMemberProvider.notifier); final profilePicture = ref.watch(profilePictureProvider); final association = ref.watch(associationProvider); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); diff --git a/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart b/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart index d4e379fc3..a334d899e 100644 --- a/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart +++ b/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart @@ -34,7 +34,6 @@ class MembershipDialog extends HookConsumerWidget { if (name == "") { return ""; } - ; return name.substring(1, name.length); } diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index 7b887cd75..8a2060439 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -1,16 +1,13 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/tools/fake_class.dart'; import 'package:myecl/phonebook/ui/pages/association_page/member_card.dart'; import 'package:myecl/tools/ui/refresher.dart'; class AssociationPage extends HookConsumerWidget { - const AssociationPage({Key? key}) : super(key: key); @override @@ -18,39 +15,79 @@ class AssociationPage extends HookConsumerWidget { final association = ref.watch(associationProvider); final associationPicture = ref.watch(associationPictureProvider); final associationMemberList = ref.watch(associationMemberListProvider); - final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); - final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); - + final associationMemberListNotifier = + ref.watch(associationMemberListProvider.notifier); + final associationPictureNotifier = + ref.watch(associationPictureProvider.notifier); return Refresher( - onRefresh : () async { - await associationMemberListNotifier.loadMembers(association.id); - await associationPictureNotifier.getAssociationPicture(association.id); - }, - child: Column( - children: [ - const Text(PhonebookTextConstants.associationDetail, style: TextStyle(fontSize: 30)), - const SizedBox(height: 20,), - Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - spreadRadius: 5, - blurRadius: 10, - offset: const Offset(2, 3), - ), - ], + onRefresh: () async { + await associationMemberListNotifier.loadMembers(association.id); + await associationPictureNotifier + .getAssociationPicture(association.id); + }, + child: Column(children: [ + const Text(PhonebookTextConstants.associationDetail, + style: TextStyle(fontSize: 30)), + const SizedBox( + height: 20, ), - child: associationPicture.when( - data: (picture) { - return CircleAvatar( - radius: 120, - backgroundImage: picture.isEmpty - ? const AssetImage('assets/images/logo_alpha.png') - : Image.memory(picture).image, - ); + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + spreadRadius: 5, + blurRadius: 10, + offset: const Offset(2, 3), + ), + ], + ), + child: associationPicture.when( + data: (picture) { + return CircleAvatar( + radius: 120, + backgroundImage: picture.isEmpty + ? const AssetImage('assets/images/logo_alpha.png') + : Image.memory(picture).image, + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return const Center( + child: + Text(PhonebookTextConstants.errorLoadAssociationPicture), + ); + }, + ), + ), + const SizedBox(height: 20), + Text( + association.name, + style: const TextStyle(fontSize: 40, color: Colors.black), + ), + const SizedBox(height: 10), + Text(association.kind, + style: const TextStyle(fontSize: 20, color: Colors.black)), + const SizedBox(height: 10), + Text( + association.description, + style: const TextStyle(fontSize: 15, color: Colors.black), + ), + const SizedBox( + height: 20, + ), + associationMemberList.when( + data: (members) { + return Column( + children: members + .map((member) => MemberCard(member: member)) + .toList()); }, loading: () { return const Center( @@ -59,57 +96,15 @@ class AssociationPage extends HookConsumerWidget { }, error: (e, s) { return const Center( - child: Text(PhonebookTextConstants.errorLoadAssociationPicture), + child: Text(PhonebookTextConstants.errorLoadAssociationMember), + // List fakeMembers = [CompleteMember.empty()]; + // return Column( + // children: fakeMembers.map((member) => + // MemberCard(member: member) + // ).toList() ); }, - ), - ), - const SizedBox(height: 20), - Text(association.name, - style: const TextStyle( - fontSize: 40, - color: Colors.black - ), - ), - const SizedBox(height: 10), - Text(association.kind, - style: const TextStyle( - fontSize: 20, - color: Colors.black - ) - ), - const SizedBox(height: 10), - Text(association.description, - style: const TextStyle( - fontSize: 15, - color: Colors.black - ), - ), - const SizedBox(height: 20,), - associationMemberList.when( - data: (members) { - return Column( - children: members.map((member) => - MemberCard(member: member) - ).toList() - ); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: Text(PhonebookTextConstants.errorLoadAssociationMember), - // List fakeMembers = [CompleteMember.empty()]; - // return Column( - // children: fakeMembers.map((member) => - // MemberCard(member: member) - // ).toList() - ); - }, - ) - ])); + ) + ])); } } diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index bbeb08ebf..bd4839f3b 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -5,7 +5,6 @@ import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/filtered_association_list_provider.dart'; -import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/admin/providers/is_admin.dart'; @@ -18,21 +17,21 @@ class MainPage extends HookConsumerWidget { const MainPage({Key? key}) : super(key: key); @override - Widget build(BuildContext context, WidgetRef ref) { + Widget build(BuildContext context, WidgetRef ref) { final isAdmin = ref.watch(isAdminProvider); final pageNotifier = ref.watch(phonebookPageProvider.notifier); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationListNotifier = ref.watch(associationListProvider.notifier); - final filteredAssociationList = ref.watch(filteredAssociationListProvider); - final filterNotifier = ref.watch(filterProvider.notifier); - final filteredAssociationListNotifier = ref.watch(filteredAssociationListProvider.notifier); + final filteredAssociationListNotifier = + ref.watch(filteredAssociationListProvider.notifier); final associationList = ref.watch(associationListProvider); - final associationKindsNotifier = ref.watch(associationKindsProvider.notifier); + final associationKindsNotifier = + ref.watch(associationKindsProvider.notifier); final rolesTagsNotifier = ref.watch(rolesTagsProvider.notifier); return Stack( - children: [ - Refresher( + children: [ + Refresher( onRefresh: () async { await rolesTagsNotifier.loadRolesTags(); await associationKindsNotifier.loadAssociationKinds(); @@ -40,58 +39,67 @@ class MainPage extends HookConsumerWidget { await filteredAssociationListNotifier.loadAssociations(); }, child: Column( - children: [ - const SizedBox(height: 70), - const ResearchBar(), - const SizedBox(width: 10),] + - associationList.when( - data: (associations) { - return associations.map((association) => AssociationCard( - association: association, - onClicked: () { - associationNotifier.setAssociation(association); - pageNotifier.setPhonebookPage(PhonebookPage.associationPage); - },) - ).toList();}, - loading: () => const [Center(child: CircularProgressIndicator())], - error: (error, stack) => [const Center(child: Text(PhonebookTextConstants.errorLoadAssociationList))] - ) - )), - if (isAdmin) - Positioned( - top: 15, - right: 15, - child: GestureDetector( - onTap: () { - pageNotifier.setPhonebookPage(PhonebookPage.admin); - }, - child: Container( - padding: - const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 10, - offset: const Offset(0, 5)) - ]), - child: Row( - children: const [ - HeroIcon(HeroIcons.userGroup, color: Colors.white), - SizedBox(width: 10), - Text(PhonebookTextConstants.admin, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.white)), - ], - ), + children: [ + const SizedBox(height: 70), + const ResearchBar(), + const SizedBox(width: 10), + ] + + associationList.when( + data: (associations) { + return associations + .map((association) => AssociationCard( + association: association, + onClicked: () { + associationNotifier + .setAssociation(association); + pageNotifier.setPhonebookPage( + PhonebookPage.associationPage); + }, + )) + .toList(); + }, + loading: () => + const [Center(child: CircularProgressIndicator())], + error: (error, stack) => [ + const Center( + child: Text(PhonebookTextConstants + .errorLoadAssociationList)) + ]))), + if (isAdmin) + Positioned( + top: 15, + right: 15, + child: GestureDetector( + onTap: () { + pageNotifier.setPhonebookPage(PhonebookPage.admin); + }, + child: Container( + padding: + const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + blurRadius: 10, + offset: const Offset(0, 5)) + ]), + child: Row( + children: const [ + HeroIcon(HeroIcons.userGroup, color: Colors.white), + SizedBox(width: 10), + Text(PhonebookTextConstants.admin, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.white)), + ], ), ), - ) - ], - ); + ), + ) + ], + ); } } diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart index 4e9f1dd15..f8520ddbe 100644 --- a/lib/phonebook/ui/pages/main_page/research_bar.dart +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -1,26 +1,18 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/providers/association_list_provider.dart'; -import 'package:myecl/phonebook/providers/filtered_association_list_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/tools/token_expire_wrapper.dart'; class ResearchBar extends HookConsumerWidget { const ResearchBar({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { - final associationListNotifier = - ref.watch(associationListProvider.notifier); - final filteredAssociationListNotifier = - ref.watch(filteredAssociationListProvider.notifier); final focusNode = useFocusNode(); final editingController = useTextEditingController(); final filterNotifier = ref.watch(filterProvider.notifier); - final associationsNotifier = ref.watch(associationListProvider.notifier); - + return Container( decoration: BoxDecoration( border: Border.all(), @@ -44,17 +36,17 @@ class ResearchBar extends HookConsumerWidget { controller: editingController, cursorColor: PhonebookColorConstants.textDark, decoration: const InputDecoration( - labelText: PhonebookTextConstants.associationPureSearch, - labelStyle: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: PhonebookColorConstants.textDark), - suffixIcon: Icon( - Icons.search, - color: PhonebookColorConstants.textDark, - size: 30, - ), - ), + labelText: PhonebookTextConstants.associationPureSearch, + labelStyle: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: PhonebookColorConstants.textDark), + suffixIcon: Icon( + Icons.search, + color: PhonebookColorConstants.textDark, + size: 30, + ), + ), )); } } diff --git a/lib/phonebook/ui/pages/role_member_page/role_member_page.dart b/lib/phonebook/ui/pages/role_member_page/role_member_page.dart index 2196f8a95..e3fe2006d 100644 --- a/lib/phonebook/ui/pages/role_member_page/role_member_page.dart +++ b/lib/phonebook/ui/pages/role_member_page/role_member_page.dart @@ -6,6 +6,6 @@ class RoleMemberPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - return SizedBox(); + return const SizedBox(); } } \ No newline at end of file From 32e751cf0bcd977773c271e0a7608b2bebea1e65 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:00 +0100 Subject: [PATCH 014/123] Fix errors due to previous merge --- lib/phonebook/ui/pages/admin_page/association_research_bar.dart | 1 + lib/phonebook/ui/pages/main_page/research_bar.dart | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart index 84ecf8355..684db09be 100644 --- a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart +++ b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart index f8520ddbe..171d4c84e 100644 --- a/lib/phonebook/ui/pages/main_page/research_bar.dart +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; From 5d5554ec3cf98c078fde6d4d62ea1201fac0e1bc Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:00 +0100 Subject: [PATCH 015/123] Fully functional front Complete last required features: - association's kind search filter - association's name search filter - complete membership management - gestion of mandateYear and new mandate - student's promotion --- lib/phonebook/class/complete_member.dart | 16 +- lib/phonebook/class/member.dart | 14 +- lib/phonebook/class/membership.dart | 9 +- .../providers/association_kind_provider.dart | 8 +- .../providers/association_kinds_provider.dart | 2 +- .../providers/association_list_provider.dart | 14 +- .../providers/complete_member_provider.dart | 5 + lib/phonebook/providers/edition_provider.dart | 14 ++ .../filtered_association_list_provider.dart | 52 ----- .../providers/member_role_tags_provider.dart | 8 +- .../providers/phonebook_page_provider.dart | 10 +- lib/phonebook/providers/reload_provider.dart | 14 ++ .../providers/research_filter_provider.dart | 10 +- .../providers/roles_tags_provider.dart | 18 ++ .../repositories/association_repository.dart | 11 + lib/phonebook/tools/constants.dart | 12 + lib/phonebook/tools/fake_class.dart | 18 +- .../kind_chip.dart | 0 lib/phonebook/ui/page_switcher.dart | 9 +- .../ui/pages/admin_page/admin_page.dart | 134 ++++++++---- .../admin_page/association_research_bar.dart | 5 +- .../association_creation_page.dart | 2 +- .../association_editor_page.dart | 147 ++++++++++--- .../member_editable_card.dart | 43 ++-- .../membership_dialog.dart | 76 ++++--- .../association_page/association_page.dart | 10 +- .../ui/pages/main_page/main_page.dart | 92 +++++--- .../ui/pages/main_page/research_bar.dart | 8 +- .../member_detail_page.dart | 11 +- .../membership_editor_page.dart | 205 ++++++++++++++++++ .../search_result.dart | 6 +- .../role_member_page/role_member_page.dart | 11 - .../ui/pages/role_page/role_page.dart | 11 - lib/phonebook/ui/phonebook.dart | 9 +- lib/phonebook/ui/top_bar.dart | 9 +- 35 files changed, 712 insertions(+), 311 deletions(-) create mode 100644 lib/phonebook/providers/edition_provider.dart delete mode 100644 lib/phonebook/providers/filtered_association_list_provider.dart create mode 100644 lib/phonebook/providers/reload_provider.dart rename lib/phonebook/ui/{pages/association_creation_page => }/kind_chip.dart (100%) create mode 100644 lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart rename lib/phonebook/ui/pages/{association_editor_page => membership_editor_page}/search_result.dart (91%) delete mode 100644 lib/phonebook/ui/pages/role_member_page/role_member_page.dart delete mode 100644 lib/phonebook/ui/pages/role_page/role_page.dart diff --git a/lib/phonebook/class/complete_member.dart b/lib/phonebook/class/complete_member.dart index 78812d2cb..4b97afc17 100644 --- a/lib/phonebook/class/complete_member.dart +++ b/lib/phonebook/class/complete_member.dart @@ -13,13 +13,13 @@ class CompleteMember{ CompleteMember.fromJSON(Map json){ member = Member.fromJSON(json['user']); - memberships = json['membership'].map((membership) => Membership.fromJSON(membership)).toList(); + memberships = json['memberships'].map((membership) => Membership.fromJSON(membership)).toList(); } Map toJSON(){ final data = { 'member': member.id, - 'membership': memberships.map((e) => e.toJSON()).toList(), + 'memberships': memberships.map((e) => e.toJSON()).toList(), }; return data; } @@ -45,6 +45,16 @@ class CompleteMember{ firstname: member.firstname, nickname: member.nickname, id: member.id, - email: member.email); + email: member.email, + promotion: member.promotion,); + } + + @override + String toString() { + return 'CompleteMember(member: $member, memberships: $memberships)'; + } + + List getRolesTags(String associationId){ + return memberships.firstWhere((element) => element.association.id == associationId).rolesTags; } } diff --git a/lib/phonebook/class/member.dart b/lib/phonebook/class/member.dart index 7c7839791..29a177988 100644 --- a/lib/phonebook/class/member.dart +++ b/lib/phonebook/class/member.dart @@ -7,6 +7,7 @@ class Member{ required this.nickname, required this.id, required this.email, + required this.promotion, }); late final String name; @@ -14,6 +15,7 @@ class Member{ late final String? nickname; late final String id; late final String email; + late final String promotion; Member.fromJSON(Map json){ name = json['name']; @@ -21,6 +23,7 @@ class Member{ nickname = json['nickname']; id = json['id']; email = json['email']; + promotion = json['promotion']; } Map toJSON(){ @@ -30,6 +33,7 @@ class Member{ 'nickname': nickname, 'id': id, 'email': email, + 'promotion': promotion, }; return data; } @@ -40,6 +44,7 @@ class Member{ String? nickname, String? id, String? email, + String? promotion, }) { return Member( name: name ?? this.name, @@ -47,6 +52,7 @@ class Member{ nickname: nickname, id: id ?? this.id, email: email ?? this.email, + promotion: promotion ?? this.promotion, ); } @@ -56,6 +62,7 @@ class Member{ nickname = null; id = ""; email = "email.test@empty.useless"; + promotion = "Exx"; } Member.fromUser(SimpleUser user){ @@ -64,10 +71,15 @@ class Member{ nickname = user.nickname; id = user.id; email = ""; + promotion = "Exx"; } @override String toString() { - return 'Member(name: $name, firstname: $firstname, nickname: $nickname, id: $id, email: $email)'; + return 'Member(name: $name, firstname: $firstname, nickname: $nickname, id: $id, email: $email, promotion: $promotion)'; + } + + String getName() { + return "$firstname $name ($nickname)"; } } \ No newline at end of file diff --git a/lib/phonebook/class/membership.dart b/lib/phonebook/class/membership.dart index 1f31f4ac1..fe6310bf5 100644 --- a/lib/phonebook/class/membership.dart +++ b/lib/phonebook/class/membership.dart @@ -13,14 +13,14 @@ class Membership{ Membership.fromJSON(Map json){ association = json['association']; - rolesTags = json['role']; + rolesTags = json['roleTags']; apparentName = json['apparentName']; } Map toJSON(){ final data = { 'association': association.id, - 'rolesTags': rolesTags, + 'roleTags': rolesTags, 'apparentName': apparentName, }; return data; @@ -55,4 +55,9 @@ class Membership{ Membership setApparentName(String apparentName) { return copyWith(apparentName: apparentName); } + + @override + String toString() { + return 'Membership(association: $association, rolesTags: $rolesTags, apparentName: $apparentName)'; + } } \ No newline at end of file diff --git a/lib/phonebook/providers/association_kind_provider.dart b/lib/phonebook/providers/association_kind_provider.dart index 891404b2e..5b9b3026c 100644 --- a/lib/phonebook/providers/association_kind_provider.dart +++ b/lib/phonebook/providers/association_kind_provider.dart @@ -1,12 +1,12 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; -final kindProvider = StateNotifierProvider((ref) { - return KindNotifier(); +final associationKindProvider = StateNotifierProvider((ref) { + return AssociationKindNotifier(); }); -class KindNotifier extends StateNotifier { - KindNotifier() : super(""); +class AssociationKindNotifier extends StateNotifier { + AssociationKindNotifier() : super(""); void setKind(String i) { state = i; diff --git a/lib/phonebook/providers/association_kinds_provider.dart b/lib/phonebook/providers/association_kinds_provider.dart index 7a7c597c2..8e9b8292d 100644 --- a/lib/phonebook/providers/association_kinds_provider.dart +++ b/lib/phonebook/providers/association_kinds_provider.dart @@ -13,7 +13,7 @@ class AssociationKindsNotifier extends SingleNotifier { associationKindsRepository.setToken(token); } - void setRole(AssociationKinds i) { + void setKind(AssociationKinds i) { state = AsyncValue.data(i); } diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index d6c211153..51f80e124 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -52,11 +52,21 @@ class AssociationListNotifier extends ListNotifier { return result; } - void filterAssociationList(String filter) async { + void filterAssociationList(String nameFilter, String kindFilter) async { + if (kindFilter == "") { associationList.maybeWhen( - data: (data) => state = AsyncValue.data(data.where((element) => element.name.toLowerCase().contains(filter.toLowerCase())).toList()), + data: (data) => state = AsyncValue.data(data.where((element) => + element.name.toLowerCase().contains(nameFilter.toLowerCase())).toList()), orElse: () => state = const AsyncLoading(),); } + else { + associationList.maybeWhen( + data: (data) => state = AsyncValue.data(data.where((element) => + (element.name.toLowerCase().contains(nameFilter.toLowerCase()) & (element.kind == kindFilter)) + ).toList()), + orElse: () => state = const AsyncLoading(),); + } + } void setAssociationList(List associationList) { state.whenData( diff --git a/lib/phonebook/providers/complete_member_provider.dart b/lib/phonebook/providers/complete_member_provider.dart index 936547928..718829eda 100644 --- a/lib/phonebook/providers/complete_member_provider.dart +++ b/lib/phonebook/providers/complete_member_provider.dart @@ -1,5 +1,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/member.dart'; final completeMemberProvider = StateNotifierProvider((ref) { @@ -12,4 +13,8 @@ class CompleteMemberProvider extends StateNotifier { void setCompleteMember(CompleteMember i) { state = i; } + + void setMember(Member i) { + state = state.copyWith(member: i); + } } \ No newline at end of file diff --git a/lib/phonebook/providers/edition_provider.dart b/lib/phonebook/providers/edition_provider.dart new file mode 100644 index 000000000..fff792a62 --- /dev/null +++ b/lib/phonebook/providers/edition_provider.dart @@ -0,0 +1,14 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; + + +final editionProvider = StateNotifierProvider((ref) { + return EditionProvider(); +}); + +class EditionProvider extends StateNotifier { + EditionProvider() : super(false); + + void setStatus(bool i) { + state = i; + } +} \ No newline at end of file diff --git a/lib/phonebook/providers/filtered_association_list_provider.dart b/lib/phonebook/providers/filtered_association_list_provider.dart deleted file mode 100644 index 1eb6c0f62..000000000 --- a/lib/phonebook/providers/filtered_association_list_provider.dart +++ /dev/null @@ -1,52 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/auth/providers/openid_provider.dart'; -import 'package:myecl/phonebook/providers/association_list_provider.dart'; -import 'package:myecl/phonebook/repositories/association_repository.dart'; -import 'package:myecl/tools/providers/list_notifier.dart'; -import 'package:myecl/tools/token_expire_wrapper.dart'; - -class FilteredAssociationListNotifier extends ListNotifier { - final AssociationRepository associationRepository = AssociationRepository(); - FilteredAssociationListNotifier({ - required String token, - required this.associationList,}) - : super(const AsyncValue.loading()) { - associationRepository.setToken(token); - } - - late final AsyncValue> associationList; - - Future>> loadAssociations() async { - return await loadList(() async => associationRepository.getAssociationList()); - } - - void filterAssociationList(String filter) async { - associationList.maybeWhen( - data: (d) { - state = AsyncValue.data(d.where((association) => association.name.toLowerCase().contains(filter.toLowerCase())).toList()); - }, - orElse: () => state = const AsyncLoading()); - } - - void setAssociationList(List associationList) { - state.whenData( - (d) { - state = - AsyncValue.data(associationList); - }, - ); - } -} - -final filteredAssociationListProvider = - StateNotifierProvider>>( - (ref) { - final token = ref.watch(tokenProvider); - final associationList = ref.watch(associationListProvider); - FilteredAssociationListNotifier notifier = FilteredAssociationListNotifier(token: token, associationList: associationList); - tokenExpireWrapperAuth(ref, () async { - await notifier.loadAssociations(); - }); - return notifier; -}); diff --git a/lib/phonebook/providers/member_role_tags_provider.dart b/lib/phonebook/providers/member_role_tags_provider.dart index 7fbaf8a20..d0e09a7c0 100644 --- a/lib/phonebook/providers/member_role_tags_provider.dart +++ b/lib/phonebook/providers/member_role_tags_provider.dart @@ -4,12 +4,12 @@ import 'package:myecl/phonebook/class/roles_tags.dart'; import 'package:tuple/tuple.dart'; -final memberRolesTagsProvider = StateNotifierProvider>((ref) { - return MemberRolesTagsProvider(); +final memberRoleTagsProvider = StateNotifierProvider>((ref) { + return MemberRoleTagsProvider(); }); -class MemberRolesTagsProvider extends StateNotifier> { - MemberRolesTagsProvider() : super([]); +class MemberRoleTagsProvider extends StateNotifier> { + MemberRoleTagsProvider() : super([]); void setRoleTagsWithFilter(Tuple2> data) { debugPrint(data.item1.tags.toString()); diff --git a/lib/phonebook/providers/phonebook_page_provider.dart b/lib/phonebook/providers/phonebook_page_provider.dart index c17950604..00548b3ef 100644 --- a/lib/phonebook/providers/phonebook_page_provider.dart +++ b/lib/phonebook/providers/phonebook_page_provider.dart @@ -1,6 +1,14 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; -enum PhonebookPage { main, admin, memberDetail, addEditRoleMember, editRole, associationEditor, associationPage, associationCreation} +enum PhonebookPage { + main, + admin, + memberDetail, + associationEditor, + associationPage, + associationCreation, + membershipEdition +} final phonebookPageProvider = StateNotifierProvider((ref) { diff --git a/lib/phonebook/providers/reload_provider.dart b/lib/phonebook/providers/reload_provider.dart new file mode 100644 index 000000000..3fd1f1ae7 --- /dev/null +++ b/lib/phonebook/providers/reload_provider.dart @@ -0,0 +1,14 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; + + +final reloadProvider = StateNotifierProvider((ref) { + return ReloadProvider(); +}); + +class ReloadProvider extends StateNotifier { + ReloadProvider() : super(false); + + void setStatus(bool i) { + state = i; + } +} \ No newline at end of file diff --git a/lib/phonebook/providers/research_filter_provider.dart b/lib/phonebook/providers/research_filter_provider.dart index e276ceab5..0743c5a29 100644 --- a/lib/phonebook/providers/research_filter_provider.dart +++ b/lib/phonebook/providers/research_filter_provider.dart @@ -1,20 +1,16 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:myecl/phonebook/providers/filtered_association_list_provider.dart'; final filterProvider = StateNotifierProvider((ref) { - final filteredAssociationListNotifier = ref.watch(filteredAssociationListProvider.notifier); - return FilterNotifier(filteredAssociationListNotifier); + return FilterNotifier(); }); class FilterNotifier extends StateNotifier { - FilterNotifier(this.filteredAssociationListNotifier + FilterNotifier( ) : super(""); - late final FilteredAssociationListNotifier filteredAssociationListNotifier; void setFilter(String i) { - state = i; - filteredAssociationListNotifier.filterAssociationList(i); + state = i;; } } \ No newline at end of file diff --git a/lib/phonebook/providers/roles_tags_provider.dart b/lib/phonebook/providers/roles_tags_provider.dart index 08d1d7ca7..6ea272041 100644 --- a/lib/phonebook/providers/roles_tags_provider.dart +++ b/lib/phonebook/providers/roles_tags_provider.dart @@ -1,5 +1,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/roles_tags.dart'; import 'package:myecl/phonebook/repositories/role_tags_repository.dart'; import 'package:myecl/tools/providers/single_notifier.dart'; @@ -26,6 +28,22 @@ class RolesTagsNotifier extends SingleNotifier>> { final checked = state.value!.item2; state = AsyncValue.data(Tuple2(state.value!.item1, List.filled(checked.length, false))); } + + void setChecked(int index, bool value) { + List checked = state.value!.item2; + checked[index] = value; + state = AsyncValue.data(Tuple2(state.value!.item1, checked)); + } + + void loadRoleTagsFromMember(CompleteMember member, Association association) { + final checked = state.value!.item2; + List roleTags = member.getRolesTags(association.id); + for (int i = 0; i < checked.length; i++) { + checked[i] = roleTags.contains(state.value!.item1.tags[i]); + } + state = AsyncValue.data(Tuple2(state.value!.item1, checked)); + } + } final rolesTagsProvider = StateNotifierProvider>>>((ref) { diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index f952eb8fa..7e8653c57 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -1,3 +1,4 @@ +import 'package:flutter/material.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/member.dart'; @@ -45,6 +46,15 @@ class AssociationRepository extends Repository { } Future addMember(Association association, Member member, List rolesTags, String apparentName) async { + if (fakeMembersList.indexWhere((element) => element.member.id == member.id) == -1) { + fakeMembersList.add(CompleteMember(member: member, memberships: [])); + } + if (fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.id)] + .memberships + .indexWhere((element) => element.association.id == association.id) != + -1) { + return false; + } fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.id)] .memberships .add(Membership(association: association, rolesTags: rolesTags, apparentName: apparentName)); @@ -72,6 +82,7 @@ class AssociationRepository extends Repository { } Future updateMember(Association association, Member member, List rolesTags, String apparentName) async { + debugPrint("updateMember"); fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.id)] .memberships .where((element) => element.association.id == association.id).toList()[0] = diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index 4add155e6..ba2c6f49c 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -58,6 +58,18 @@ class PhonebookTextConstants { static const String addingError = "Erreur lors de l'ajout"; static const String addMember = "Ajouter un membre"; static const String updatedMember = "Membre modifié"; + static const String add = "Ajouter"; + static const String emptyMember = "Aucun membre sélectionné"; + static const String emptyApparentName = "Veuillez entrer un nom de role"; + static const String errorRoleTagsLoading = "Erreur lors du chargement des tags de rôle"; + static const String promotion = "Promotion :"; + static const String newMandateConfirmed = "Mandat changé"; + static const String mandateChangingError = "Erreur lors du changement de mandat"; + static const String changeMandateConfirm = "Êtes-vous sûr de vouloir changer tout le mandat ?\nCette action est irréversible !"; + static const String newMandate = "Nouveau mandat"; + static const String changeMandate = "Passer au mandat "; + + static const String activeMandate = "Mandat actif :"; } class PhonebookColorConstants{ diff --git a/lib/phonebook/tools/fake_class.dart b/lib/phonebook/tools/fake_class.dart index f2649b9f2..a57f50ee0 100644 --- a/lib/phonebook/tools/fake_class.dart +++ b/lib/phonebook/tools/fake_class.dart @@ -44,7 +44,8 @@ List fakeMembersList = [ firstname: 'Michel', nickname: 'Testouille', id: '1', - email: 'test1@useless'), + email: 'test1@useless', + promotion: 'E21'), memberships: [Membership(association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[0]], apparentName: 'Prez\'')]), CompleteMember( member: Member( @@ -52,7 +53,8 @@ List fakeMembersList = [ firstname: 'Frank', nickname: 'Chad', id: '2', - email: 'test2@useless'), + email: 'test2@useless', + promotion: 'E22'), memberships: [Membership(association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[1]], apparentName: 'Trez\'')]), CompleteMember( member: Member( @@ -60,7 +62,8 @@ List fakeMembersList = [ firstname: 'Pascal', nickname: 'Salut', id: '3', - email: 'test3@useless'), + email: 'test3@useless', + promotion: 'E21'), memberships: [Membership(association: fakeAssociations[1], rolesTags: [fakeRolesTags.tags[2]], apparentName: 'SG')]), CompleteMember( member: Member( @@ -68,7 +71,8 @@ List fakeMembersList = [ firstname: 'Jean-Luc', nickname: 'Cascouille', id: '4', - email: 'test4@useless'), + email: 'test4@useless', + promotion: 'E20'), memberships: [ Membership(association: fakeAssociations[1], rolesTags: [fakeRolesTags.tags[0]], apparentName: 'Prez\''), Membership(association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[4]], apparentName: 'VP sponsor'), @@ -79,7 +83,8 @@ List fakeMembersList = [ firstname: 'Jean', nickname: 'Jean', id: '5', - email: 'test5@useless'), + email: 'test5@useless', + promotion: 'E20'), memberships: [Membership(association: fakeAssociations[1], rolesTags: [], apparentName: 'VP Emprunt')]), CompleteMember( member: Member( @@ -87,7 +92,8 @@ List fakeMembersList = [ firstname: 'François', nickname: 'Zarzou', id: '6', - email: 'test6@useless'), + email: 'test6@useless', + promotion: 'E21'), memberships: [ Membership(association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[3]], apparentName: 'VP com'), Membership(association: fakeAssociations[0], rolesTags: [], apparentName: 'VP Event')]), diff --git a/lib/phonebook/ui/pages/association_creation_page/kind_chip.dart b/lib/phonebook/ui/kind_chip.dart similarity index 100% rename from lib/phonebook/ui/pages/association_creation_page/kind_chip.dart rename to lib/phonebook/ui/kind_chip.dart diff --git a/lib/phonebook/ui/page_switcher.dart b/lib/phonebook/ui/page_switcher.dart index dc9fbf5f8..309452d66 100644 --- a/lib/phonebook/ui/page_switcher.dart +++ b/lib/phonebook/ui/page_switcher.dart @@ -7,8 +7,7 @@ import 'package:myecl/phonebook/ui/pages/association_editor_page/association_edi import 'package:myecl/phonebook/ui/pages/association_page/association_page.dart'; import 'package:myecl/phonebook/ui/pages/main_page/main_page.dart'; import 'package:myecl/phonebook/ui/pages/member_detail_page/member_detail_page.dart'; -import 'package:myecl/phonebook/ui/pages/role_member_page/role_member_page.dart'; -import 'package:myecl/phonebook/ui/pages/role_page/role_page.dart'; +import 'package:myecl/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart'; class PageSwitcher extends ConsumerWidget { const PageSwitcher({Key? key}) : super(key: key); @@ -23,16 +22,14 @@ class PageSwitcher extends ConsumerWidget { return const AdminPage(); case PhonebookPage.memberDetail: return const MemberDetailPage(); - case PhonebookPage.addEditRoleMember: - return const RoleMemberPage(); - case PhonebookPage.editRole: - return const RolePage(); case PhonebookPage.associationEditor: return const AssociationEditorPage(); case PhonebookPage.associationPage: return const AssociationPage(); case PhonebookPage.associationCreation: return const AssociationCreationPage(); + case PhonebookPage.membershipEdition: + return const MembershipEditorPage(); default: return const Text('Unknown page'); } diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 92a25c9fd..449d2cc44 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -1,13 +1,15 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/providers/association_kind_provider.dart'; +import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; -import 'package:myecl/phonebook/providers/filtered_association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/phonebook/ui/kind_chip.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/association_research_bar.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/editable_association_card.dart'; import 'package:myecl/tools/functions.dart'; @@ -23,62 +25,108 @@ class AdminPage extends HookConsumerWidget { final associationsNotifier = ref.watch(associationListProvider.notifier); final associations = ref.watch(associationListProvider); final roleNotifier = ref.watch(rolesTagsProvider.notifier); - final filteredAssociationListNotifier = ref.watch(filteredAssociationListProvider.notifier); + final associationKinds = ref.watch(associationKindsProvider); + final kind = useState(''); + final kindNotifier = ref.watch(associationKindProvider.notifier); + final nameFilter = ref.watch(filterProvider); void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); } return Refresher( - onRefresh: () async { - await associationsNotifier.loadAssociations(); - await roleNotifier.loadRolesTags(); - }, - child: Column( - children: - [const SizedBox(width: 10), - const AssociationResearchBar(), + onRefresh: () async { + await associationsNotifier.loadAssociations(); + await roleNotifier.loadRolesTags(); + }, + child: Column(children: [ const SizedBox(width: 10), + associationKinds.when( + data: (data) { + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row(children: [ + KindChip( + label: "Toutes", + selected: kind.value == "", + onTap: () { + kind.value = ""; + kindNotifier.setKind(""); + associationsNotifier.filterAssociationList(nameFilter, kind.value); + }), + ...data.kinds + .map((e) => KindChip( + label: e, + selected: kind.value == e, + onTap: () { + kind.value = e; + kindNotifier.setKind(e); + associationsNotifier.filterAssociationList(nameFilter, kind.value); + })) + .toList() + ] + ) + ); + }, + error: (error, stackTrace) => + const Text(PhonebookTextConstants.errorRoleTagsLoading), + loading: () => const CircularProgressIndicator()), + const SizedBox(height: 10), + const AssociationResearchBar(), + const SizedBox(height: 10), Column( children: [ - GestureDetector( - onTap: () { - pageNotifier.setPhonebookPage(PhonebookPage.associationCreation); - }, - child: Container( + GestureDetector( + onTap: () { + pageNotifier + .setPhonebookPage(PhonebookPage.associationCreation); + }, + child: Container( decoration: BoxDecoration( border: Border.all(color: Colors.black), borderRadius: const BorderRadius.all(Radius.circular(20)), ), height: 58, margin: const EdgeInsets.all(10), - child: Row(children: const [Spacer(), Icon(Icons.add), Spacer()]) - ), - ), - ...associations.when( - data: (associations) { - return associations.map((association) => EditableAssociationCard( - association: association, - onEdit: () { - associationNotifier.setAssociation(association); - pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); + child: Row( + children: const [Spacer(), Icon(Icons.add), Spacer()])), + ), + ...associations.when( + data: (associations) { + return associations + .map((association) => EditableAssociationCard( + association: association, + onEdit: () { + associationNotifier.setAssociation(association); + pageNotifier.setPhonebookPage( + PhonebookPage.associationEditor); + }, + onDelete: () async { + final result = await associationsNotifier + .deleteAssociation(association); + if (result) { + displayToastWithContext( + TypeMsg.msg, + PhonebookTextConstants + .deletedAssociation); + } else { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.deletingError); + } + associationsNotifier.loadAssociations(); + }, + )) + .toList(); }, - onDelete: () async { - final result = await associationsNotifier.deleteAssociation(association); - if (result) { - displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.deletedAssociation); - } else { - displayToastWithContext(TypeMsg.error, PhonebookTextConstants.deletingError); - } - associationsNotifier.loadAssociations(); - - },) - ).toList();}, - loading: () => const [Center(child: CircularProgressIndicator())], - error: (error, stack) => [const Center(child: Text(PhonebookTextConstants.errorLoadAssociationList))]) - ],), - ]) - - ); + loading: () => + const [Center(child: CircularProgressIndicator())], + error: (error, stack) => [ + const Center( + child: Text(PhonebookTextConstants + .errorLoadAssociationList)) + ]) + ], + ), + ])); } } diff --git a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart index 684db09be..b956a2334 100644 --- a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart +++ b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; @@ -14,6 +15,7 @@ class AssociationResearchBar extends HookConsumerWidget { final editingController = useTextEditingController(); final filterNotifier = ref.watch(filterProvider.notifier); final associationsNotifier = ref.watch(associationListProvider.notifier); + final associationKind = ref.watch(associationKindProvider); return Container( decoration: BoxDecoration( @@ -32,7 +34,8 @@ class AssociationResearchBar extends HookConsumerWidget { width: 300, child: TextField( onChanged: (value) async { - associationsNotifier.filterAssociationList(value); + associationsNotifier.filterAssociationList(value, associationKind); + filterNotifier.setFilter(value); }, focusNode: focusNode, controller: editingController, diff --git a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart index 9d7140ab2..0ecc7a1e6 100644 --- a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart +++ b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart @@ -8,7 +8,7 @@ import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/ui/pages/association_creation_page/kind_chip.dart'; +import 'package:myecl/phonebook/ui/kind_chip.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index a3bef140f..1145519c3 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -2,17 +2,21 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; +import 'package:myecl/phonebook/providers/complete_member_provider.dart'; +import 'package:myecl/phonebook/providers/edition_provider.dart'; import 'package:myecl/phonebook/providers/member_provider.dart'; import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; +import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/ui/pages/association_creation_page/kind_chip.dart'; +import 'package:myecl/phonebook/ui/kind_chip.dart'; import 'package:myecl/phonebook/ui/pages/association_editor_page/member_editable_card.dart'; -import 'package:myecl/phonebook/ui/pages/association_editor_page/membership_dialog.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; @@ -32,14 +36,14 @@ class AssociationEditorPage extends HookConsumerWidget { final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); final associationListNotifier = ref.watch(associationListProvider.notifier); - final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationKinds = ref.watch(associationKindsProvider); final kind = useState(association.kind); final name = useTextEditingController(text: association.name); final description = useTextEditingController(text: association.description); - final controller = TextEditingController(); - final member = ref.watch(memberProvider); - final memberRoleTags = ref.watch(memberRolesTagsProvider); + final rolesTagsNotifier = ref.watch(rolesTagsProvider.notifier); + final editionNotifier = ref.watch(editionProvider.notifier); + final completeMemberNotifier = ref.watch(completeMemberProvider.notifier); + final pageNotifier = ref.watch(phonebookPageProvider.notifier); void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); @@ -285,35 +289,10 @@ class AssociationEditorPage extends HookConsumerWidget { const Spacer(), ShrinkButton( onTap: () async { - await tokenExpireWrapper(ref, () async { - showDialog( - context: context, - builder: (BuildContext context) { - return MembershipDialog( - apparentNameController: controller, - title: PhonebookTextConstants.addMember, - defaultText: "", - onConfirm: () async { - debugPrint( - "assciation: $association,\n member: ${member.toString()},\n memberRoleTags: $memberRoleTags,\n controller: ${controller.text}"); - final value = - await associationNotifier.addMember( - association, - member, - memberRoleTags, - controller.text); - if (value) { - associationMemberListNotifier - .loadMembers(association.id); - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.addedMember); - } else { - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.addingError); - } - }); - }); - }); + rolesTagsNotifier.resetChecked(); + completeMemberNotifier.setCompleteMember(CompleteMember.empty()); + editionNotifier.setStatus(false); + pageNotifier.setPhonebookPage(PhonebookPage.membershipEdition); }, child: Container( width: 40, @@ -350,6 +329,104 @@ class AssociationEditorPage extends HookConsumerWidget { ), const SizedBox( height: 10, + ), + ShrinkButton( + waitChild: Container( + width: double.infinity, + margin: const EdgeInsets.all(30), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), + ], + borderRadius: BorderRadius.circular(15), + ), + child: const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + color: Colors.white, + ), + ), + ), + onTap: () async { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text(PhonebookTextConstants.newMandate), + content: const Text(PhonebookTextConstants.changeMandateConfirm), + actions: [ + TextButton( + onPressed: () { + Navigator.pop(context); + }, + child: const Text(PhonebookTextConstants.cancel), + ), + TextButton( + onPressed: () async { + Navigator.pop(context); + await tokenExpireWrapper(ref, () async { + final value = await associationListNotifier + .updateAssociation(association.copyWith( + mandateYear: (int.parse(association.mandateYear)+1).toString())); + if (value) { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.newMandateConfirmed); + } else { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.mandateChangingError); + } + }); + }, + child: const Text(PhonebookTextConstants.validation), + ), + ], + ), + ); + }, + child: Container( + width: double.infinity, + margin: const EdgeInsets.all(30), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), + ], + borderRadius: BorderRadius.circular(15), + ), + child: Text( + "${PhonebookTextConstants.changeMandate} ${(int.parse(association.mandateYear)+1).toString()}", + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), + ), + ), + ), ) ]), ); diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index e2ffadeda..a013a36d9 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -3,10 +3,13 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/providers/complete_member_provider.dart'; +import 'package:myecl/phonebook/providers/edition_provider.dart'; import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; +import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/ui/delete_button.dart'; import 'package:myecl/phonebook/ui/edition_button.dart'; -import 'package:myecl/phonebook/ui/pages/association_editor_page/membership_dialog.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/user/providers/profile_picture_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; @@ -21,10 +24,12 @@ class MemberEditableCard extends HookConsumerWidget { final profilePicture = ref.watch(profilePictureProvider); final association = ref.watch(associationProvider); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); - final controller = TextEditingController(); final associationMembersNotifier = ref.watch(associationMemberListProvider.notifier); - final memberRoleTags = ref.watch(memberRolesTagsProvider); + final roleTagsNotifier = ref.watch(rolesTagsProvider.notifier); + final editionNotifier = ref.watch(editionProvider.notifier); + final completeMemberNotifier = ref.watch(completeMemberProvider.notifier); + final pageNotifier = ref.watch(phonebookPageProvider.notifier); void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); @@ -108,33 +113,11 @@ class MemberEditableCard extends HookConsumerWidget { )), const Spacer(), EditionButton(onEdition: () async { - showDialog( - context: context, - builder: (BuildContext context) { - return MembershipDialog( - apparentNameController: controller, - title: PhonebookTextConstants.editMembership, - defaultText: member.memberships - .firstWhere((element) => - element.association.id == association.id) - .apparentName, - onConfirm: () async { - final result = await associationNotifier.updateMember( - association, - member.toMember(), - memberRoleTags, - controller.text); - if (result) { - await associationMembersNotifier - .loadMembers(association.id); - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.updatedMember); - } else { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.updatingError); - } - }); - }); + roleTagsNotifier.resetChecked(); + roleTagsNotifier.loadRoleTagsFromMember(member, association); + completeMemberNotifier.setCompleteMember(member); + editionNotifier.setStatus(true); + pageNotifier.setPhonebookPage(PhonebookPage.membershipEdition); }), const SizedBox(width: 10), DeleteButton( diff --git a/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart b/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart index a334d899e..44cd55a69 100644 --- a/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart +++ b/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart @@ -1,14 +1,17 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/roles_tags.dart'; import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/ui/pages/association_editor_page/search_result.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:myecl/user/providers/user_list_provider.dart'; import 'package:tuple/tuple.dart'; +import 'package:myecl/phonebook/ui/pages/membership_editor_page/search_result.dart'; + class MembershipDialog extends HookConsumerWidget { const MembershipDialog({ @@ -17,12 +20,16 @@ class MembershipDialog extends HookConsumerWidget { required this.title, required this.defaultText, required this.onConfirm, + required this.member, + required this.association }) : super(key: key); final String title; final String defaultText; final VoidCallback onConfirm; final TextEditingController apparentNameController; + final CompleteMember member; + final Association association; String nameConstructor(Tuple2> data) { String name = ''; @@ -43,10 +50,9 @@ class MembershipDialog extends HookConsumerWidget { final apparentName = useState(defaultText); final queryController = useTextEditingController(text: ''); final usersNotifier = ref.watch(userList.notifier); - final memberRoleTagsNotifier = ref.watch(memberRolesTagsProvider.notifier); + final memberRoleTagsNotifier = ref.watch(memberRoleTagsProvider.notifier); final rolesTagsNotifier = ref.watch(rolesTagsProvider.notifier); - List checked = []; apparentNameController.text = apparentName.value; return AlertDialog( title: Center( @@ -61,35 +67,44 @@ class MembershipDialog extends HookConsumerWidget { child: SingleChildScrollView( child: Column( children: [ - TextFormField( - onChanged: (value) { - tokenExpireWrapper(ref, () async { - if (queryController.text.isNotEmpty) { - await usersNotifier.filterUsers(queryController.text); - } else { - usersNotifier.clear(); - } - }); - }, - cursorColor: Colors.black, - controller: queryController, - decoration: const InputDecoration( - labelText: PhonebookTextConstants.member, - floatingLabelStyle: TextStyle( - color: Colors.black, - fontWeight: FontWeight.bold, - ), - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide(color: Colors.black, width: 2.0), + if (member.member.id == "") + TextFormField( + enabled: member.member.id == "", + onChanged: (value) { + tokenExpireWrapper(ref, () async { + if (queryController.text.isNotEmpty) { + await usersNotifier.filterUsers(queryController.text); + } else { + usersNotifier.clear(); + } + }); + }, + cursorColor: Colors.black, + controller: queryController, + decoration: const InputDecoration( + labelText: PhonebookTextConstants.member, + floatingLabelStyle: TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + ), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.black, width: 2.0), + ), ), ), - ), - const SizedBox( - height: 10, - ), - SearchResult(queryController: queryController), + const SizedBox( + height: 10, + ), + SearchResult(queryController: queryController), ...rolesTags.when( data: (data) { + if (member.member.id != "") { + for (int i = 0; i < data.item2.length; i++) { + if (member.memberships.where((e) => e.association.id == association.id).toList()[0].rolesTags.contains(data.item1.tags[i])) { + data.item2[i] = true; + } + } + } return data.item1.tags .map((e) => Row(children: [ Text(e), @@ -98,9 +113,8 @@ class MembershipDialog extends HookConsumerWidget { value: data.item2[data.item1.tags.indexOf(e)], fillColor: MaterialStateProperty.all(Colors.black), onChanged: (value) { - checked = data.item2; - checked[data.item1.tags.indexOf(e)] = value!; - debugPrint(checked.toString()); + data.item2[data.item1.tags.indexOf(e)] = value!; + debugPrint(data.item2.toString()); apparentName.value = nameConstructor(data); apparentNameController.text = apparentName.value; memberRoleTagsNotifier diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index 8a2060439..1b86c5220 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -79,6 +79,11 @@ class AssociationPage extends HookConsumerWidget { association.description, style: const TextStyle(fontSize: 15, color: Colors.black), ), + const SizedBox(height: 10), + Text( + "${PhonebookTextConstants.activeMandate} ${association.mandateYear}", + style: const TextStyle(fontSize: 15, color: Colors.black), + ), const SizedBox( height: 20, ), @@ -97,11 +102,6 @@ class AssociationPage extends HookConsumerWidget { error: (e, s) { return const Center( child: Text(PhonebookTextConstants.errorLoadAssociationMember), - // List fakeMembers = [CompleteMember.empty()]; - // return Column( - // children: fakeMembers.map((member) => - // MemberCard(member: member) - // ).toList() ); }, ) diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index bd4839f3b..8b4c47508 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -1,15 +1,18 @@ import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; -import 'package:myecl/phonebook/providers/filtered_association_list_provider.dart'; +import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/admin/providers/is_admin.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/ui/association_card.dart'; +import 'package:myecl/phonebook/ui/kind_chip.dart'; import 'package:myecl/phonebook/ui/pages/main_page/research_bar.dart'; import 'package:myecl/tools/ui/refresher.dart'; @@ -22,12 +25,14 @@ class MainPage extends HookConsumerWidget { final pageNotifier = ref.watch(phonebookPageProvider.notifier); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationListNotifier = ref.watch(associationListProvider.notifier); - final filteredAssociationListNotifier = - ref.watch(filteredAssociationListProvider.notifier); final associationList = ref.watch(associationListProvider); final associationKindsNotifier = ref.watch(associationKindsProvider.notifier); final rolesTagsNotifier = ref.watch(rolesTagsProvider.notifier); + final associationKinds = ref.watch(associationKindsProvider); + final kind = useState(''); + final kindNotifier = ref.watch(associationKindProvider.notifier); + final nameFilter = ref.watch(filterProvider); return Stack( children: [ @@ -36,35 +41,64 @@ class MainPage extends HookConsumerWidget { await rolesTagsNotifier.loadRolesTags(); await associationKindsNotifier.loadAssociationKinds(); await associationListNotifier.loadAssociations(); - await filteredAssociationListNotifier.loadAssociations(); }, child: Column( children: [ - const SizedBox(height: 70), - const ResearchBar(), - const SizedBox(width: 10), - ] + - associationList.when( - data: (associations) { - return associations - .map((association) => AssociationCard( - association: association, - onClicked: () { - associationNotifier - .setAssociation(association); - pageNotifier.setPhonebookPage( - PhonebookPage.associationPage); - }, - )) - .toList(); - }, - loading: () => - const [Center(child: CircularProgressIndicator())], - error: (error, stack) => [ - const Center( - child: Text(PhonebookTextConstants - .errorLoadAssociationList)) - ]))), + const SizedBox(height: 70), + associationKinds.when( + data: (data) { + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row(children: [ + KindChip( + label: "Toutes", + selected: kind.value == "", + onTap: () { + kind.value = ""; + kindNotifier.setKind(""); + associationListNotifier.filterAssociationList(nameFilter, kind.value); + }), + ...data.kinds + .map((e) => KindChip( + label: e, + selected: kind.value == e, + onTap: () { + kind.value = e; + kindNotifier.setKind(e); + associationListNotifier.filterAssociationList(nameFilter, kind.value); + })) + .toList() + ] + ) + ); + }, + error: (error, stackTrace) => + const Text(PhonebookTextConstants.errorRoleTagsLoading), + loading: () => const CircularProgressIndicator()), + const SizedBox(height: 30), + const ResearchBar(), + const SizedBox(height: 10), + ...associationList.when( + data: (associations) { + return associations + .map((association) => AssociationCard( + association: association, + onClicked: () { + associationNotifier + .setAssociation(association); + pageNotifier.setPhonebookPage( + PhonebookPage.associationPage); + }, + )) + .toList(); + }, + loading: () => + const [Center(child: CircularProgressIndicator())], + error: (error, stack) => [ + const Center( + child: Text(PhonebookTextConstants + .errorLoadAssociationList)) + ])])), if (isAdmin) Positioned( top: 15, diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart index 171d4c84e..22c5b891c 100644 --- a/lib/phonebook/ui/pages/main_page/research_bar.dart +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; @@ -13,7 +14,9 @@ class ResearchBar extends HookConsumerWidget { final focusNode = useFocusNode(); final editingController = useTextEditingController(); final filterNotifier = ref.watch(filterProvider.notifier); - + final associationsNotifier = ref.watch(associationListProvider.notifier); + final associationKind = ref.watch(associationKindProvider); + return Container( decoration: BoxDecoration( border: Border.all(), @@ -31,7 +34,8 @@ class ResearchBar extends HookConsumerWidget { width: 300, child: TextField( onChanged: (value) { - associationsNotifier.filterAssociationList(value); + associationsNotifier.filterAssociationList(value, associationKind); + filterNotifier.setFilter(value); }, focusNode: focusNode, controller: editingController, diff --git a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart index 25bd5c57d..8ec32b0d6 100644 --- a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart +++ b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart @@ -13,8 +13,7 @@ class MemberDetailPage extends HookConsumerWidget { margin: const EdgeInsets.all(10), width: MediaQuery.of(context).size.width, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(50), - color: const Color.fromARGB(255, 187, 187, 187)), + borderRadius: BorderRadius.circular(50)), child: Column(children: [ const Text(PhonebookTextConstants.detail), Text("${PhonebookTextConstants.name} ${memberProvider.member.name}"), @@ -23,6 +22,7 @@ class MemberDetailPage extends HookConsumerWidget { if (memberProvider.member.nickname != null) Text( "${PhonebookTextConstants.nickname} ${memberProvider.member.nickname!}"), + Text("${PhonebookTextConstants.promotion} ${memberProvider.member.promotion}"), Text( "${PhonebookTextConstants.email} ${memberProvider.member.email}"), const Text(PhonebookTextConstants @@ -31,15 +31,10 @@ class MemberDetailPage extends HookConsumerWidget { for (var membership in memberProvider.memberships) Container( margin: const EdgeInsets.all(10), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(50), - border: Border.all(), - color: const Color.fromARGB(255, 187, 187, 187)), child: Row( children: [ const Spacer(flex: 1), - Text("${membership.association.name} : ${membership.apparentName}", - style: const TextStyle(fontSize: 20)), + Text("${membership.association.name} : ${membership.apparentName}"), const Spacer(flex: 1), ])) ]), diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart new file mode 100644 index 000000000..6faa4859f --- /dev/null +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -0,0 +1,205 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/roles_tags.dart'; +import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; +import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/providers/edition_provider.dart'; +import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; +import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/tools/functions.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; +import 'package:myecl/tools/ui/shrink_button.dart'; +import 'package:myecl/user/providers/user_list_provider.dart'; +import 'package:tuple/tuple.dart'; +import 'package:myecl/phonebook/providers/complete_member_provider.dart'; +import 'package:myecl/phonebook/ui/pages/membership_editor_page/search_result.dart'; + +class MembershipEditorPage extends HookConsumerWidget { + const MembershipEditorPage({ + Key? key, + }) : super(key: key); + + + + String nameConstructor(Tuple2> data) { + String name = ''; + for (int i = 0; i < data.item2.length; i++) { + if (data.item2[i]) { + name = "$name, ${data.item1.tags[i]}"; + } + } + if (name == "") { + return ""; + } + return name.substring(1, name.length); + } + + List setRoleTagsWithFilter(Tuple2> data) { + List roleTags = []; + for (int i = 0; i < data.item2.length; i++) { + if (data.item2[i]) { + roleTags.add(data.item1.tags[i]); + } + } + return roleTags; + } + + @override + Widget build(BuildContext context, WidgetRef ref) { + final rolesTags = ref.watch(rolesTagsProvider); + final queryController = useTextEditingController(text: ''); + final usersNotifier = ref.watch(userList.notifier); + final rolesTagsNotifier = ref.watch(rolesTagsProvider.notifier); + final apparentNameController = useTextEditingController(text: ''); + final member = ref.watch(completeMemberProvider); + final association = ref.watch(associationProvider); + final edition = ref.watch(editionProvider); + final associationNotifier = ref.watch(asyncAssociationProvider.notifier); + final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); + final pageNotifier = ref.watch(phonebookPageProvider.notifier); + final memberRoleTagsNotifier = ref.watch(memberRoleTagsProvider.notifier); + final memberRoleTags = ref.watch(memberRoleTagsProvider); + + void displayToastWithContext(TypeMsg type, String msg) { + displayToast(context, type, msg); + } + + if (edition){ + apparentNameController.text = member.memberships.where((e) => e.association.id == association.id).toList()[0].apparentName; + } + + return Padding( + padding: const EdgeInsets.all(20.0), + child: SingleChildScrollView( + child : Column( + children : [ + Center( + child: Container( + decoration: const BoxDecoration( + border: Border(bottom: BorderSide(color: Colors.black)), + color: Colors.white, + ), + child: Text( + edition? PhonebookTextConstants.editMembership : PhonebookTextConstants.addMember, + style: const TextStyle(fontSize: 20) + ) + ) + ), + if (!edition) + TextFormField( + onChanged: (value) { + tokenExpireWrapper(ref, () async { + if (queryController.text.isNotEmpty) { + await usersNotifier.filterUsers(queryController.text); + } else { + usersNotifier.clear(); + } + }); + }, + cursorColor: Colors.black, + controller: queryController, + decoration: const InputDecoration( + labelText: PhonebookTextConstants.member, + floatingLabelStyle: TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + ), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.black, width: 2.0), + ), + ), + ), + const SizedBox( + height: 10, + ), + SearchResult(queryController: queryController), + SizedBox( + width: min(MediaQuery.of(context).size.width, 300), + child: Column(children: [ + ...rolesTags.when( + data: (data) { + return data.item1.tags + .map((e) => Row(children: [ + Text(e), + const Spacer(), + Checkbox( + value: data.item2[data.item1.tags.indexOf(e)], + fillColor: MaterialStateProperty.all(Colors.black), + onChanged: (value) { + data.item2[data.item1.tags.indexOf(e)] = value!; + debugPrint(data.item2.toString()); + apparentNameController.text = nameConstructor(data); + memberRoleTagsNotifier.setRoleTagsWithFilter(data); + rolesTagsNotifier.setChecked(data.item1.tags.indexOf(e), value); + }, + ), + ])) + .toList(); + }, + error: (e, s) => [const Text('Error')], + loading: () => [const Text('Loading')], + ), + ]), + ), + const SizedBox(height: 5), + const Text(PhonebookTextConstants.apparentName), + TextField( + controller: apparentNameController, + ), + const SizedBox(height: 5), + ShrinkButton( + child: Text(!edition ? PhonebookTextConstants.add : PhonebookTextConstants.edit), + onTap: () async { + if (member.member.id == "") { + displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.emptyMember); + return; + } + if (apparentNameController.text == "") { + displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.emptyApparentName); + return; + } + debugPrint("Appui sur le bouton avec les paramètres:\n" + "association: $association\n" + "member: ${member.member}\n" + "rolesTags: $memberRoleTags\n" + "apparentName: ${apparentNameController.text}"); + tokenExpireWrapper(ref, () async { + if (edition) { + final value = await associationNotifier.updateMember(association, member.member, memberRoleTags, apparentNameController.text); + if (value) { + associationMemberListNotifier + .loadMembers(association.id); + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.updatedMember); + pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); + } else { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.updatingError); + } + } else { + final value = await associationNotifier.addMember(association, member.member, memberRoleTags, apparentNameController.text); + if (value) { + associationMemberListNotifier + .loadMembers(association.id); + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.addedMember); + pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); + } else { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.addingError); + } + } + }); + }, + ), + ], + ) + ) + ); + } +} diff --git a/lib/phonebook/ui/pages/association_editor_page/search_result.dart b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart similarity index 91% rename from lib/phonebook/ui/pages/association_editor_page/search_result.dart rename to lib/phonebook/ui/pages/membership_editor_page/search_result.dart index eebc4aaa6..dcbc09525 100644 --- a/lib/phonebook/ui/pages/association_editor_page/search_result.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/member.dart'; -import 'package:myecl/phonebook/providers/member_provider.dart'; +import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/user/providers/user_list_provider.dart'; class SearchResult extends HookConsumerWidget { @@ -13,8 +13,8 @@ class SearchResult extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final users = ref.watch(userList); final usersNotifier = ref.watch(userList.notifier); - final memberNotifier = ref.watch(memberProvider.notifier); - final member = ref.watch(memberProvider); + final memberNotifier = ref.watch(completeMemberProvider.notifier); + final member = ref.watch(completeMemberProvider); return users.when( data: (u) { diff --git a/lib/phonebook/ui/pages/role_member_page/role_member_page.dart b/lib/phonebook/ui/pages/role_member_page/role_member_page.dart deleted file mode 100644 index e3fe2006d..000000000 --- a/lib/phonebook/ui/pages/role_member_page/role_member_page.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; - -class RoleMemberPage extends HookConsumerWidget { - const RoleMemberPage({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context, WidgetRef ref) { - return const SizedBox(); - } -} \ No newline at end of file diff --git a/lib/phonebook/ui/pages/role_page/role_page.dart b/lib/phonebook/ui/pages/role_page/role_page.dart deleted file mode 100644 index e70820d1c..000000000 --- a/lib/phonebook/ui/pages/role_page/role_page.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; - -class RolePage extends HookConsumerWidget { - const RolePage({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context, WidgetRef ref) { - return const Text('RolePage'); - } -} \ No newline at end of file diff --git a/lib/phonebook/ui/phonebook.dart b/lib/phonebook/ui/phonebook.dart index af7f38a32..18dbdb4b2 100644 --- a/lib/phonebook/ui/phonebook.dart +++ b/lib/phonebook/ui/phonebook.dart @@ -33,12 +33,6 @@ class PhonebookHomePage extends HookConsumerWidget { case PhonebookPage.admin: pageNotifier.setPhonebookPage(PhonebookPage.main); break; - case PhonebookPage.addEditRoleMember: - pageNotifier.setPhonebookPage(PhonebookPage.memberDetail); - break; - case PhonebookPage.editRole: - pageNotifier.setPhonebookPage(PhonebookPage.admin); - break; case PhonebookPage.associationEditor: pageNotifier.setPhonebookPage(PhonebookPage.admin); break; @@ -48,6 +42,9 @@ class PhonebookHomePage extends HookConsumerWidget { case PhonebookPage.associationCreation: pageNotifier.setPhonebookPage(PhonebookPage.admin); break; + case PhonebookPage.membershipEdition: + pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); + break; } return false; }, diff --git a/lib/phonebook/ui/top_bar.dart b/lib/phonebook/ui/top_bar.dart index 6d52d82d4..4ab40982b 100644 --- a/lib/phonebook/ui/top_bar.dart +++ b/lib/phonebook/ui/top_bar.dart @@ -37,12 +37,6 @@ class TopBar extends HookConsumerWidget { case PhonebookPage.admin: pageNotifier.setPhonebookPage(PhonebookPage.main); break; - case PhonebookPage.addEditRoleMember: - pageNotifier.setPhonebookPage(PhonebookPage.memberDetail); - break; - case PhonebookPage.editRole: - pageNotifier.setPhonebookPage(PhonebookPage.admin); - break; case PhonebookPage.associationEditor: pageNotifier.setPhonebookPage(PhonebookPage.admin); break; @@ -52,6 +46,9 @@ class TopBar extends HookConsumerWidget { case PhonebookPage.associationCreation: pageNotifier.setPhonebookPage(PhonebookPage.admin); break; + case PhonebookPage.membershipEdition: + pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); + break; } }, icon: HeroIcon( From 7fce6d22c83c491ee8464954c50a9c853f2c348c Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:01 +0100 Subject: [PATCH 016/123] Change repositories to back system --- .../association_kind_repository.dart | 4 +- .../association_member_repository.dart | 6 +- .../repositories/association_repository.dart | 113 +++++++++--------- .../repositories/role_tags_repository.dart | 6 +- 4 files changed, 66 insertions(+), 63 deletions(-) diff --git a/lib/phonebook/repositories/association_kind_repository.dart b/lib/phonebook/repositories/association_kind_repository.dart index 44eebe655..9df42a20e 100644 --- a/lib/phonebook/repositories/association_kind_repository.dart +++ b/lib/phonebook/repositories/association_kind_repository.dart @@ -8,7 +8,7 @@ class AssociationKindsRepository extends Repository { final ext = "phonebook/associations"; Future getAssociationKinds() async { - return fakeAssociationKinds ; - // return AssociationKinds.fromJSON(await getOne("kinds")); + // return fakeAssociationKinds ; + return AssociationKinds.fromJSON(await getOne("kinds")); } } \ No newline at end of file diff --git a/lib/phonebook/repositories/association_member_repository.dart b/lib/phonebook/repositories/association_member_repository.dart index a0b14c877..d98bcf166 100644 --- a/lib/phonebook/repositories/association_member_repository.dart +++ b/lib/phonebook/repositories/association_member_repository.dart @@ -8,8 +8,8 @@ class AssociationMemberRepository extends Repository { final ext = "phonebook/associations/"; Future> getAssociationMemberList(String associationId) async { - return fakeMembersList.where((element) => element.memberships.map((e) => e.association.id).contains(associationId)).toList(); - //return List.from( - // (await getList(suffix: "$associationId/members")).map((x) => CompleteMember.fromJSON(x))); + // return fakeMembersList.where((element) => element.memberships.map((e) => e.association.id).contains(associationId)).toList(); + return List.from( + (await getList(suffix: "$associationId/members")).map((x) => CompleteMember.fromJSON(x))); } } \ No newline at end of file diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index 7e8653c57..879df4379 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -1,9 +1,12 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/member.dart'; import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/tools/fake_class.dart'; +import 'package:myecl/tools/exception.dart'; import 'package:myecl/tools/repository/repository.dart'; class AssociationRepository extends Repository { @@ -12,83 +15,83 @@ class AssociationRepository extends Repository { final ext = "phonebook/associations/"; Future> getAssociationList() async { - return fakeAssociations; - //return List.from( - // (await getList()).map((x) => Association.fromJSON(x))); + // return fakeAssociations; + return List.from( + (await getList()).map((x) => Association.fromJSON(x))); } Future getAssociation(String associationId) async { - return fakeAssociations.firstWhere((element) => element.id == associationId); - //return Association.fromJSON(await getOne(associationId)); + // return fakeAssociations.firstWhere((element) => element.id == associationId); + return Association.fromJSON(await getOne(associationId)); } Future deleteAssociation(String associationId) async { //fakeAssociations.removeWhere((element) => element.id == associationId); - return true; - //return await delete(associationId); + // return true; + return await delete(associationId); } Future updateAssociation(Association association) async { //fakeAssociations[fakeAssociations.indexWhere((element) => element.id == association.id)] = association; - return true; - //return await update(association.toJSON(), association.id); + // return true; + return await update(association.toJSON(), association.id); } Future createAssociation(Association association) async { - List ids = fakeAssociations.map((e) => e.id).toList(); - String newId = "1"; - while (ids.contains(newId)) { - newId = (int.parse(newId) + 1).toString(); - } - association = association.copyWith(id: newId); - return association; - //return Association.fromJSON(await create(association.toJSON())); + // List ids = fakeAssociations.map((e) => e.id).toList(); + // String newId = "1"; + // while (ids.contains(newId)) { + // newId = (int.parse(newId) + 1).toString(); + // } + // association = association.copyWith(id: newId); + // return association; + return Association.fromJSON(await create(association.toJSON())); } Future addMember(Association association, Member member, List rolesTags, String apparentName) async { - if (fakeMembersList.indexWhere((element) => element.member.id == member.id) == -1) { - fakeMembersList.add(CompleteMember(member: member, memberships: [])); - } - if (fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.id)] - .memberships - .indexWhere((element) => element.association.id == association.id) != - -1) { - return false; - } - fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.id)] - .memberships - .add(Membership(association: association, rolesTags: rolesTags, apparentName: apparentName)); - //await create({"member_id": member.id, "association_id": association.id, "rolesTags": rolesTags, "apparentName": apparentName"}, - // suffix: "membership"); - return true; + // if (fakeMembersList.indexWhere((element) => element.member.id == member.id) == -1) { + // fakeMembersList.add(CompleteMember(member: member, memberships: [])); + // } + // if (fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.id)] + // .memberships + // .indexWhere((element) => element.association.id == association.id) != + // -1) { + // return false; + // } + // fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.id)] + // .memberships + // .add(Membership(association: association, rolesTags: rolesTags, apparentName: apparentName)); + return await create({"member_id": member.id, "association_id": association.id, "rolesTags": rolesTags, "apparentName": apparentName}, + suffix: "membership"); + // return true; } Future deleteMember(Association association, CompleteMember member) async { - fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.member.id)] - .memberships - .removeWhere((element) => element.association.id == association.id); - return true; - //final response = await http.delete( - // Uri.parse("$host${ext}membership"), - // headers: headers, - // body: json.encode({"member_id": member.member.id, "association_id": association.id})); - // if (response.statusCode == 204) { - // return true; - // } else if (response.statusCode == 403) { - // throw AppException(ErrorType.tokenExpire, response.body); - // } else { - // throw AppException(ErrorType.notFound, "Failed to update item"); - // } + // fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.member.id)] + // .memberships + // .removeWhere((element) => element.association.id == association.id); + // return true; + final response = await http.delete( + Uri.parse("$host${ext}membership"), + headers: headers, + body: json.encode({"member_id": member.member.id, "association_id": association.id})); + if (response.statusCode == 204) { + return true; + } else if (response.statusCode == 403) { + throw AppException(ErrorType.tokenExpire, response.body); + } else { + throw AppException(ErrorType.notFound, "Failed to update item"); + } } Future updateMember(Association association, Member member, List rolesTags, String apparentName) async { - debugPrint("updateMember"); - fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.id)] - .memberships - .where((element) => element.association.id == association.id).toList()[0] = - Membership(association: association, rolesTags: rolesTags, apparentName: apparentName); - //await update({"member_id": member.id, "association_id": association.id, "rolesTags": rolesTags, "apparentName": apparentName"}, - // suffix: "membership"); - return true; + // debugPrint("updateMember"); + // fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.id)] + // .memberships + // .where((element) => element.association.id == association.id).toList()[0] = + // Membership(association: association, rolesTags: rolesTags, apparentName: apparentName); + return await update({"member_id": member.id, "association_id": association.id, "rolesTags": rolesTags, "apparentName": apparentName}, association.id, + suffix: "membership"); + // return true; } } diff --git a/lib/phonebook/repositories/role_tags_repository.dart b/lib/phonebook/repositories/role_tags_repository.dart index a7ab8201d..069613fd8 100644 --- a/lib/phonebook/repositories/role_tags_repository.dart +++ b/lib/phonebook/repositories/role_tags_repository.dart @@ -9,9 +9,9 @@ class RolesTagsRepository extends Repository { final ext = "phonebook/"; Future>> getRolesTags() async { - return Tuple2(fakeRolesTags,List.filled(fakeRolesTags.tags.length, false)); - // RolesTags rolesTags = RolesTags.fromJSON(await getOne("rolesTags")); - // return Tuple2(rolesTags,List.filled(rolesTags.tags.length, false)); + // return Tuple2(fakeRolesTags,List.filled(fakeRolesTags.tags.length, false)); + RolesTags rolesTags = RolesTags.fromJSON(await getOne("rolesTags")); + return Tuple2(rolesTags,List.filled(rolesTags.tags.length, false)); } } From 277767affdffcda1f34c4f3b0a1df1d230683f11 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:01 +0100 Subject: [PATCH 017/123] Change fromJSON for CompleteMember to match back --- lib/phonebook/class/complete_member.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/phonebook/class/complete_member.dart b/lib/phonebook/class/complete_member.dart index 4b97afc17..b0ce4eb20 100644 --- a/lib/phonebook/class/complete_member.dart +++ b/lib/phonebook/class/complete_member.dart @@ -12,7 +12,13 @@ class CompleteMember{ CompleteMember.fromJSON(Map json){ - member = Member.fromJSON(json['user']); + String name = json['name']; + String firstname = json['firstname']; + String nickname = json['nickname']; + String id = json['id']; + String email = json['email']; + String promotion = json['promotion']; + member = Member(name: name, firstname: firstname, nickname: nickname, id: id, email: email, promotion: promotion); memberships = json['memberships'].map((membership) => Membership.fromJSON(membership)).toList(); } From 7734641296aef71321293de6496f88ab839b5518 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:01 +0100 Subject: [PATCH 018/123] Add association picture --- .../association_picture_provider.dart | 82 +-------- .../associations_pictures_provider.dart | 32 ++++ .../providers/research_filter_provider.dart | 2 +- .../association_picture_repository.dart | 15 +- lib/phonebook/ui/association_card.dart | 174 +++++++++++------- .../admin_page/editable_association_card.dart | 95 ++++++++-- .../association_page/association_page.dart | 17 +- 7 files changed, 243 insertions(+), 174 deletions(-) create mode 100644 lib/phonebook/providers/associations_pictures_provider.dart diff --git a/lib/phonebook/providers/association_picture_provider.dart b/lib/phonebook/providers/association_picture_provider.dart index 27187f58f..a2ce9d64b 100644 --- a/lib/phonebook/providers/association_picture_provider.dart +++ b/lib/phonebook/providers/association_picture_provider.dart @@ -1,103 +1,33 @@ -import 'dart:io'; -import 'package:flutter/foundation.dart'; -import 'package:image_cropper/image_cropper.dart'; -import 'package:image_picker/image_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/repositories/association_picture_repository.dart'; -import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/providers/single_notifier.dart'; -import 'package:path_provider/path_provider.dart'; final associationPictureProvider = - StateNotifierProvider>((ref) { + StateNotifierProvider>((ref) { final token = ref.watch(tokenProvider); AssociationPictureNotifier notifier = AssociationPictureNotifier(token); return notifier; }); -class AssociationPictureNotifier extends SingleNotifier { +class AssociationPictureNotifier extends SingleNotifier { final AssociationPictureRepository associationPictureRepository = AssociationPictureRepository(); - final ImagePicker _picker = ImagePicker(); AssociationPictureNotifier(String token) : super(const AsyncLoading()) { associationPictureRepository.setToken(token); } - Future> getAssociationPicture(String associationId) async { + Future> getAssociationPicture(String associationId) async { return await load( () async => associationPictureRepository.getAssociationPicture(associationId)); } - Future setAssociationPicture(ImageSource source, String associationId) async { - final previousState = state; - state = const AsyncLoading(); - final XFile? image = - await _picker.pickImage(source: source, imageQuality: 20); - if (image != null) { - try { - final i = await associationPictureRepository.addAssociationPicture(image.path, associationId); - state = AsyncValue.data(i); - return true; - } catch (e) { - state = previousState; - return false; - } - } - state = previousState; - return null; - } - - Future cropImage(String associationId) async { - final previousState = state; - state.whenData((value) async { - Directory tempDir = await getTemporaryDirectory(); - File file = await File( - '${tempDir.path}/${DateTime.now().millisecondsSinceEpoch}.png') - .create(); - final File newImage = await file.writeAsBytes(value); - CroppedFile? croppedFile = await ImageCropper().cropImage( - sourcePath: newImage.path, - aspectRatioPresets: [ - CropAspectRatioPreset.square, - CropAspectRatioPreset.ratio3x2, - CropAspectRatioPreset.original, - CropAspectRatioPreset.ratio4x3, - CropAspectRatioPreset.ratio16x9 - ], - uiSettings: [ - AndroidUiSettings( - toolbarTitle: 'Recadrer', - toolbarColor: ColorConstants.gradient1, - toolbarWidgetColor: Colors.grey[100], - initAspectRatio: CropAspectRatioPreset.original, - lockAspectRatio: false), - IOSUiSettings( - title: 'Recadrer', - ), - ], - ); - if (croppedFile != null) { - try { - final i = await associationPictureRepository - .addAssociationPicture(croppedFile.path, associationId); - state = AsyncValue.data(i); - return true; - } catch (e) { - state = previousState; - return false; - } - } else { - state = previousState; - return null; - } - }); - state = previousState; - return null; + Future> updateAssociationPicture(String associationId, String path) async { + return await load( + () => associationPictureRepository.addAssociationPicture(path, associationId)); } } - diff --git a/lib/phonebook/providers/associations_pictures_provider.dart b/lib/phonebook/providers/associations_pictures_provider.dart new file mode 100644 index 000000000..6462b2e1c --- /dev/null +++ b/lib/phonebook/providers/associations_pictures_provider.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/providers/association_list_provider.dart'; +import 'package:myecl/tools/providers/map_provider.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; + +class AssociationPictureNotifier extends MapNotifier { + AssociationPictureNotifier() : super(); +} + +final associationPicturesProvider = StateNotifierProvider>>>>((ref) { + AssociationPictureNotifier associationPictureNotifier = + AssociationPictureNotifier(); + tokenExpireWrapperAuth(ref, () async { + ref.watch(associationListProvider).when(data: (association) { + associationPictureNotifier.loadTList(association); + for (final l in association) { + associationPictureNotifier.setTData(l, const AsyncValue.data([])); + } + return associationPictureNotifier; + }, error: (error, stackTrace) { + associationPictureNotifier.loadTList([]); + return associationPictureNotifier; + }, loading: () { + associationPictureNotifier.loadTList([]); + return associationPictureNotifier; + }); + }); + return associationPictureNotifier; +}); \ No newline at end of file diff --git a/lib/phonebook/providers/research_filter_provider.dart b/lib/phonebook/providers/research_filter_provider.dart index 0743c5a29..8791da651 100644 --- a/lib/phonebook/providers/research_filter_provider.dart +++ b/lib/phonebook/providers/research_filter_provider.dart @@ -11,6 +11,6 @@ class FilterNotifier extends StateNotifier { void setFilter(String i) { - state = i;; + state = i; } } \ No newline at end of file diff --git a/lib/phonebook/repositories/association_picture_repository.dart b/lib/phonebook/repositories/association_picture_repository.dart index 00aeae50f..4e03e7864 100644 --- a/lib/phonebook/repositories/association_picture_repository.dart +++ b/lib/phonebook/repositories/association_picture_repository.dart @@ -1,4 +1,4 @@ -import 'package:flutter/services.dart'; +import 'package:flutter/material.dart'; import 'package:myecl/tools/repository/logo_repository.dart'; class AssociationPictureRepository extends LogoRepository { @@ -6,12 +6,17 @@ class AssociationPictureRepository extends LogoRepository { // ignore: overridden_fields final ext = 'phonebook/associations/'; - Future getAssociationPicture(String associationId) async { - return await getLogo(associationId, suffix: "/picture"); + Future getAssociationPicture(String associationId) async { + final uint8List = await getLogo(associationId, suffix: "/picture"); + if (uint8List.isEmpty) { + return Image.asset("assets/images/logo.png"); + } + return Image.memory(uint8List); } - Future addAssociationPicture(String path, String associationId) async { + Future addAssociationPicture(String path, String associationId) async { final image = await saveLogoToTemp(path); - return await addLogo(image.path, associationId, suffix: "/picture"); + final uint8List = await addLogo(image.path, associationId, suffix: "/picture"); + return Image.memory(uint8List); } } diff --git a/lib/phonebook/ui/association_card.dart b/lib/phonebook/ui/association_card.dart index 929371279..47e9116e0 100644 --- a/lib/phonebook/ui/association_card.dart +++ b/lib/phonebook/ui/association_card.dart @@ -1,13 +1,16 @@ import 'package:flutter/material.dart'; +import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; +import 'package:myecl/phonebook/providers/associations_pictures_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; class AssociationCard extends HookConsumerWidget { - const AssociationCard({super.key, - required this.association, - required this.onClicked, + const AssociationCard({ + super.key, + required this.association, + required this.onClicked, }); final Association association; @@ -15,76 +18,113 @@ class AssociationCard extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final associationPicture = ref.watch(associationPictureProvider); - + final associationPictures = ref.watch(associationPicturesProvider); + final associationPicturesNotifier = + ref.watch(associationPicturesProvider.notifier); + final associationPictureNotifier = + ref.watch(associationPictureProvider.notifier); + return GestureDetector( - onTap: () { - onClicked(); - }, - child: Container( - margin: const EdgeInsets.all(10), - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - border: Border.all(), - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(20)), - ), - - child: Row( - children: [ - Container( + onTap: () { + onClicked(); + }, + child: Container( + margin: const EdgeInsets.all(10), + padding: const EdgeInsets.all(10), decoration: BoxDecoration( - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - spreadRadius: 5, - blurRadius: 10, - offset: const Offset(2, 3), - ), - ], + border: Border.all(), + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(20)), ), - - child: - associationPicture.when(data: (picture){ - return CircleAvatar( - radius: 80, - backgroundImage: picture.isEmpty ? - const AssetImage('assets/images/profile.png') : - Image.memory(picture).image, - ); - }, loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, error: (e, s) { - return const Center( - child: Text(PhonebookTextConstants.errorLoadAssociationPicture), - ); - }, - ), - ), - const SizedBox(width: 10), - SizedBox( - width: 200, - child: Text( - association.name, + child: Row(children: [ + associationPictures.when( + data: (pictures) { + if (pictures[association] != null) { + return pictures[association]!.when( + data: (picture) { + if (picture.isNotEmpty) { + return Container( + width: 40, + height: 40, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: picture.first.image, + fit: BoxFit.cover, + ), + ), + ); + } else { + associationPictureNotifier + .getAssociationPicture(association.id) + .then((value) { + associationPicturesNotifier.setTData( + association, + AsyncData([ + value.when( + data: (picture) => picture, + loading: () => + Image.asset("assets/images/logo.png"), + error: (e, s) => + Image.asset("assets/images/logo.png"), + ) + ])); + }); + return const HeroIcon( + HeroIcons.userCircle, + size: 40, + ); + } + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return const Center( + child: Text(PhonebookTextConstants + .errorLoadAssociationPicture), + ); + }, + ); + } + return const HeroIcon( + HeroIcons.userCircle, + size: 40, + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return const Center( + child: Text( + PhonebookTextConstants.errorLoadAssociationPicture), + ); + }, + ), + const SizedBox(width: 10), + SizedBox( + width: 200, + child: Text( + association.name, + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + const Spacer(flex: 1), + Text( + association.kind, style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), - ), - const Spacer(flex: 1), - Text(association.kind, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ], - ) - ) - ); + ]))); } -} \ No newline at end of file +} diff --git a/lib/phonebook/ui/pages/admin_page/editable_association_card.dart b/lib/phonebook/ui/pages/admin_page/editable_association_card.dart index cb140cd88..5b0248544 100644 --- a/lib/phonebook/ui/pages/admin_page/editable_association_card.dart +++ b/lib/phonebook/ui/pages/admin_page/editable_association_card.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; +import 'package:myecl/phonebook/providers/associations_pictures_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/delete_button.dart'; import 'package:myecl/phonebook/ui/edition_button.dart'; @@ -18,8 +20,11 @@ class EditableAssociationCard extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final associationPicture = - ref.watch(associationPictureProvider); + final associationPictures = ref.watch(associationPicturesProvider); + final associationPicturesNotifier = + ref.watch(associationPicturesProvider.notifier); + final associationPictureNotifier = + ref.watch(associationPictureProvider.notifier); return Container( margin: const EdgeInsets.symmetric(vertical: 10), padding: const EdgeInsets.all(10), @@ -37,23 +42,75 @@ class EditableAssociationCard extends HookConsumerWidget { const SizedBox( width: 10, ), - associationPicture.when(data: (picture){ - return CircleAvatar( - radius: 80, - backgroundImage: picture.isEmpty ? - const AssetImage('assets/images/profile.png') : - Image.memory(picture).image, - ); - }, loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, error: (e, s) { - return const Center( - child: Text(PhonebookTextConstants.errorLoadAssociationPicture), - ); - }, - ), + associationPictures.when( + data: (pictures) { + if (pictures[association] != null) { + return pictures[association]!.when( + data: (picture) { + if (picture.isNotEmpty) { + return Container( + width: 40, + height: 40, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: picture.first.image, + fit: BoxFit.cover, + ), + ), + ); + } else { + associationPictureNotifier + .getAssociationPicture(association.id) + .then((value) { + associationPicturesNotifier.setTData( + association, + AsyncData([ + value.when( + data: (picture) => picture, + loading: () => + Image.asset("assets/images/logo.png"), + error: (e, s) => + Image.asset("assets/images/logo.png"), + ) + ])); + }); + return const HeroIcon( + HeroIcons.userCircle, + size: 40, + ); + } + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return const Center( + child: Text(PhonebookTextConstants + .errorLoadAssociationPicture), + ); + }, + ); + } + return const HeroIcon( + HeroIcons.userCircle, + size: 40, + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return const Center( + child: Text( + PhonebookTextConstants.errorLoadAssociationPicture), + ); + }, + ), const SizedBox(width: 10), Text( association.name, diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index 1b86c5220..aba99177d 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -46,12 +46,17 @@ class AssociationPage extends HookConsumerWidget { ), child: associationPicture.when( data: (picture) { - return CircleAvatar( - radius: 120, - backgroundImage: picture.isEmpty - ? const AssetImage('assets/images/logo_alpha.png') - : Image.memory(picture).image, - ); + return Container( + width: 40, + height: 40, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: picture.image, + fit: BoxFit.cover, + ), + ), + ); }, loading: () { return const Center( From f6146debb0917ec1980348725a7425592c2c5f91 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:01 +0100 Subject: [PATCH 019/123] add membership's id management --- lib/phonebook/class/membership.dart | 9 ++++++++- .../providers/association_provider.dart | 5 +++-- .../repositories/association_repository.dart | 11 +++++------ lib/phonebook/tools/fake_class.dart | 16 ++++++++-------- .../member_editable_card.dart | 6 ++++-- 5 files changed, 28 insertions(+), 19 deletions(-) diff --git a/lib/phonebook/class/membership.dart b/lib/phonebook/class/membership.dart index fe6310bf5..981ee414f 100644 --- a/lib/phonebook/class/membership.dart +++ b/lib/phonebook/class/membership.dart @@ -2,16 +2,19 @@ import 'package:myecl/phonebook/class/association.dart'; class Membership{ Membership({ + required this.id, required this.association, required this.rolesTags, required this.apparentName, }); + late final String id; late final Association association; late final List rolesTags; late final String apparentName; Membership.fromJSON(Map json){ + id = json['id']; association = json['association']; rolesTags = json['roleTags']; apparentName = json['apparentName']; @@ -19,6 +22,7 @@ class Membership{ Map toJSON(){ final data = { + 'id': id, 'association': association.id, 'roleTags': rolesTags, 'apparentName': apparentName, @@ -27,11 +31,13 @@ class Membership{ } Membership copyWith({ + String? id, Association? association, List? rolesTags, String? apparentName, }) { return Membership( + id: id ?? this.id, association: association ?? this.association, rolesTags: rolesTags ?? this.rolesTags, apparentName: apparentName ?? this.apparentName, @@ -39,6 +45,7 @@ class Membership{ } Membership.empty(){ + id = ""; association = Association.empty(); rolesTags = []; apparentName = ""; @@ -58,6 +65,6 @@ class Membership{ @override String toString() { - return 'Membership(association: $association, rolesTags: $rolesTags, apparentName: $apparentName)'; + return 'Membership(id: $id, association: $association, rolesTags: $rolesTags, apparentName: $apparentName)'; } } \ No newline at end of file diff --git a/lib/phonebook/providers/association_provider.dart b/lib/phonebook/providers/association_provider.dart index a1d75aade..8960d3129 100644 --- a/lib/phonebook/providers/association_provider.dart +++ b/lib/phonebook/providers/association_provider.dart @@ -3,6 +3,7 @@ import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/member.dart'; +import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/repositories/association_repository.dart'; import 'package:myecl/tools/providers/single_notifier.dart'; @@ -23,9 +24,9 @@ class AssociationNotifier extends SingleNotifier { (association) async => associationRepository.addMember(association, member, rolesTags, apparentName), association); } - Future deleteMember(Association association, CompleteMember user) async { + Future deleteMember(Membership membership) async { return await update( - (association) async => associationRepository.deleteMember(association, user), association); + (association) async => associationRepository.deleteMember(membership), membership.association); } Future updateMember(Association association, Member user, List rolesTags, String apparentName) async { diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index 879df4379..2ad2a6404 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -62,19 +62,18 @@ class AssociationRepository extends Repository { // .memberships // .add(Membership(association: association, rolesTags: rolesTags, apparentName: apparentName)); return await create({"member_id": member.id, "association_id": association.id, "rolesTags": rolesTags, "apparentName": apparentName}, - suffix: "membership"); + suffix: "memberships"); // return true; } - Future deleteMember(Association association, CompleteMember member) async { + Future deleteMember(Membership membership) async { // fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.member.id)] // .memberships // .removeWhere((element) => element.association.id == association.id); // return true; final response = await http.delete( - Uri.parse("$host${ext}membership"), - headers: headers, - body: json.encode({"member_id": member.member.id, "association_id": association.id})); + Uri.parse("$host${ext}memberships/${membership.id}"), + headers: headers); if (response.statusCode == 204) { return true; } else if (response.statusCode == 403) { @@ -91,7 +90,7 @@ class AssociationRepository extends Repository { // .where((element) => element.association.id == association.id).toList()[0] = // Membership(association: association, rolesTags: rolesTags, apparentName: apparentName); return await update({"member_id": member.id, "association_id": association.id, "rolesTags": rolesTags, "apparentName": apparentName}, association.id, - suffix: "membership"); + suffix: "memberships"); // return true; } } diff --git a/lib/phonebook/tools/fake_class.dart b/lib/phonebook/tools/fake_class.dart index a57f50ee0..07122c2aa 100644 --- a/lib/phonebook/tools/fake_class.dart +++ b/lib/phonebook/tools/fake_class.dart @@ -46,7 +46,7 @@ List fakeMembersList = [ id: '1', email: 'test1@useless', promotion: 'E21'), - memberships: [Membership(association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[0]], apparentName: 'Prez\'')]), + memberships: [Membership(id:"1", association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[0]], apparentName: 'Prez\'')]), CompleteMember( member: Member( name: 'Debouck', @@ -55,7 +55,7 @@ List fakeMembersList = [ id: '2', email: 'test2@useless', promotion: 'E22'), - memberships: [Membership(association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[1]], apparentName: 'Trez\'')]), + memberships: [Membership(id:"2", association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[1]], apparentName: 'Trez\'')]), CompleteMember( member: Member( name: 'Ray', @@ -64,7 +64,7 @@ List fakeMembersList = [ id: '3', email: 'test3@useless', promotion: 'E21'), - memberships: [Membership(association: fakeAssociations[1], rolesTags: [fakeRolesTags.tags[2]], apparentName: 'SG')]), + memberships: [Membership(id:"3", association: fakeAssociations[1], rolesTags: [fakeRolesTags.tags[2]], apparentName: 'SG')]), CompleteMember( member: Member( name: 'Guarriguenc', @@ -74,8 +74,8 @@ List fakeMembersList = [ email: 'test4@useless', promotion: 'E20'), memberships: [ - Membership(association: fakeAssociations[1], rolesTags: [fakeRolesTags.tags[0]], apparentName: 'Prez\''), - Membership(association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[4]], apparentName: 'VP sponsor'), + Membership(id:"4", association: fakeAssociations[1], rolesTags: [fakeRolesTags.tags[0]], apparentName: 'Prez\''), + Membership(id:"5", association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[4]], apparentName: 'VP sponsor'), ]), CompleteMember( member: Member( @@ -85,7 +85,7 @@ List fakeMembersList = [ id: '5', email: 'test5@useless', promotion: 'E20'), - memberships: [Membership(association: fakeAssociations[1], rolesTags: [], apparentName: 'VP Emprunt')]), + memberships: [Membership(id:"6", association: fakeAssociations[1], rolesTags: [], apparentName: 'VP Emprunt')]), CompleteMember( member: Member( name: 'Sarrazin', @@ -95,7 +95,7 @@ List fakeMembersList = [ email: 'test6@useless', promotion: 'E21'), memberships: [ - Membership(association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[3]], apparentName: 'VP com'), - Membership(association: fakeAssociations[0], rolesTags: [], apparentName: 'VP Event')]), + Membership(id:"7", association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[3]], apparentName: 'VP com'), + Membership(id:"8", association: fakeAssociations[0], rolesTags: [], apparentName: 'VP Event')]), ]; diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index a013a36d9..a732c025c 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -5,7 +5,6 @@ import 'package:myecl/phonebook/providers/association_member_list_provider.dart' import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/providers/edition_provider.dart'; -import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/ui/delete_button.dart'; @@ -123,7 +122,10 @@ class MemberEditableCard extends HookConsumerWidget { DeleteButton( onDelete: () async { final result = - await associationNotifier.deleteMember(association, member); + await associationNotifier.deleteMember( + member.memberships.firstWhere( + (element) => element.association.id == association.id) + ); await associationMembersNotifier.loadMembers(association.id); if (result) { displayToastWithContext( From 50a78b09d37f927d28de393e3c5c9f62bf5782ed Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:01 +0100 Subject: [PATCH 020/123] Fix endpoints and kinds/roletags classes --- lib/phonebook/class/association_kinds.dart | 7 ++++++- lib/phonebook/class/roles_tags.dart | 2 +- .../providers/association_kinds_provider.dart | 12 ++++++++---- .../repositories/association_kind_repository.dart | 14 -------------- .../repositories/association_repository.dart | 6 ++++++ .../repositories/role_tags_repository.dart | 2 +- lib/phonebook/ui/pages/admin_page/admin_page.dart | 6 +++--- .../association_creation_page.dart | 4 ++-- .../association_editor_page.dart | 4 ++-- lib/phonebook/ui/pages/main_page/main_page.dart | 11 +++++------ .../ui/{kind_chip.dart => radio_chip.dart} | 4 ++-- 11 files changed, 36 insertions(+), 36 deletions(-) rename lib/phonebook/ui/{kind_chip.dart => radio_chip.dart} (93%) diff --git a/lib/phonebook/class/association_kinds.dart b/lib/phonebook/class/association_kinds.dart index fef0a7775..826285496 100644 --- a/lib/phonebook/class/association_kinds.dart +++ b/lib/phonebook/class/association_kinds.dart @@ -3,7 +3,7 @@ class AssociationKinds { required this.kinds, }); - late final List kinds; + late final List kinds; AssociationKinds.fromJSON(Map json){ kinds = json['kinds']; @@ -19,4 +19,9 @@ class AssociationKinds { AssociationKinds empty(){ return AssociationKinds(kinds: []); } + + @override + String toString() { + return 'AssociationKinds(kinds: $kinds)'; + } } \ No newline at end of file diff --git a/lib/phonebook/class/roles_tags.dart b/lib/phonebook/class/roles_tags.dart index d3d3adde6..b1b320848 100644 --- a/lib/phonebook/class/roles_tags.dart +++ b/lib/phonebook/class/roles_tags.dart @@ -3,7 +3,7 @@ class RolesTags{ required this.tags, }); - late final List tags; + late final List tags; RolesTags.fromJSON(Map json){ tags = json['tags']; diff --git a/lib/phonebook/providers/association_kinds_provider.dart b/lib/phonebook/providers/association_kinds_provider.dart index 8e9b8292d..a4005f0bc 100644 --- a/lib/phonebook/providers/association_kinds_provider.dart +++ b/lib/phonebook/providers/association_kinds_provider.dart @@ -1,16 +1,17 @@ +import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/association_kinds.dart'; -import 'package:myecl/phonebook/repositories/association_kind_repository.dart'; +import 'package:myecl/phonebook/repositories/association_repository.dart'; import 'package:myecl/tools/providers/single_notifier.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; class AssociationKindsNotifier extends SingleNotifier { - final AssociationKindsRepository associationKindsRepository = AssociationKindsRepository(); + final AssociationRepository associationRepository = AssociationRepository(); AssociationKindsNotifier({required String token}) : super(const AsyncValue.loading()) { - associationKindsRepository.setToken(token); + associationRepository.setToken(token); } void setKind(AssociationKinds i) { @@ -18,7 +19,10 @@ class AssociationKindsNotifier extends SingleNotifier { } Future> loadAssociationKinds() async { - return await load(() async => associationKindsRepository.getAssociationKinds()); + debugPrint("loadAssociationKinds"); + AsyncValue result = await load(() async => associationRepository.getAssociationKinds()); + debugPrint("loadAssociationKinds result: $result"); + return result; } } diff --git a/lib/phonebook/repositories/association_kind_repository.dart b/lib/phonebook/repositories/association_kind_repository.dart index 9df42a20e..e69de29bb 100644 --- a/lib/phonebook/repositories/association_kind_repository.dart +++ b/lib/phonebook/repositories/association_kind_repository.dart @@ -1,14 +0,0 @@ -import 'package:myecl/phonebook/class/association_kinds.dart'; -import 'package:myecl/phonebook/tools/fake_class.dart'; -import 'package:myecl/tools/repository/repository.dart'; - -class AssociationKindsRepository extends Repository { - @override - // ignore: overridden_fields - final ext = "phonebook/associations"; - - Future getAssociationKinds() async { - // return fakeAssociationKinds ; - return AssociationKinds.fromJSON(await getOne("kinds")); - } -} \ No newline at end of file diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index 2ad2a6404..aee0c1a56 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/class/association_kinds.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/member.dart'; import 'package:myecl/phonebook/class/membership.dart'; @@ -93,4 +94,9 @@ class AssociationRepository extends Repository { suffix: "memberships"); // return true; } + + Future getAssociationKinds() async { + // return fakeAssociationKinds ; + return AssociationKinds.fromJSON(await getOne("kinds")); + } } diff --git a/lib/phonebook/repositories/role_tags_repository.dart b/lib/phonebook/repositories/role_tags_repository.dart index 069613fd8..db0334218 100644 --- a/lib/phonebook/repositories/role_tags_repository.dart +++ b/lib/phonebook/repositories/role_tags_repository.dart @@ -10,7 +10,7 @@ class RolesTagsRepository extends Repository { Future>> getRolesTags() async { // return Tuple2(fakeRolesTags,List.filled(fakeRolesTags.tags.length, false)); - RolesTags rolesTags = RolesTags.fromJSON(await getOne("rolesTags")); + RolesTags rolesTags = RolesTags.fromJSON(await getOne("roletags")); return Tuple2(rolesTags,List.filled(rolesTags.tags.length, false)); } } diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 449d2cc44..5d14def44 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -9,7 +9,7 @@ import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/ui/kind_chip.dart'; +import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/association_research_bar.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/editable_association_card.dart'; import 'package:myecl/tools/functions.dart'; @@ -46,7 +46,7 @@ class AdminPage extends HookConsumerWidget { return SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row(children: [ - KindChip( + RadioChip( label: "Toutes", selected: kind.value == "", onTap: () { @@ -55,7 +55,7 @@ class AdminPage extends HookConsumerWidget { associationsNotifier.filterAssociationList(nameFilter, kind.value); }), ...data.kinds - .map((e) => KindChip( + .map((e) => RadioChip( label: e, selected: kind.value == e, onTap: () { diff --git a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart index 0ecc7a1e6..da6f5f1bd 100644 --- a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart +++ b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart @@ -8,7 +8,7 @@ import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/ui/kind_chip.dart'; +import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; @@ -60,7 +60,7 @@ class AssociationCreationPage extends HookConsumerWidget { children: [ const Spacer(), ...value.kinds.map( - (e) => KindChip( + (e) => RadioChip( label: e, selected: e == kind.value, onTap: () async { diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 1145519c3..f0fd83c71 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -15,7 +15,7 @@ import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/ui/kind_chip.dart'; +import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/phonebook/ui/pages/association_editor_page/member_editable_card.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; @@ -80,7 +80,7 @@ class AssociationEditorPage extends HookConsumerWidget { scrollDirection: Axis.horizontal, child: Row( children: value.kinds - .map((e) => KindChip( + .map((e) => RadioChip( label: e, selected: e == kind.value, onTap: () async { diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 8b4c47508..2a7b15b4b 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -12,7 +12,7 @@ import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/admin/providers/is_admin.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/ui/association_card.dart'; -import 'package:myecl/phonebook/ui/kind_chip.dart'; +import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/phonebook/ui/pages/main_page/research_bar.dart'; import 'package:myecl/tools/ui/refresher.dart'; @@ -28,7 +28,6 @@ class MainPage extends HookConsumerWidget { final associationList = ref.watch(associationListProvider); final associationKindsNotifier = ref.watch(associationKindsProvider.notifier); - final rolesTagsNotifier = ref.watch(rolesTagsProvider.notifier); final associationKinds = ref.watch(associationKindsProvider); final kind = useState(''); final kindNotifier = ref.watch(associationKindProvider.notifier); @@ -38,7 +37,6 @@ class MainPage extends HookConsumerWidget { children: [ Refresher( onRefresh: () async { - await rolesTagsNotifier.loadRolesTags(); await associationKindsNotifier.loadAssociationKinds(); await associationListNotifier.loadAssociations(); }, @@ -47,10 +45,11 @@ class MainPage extends HookConsumerWidget { const SizedBox(height: 70), associationKinds.when( data: (data) { + debugPrint("associationKinds.when data: ${data.kinds}"); return SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row(children: [ - KindChip( + RadioChip( label: "Toutes", selected: kind.value == "", onTap: () { @@ -59,7 +58,7 @@ class MainPage extends HookConsumerWidget { associationListNotifier.filterAssociationList(nameFilter, kind.value); }), ...data.kinds - .map((e) => KindChip( + .map((e) => RadioChip( label: e, selected: kind.value == e, onTap: () { @@ -73,7 +72,7 @@ class MainPage extends HookConsumerWidget { ); }, error: (error, stackTrace) => - const Text(PhonebookTextConstants.errorRoleTagsLoading), + const Text(PhonebookTextConstants.errorKindsLoading), loading: () => const CircularProgressIndicator()), const SizedBox(height: 30), const ResearchBar(), diff --git a/lib/phonebook/ui/kind_chip.dart b/lib/phonebook/ui/radio_chip.dart similarity index 93% rename from lib/phonebook/ui/kind_chip.dart rename to lib/phonebook/ui/radio_chip.dart index 33f6ec04d..672bb27f2 100644 --- a/lib/phonebook/ui/kind_chip.dart +++ b/lib/phonebook/ui/radio_chip.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; -class KindChip extends StatelessWidget { +class RadioChip extends StatelessWidget { final bool selected; final String label; final Function() onTap; - const KindChip( + const RadioChip( {super.key, required this.label, required this.selected, From 3df6cb3591d4d38d684b64186ebb891fa8f3379c Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:01 +0100 Subject: [PATCH 021/123] Updating association_creation_page UI Signed-off-by: Maxime Roucher --- .../association_creation_page.dart | 353 ++++++++---------- .../association_creation_page/text_entry.dart | 53 +++ 2 files changed, 201 insertions(+), 205 deletions(-) create mode 100644 lib/phonebook/ui/pages/association_creation_page/text_entry.dart diff --git a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart index da6f5f1bd..64d2985aa 100644 --- a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart +++ b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart @@ -8,6 +8,7 @@ import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/phonebook/ui/pages/association_creation_page/text_entry.dart'; import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; @@ -33,232 +34,174 @@ class AssociationCreationPage extends HookConsumerWidget { displayToast(context, type, msg); } - - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 30.0), - child: SingleChildScrollView( - physics: const AlwaysScrollableScrollPhysics( - parent: BouncingScrollPhysics(), + return SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics( + parent: BouncingScrollPhysics(), + ), + child: Form( + key: key, + child: Column(children: [ + const SizedBox( + height: 30, + ), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 30.0), + child: Align( + alignment: Alignment.centerLeft, + child: Text(AdminTextConstants.addAssociation, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w700, + color: ColorConstants.gradient1)), + ), + ), + const SizedBox( + height: 30, ), - child: Form( - key: key, - child: Column(children: [ - const Center( - child: Text(AdminTextConstants.addAssociation, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.w700, - color: ColorConstants.gradient1)), - ), - const SizedBox( - height: 30, - ), - associationKinds.when( - data: (value) { - return SingleChildScrollView( - child: Row( - children: [ - const Spacer(), - ...value.kinds.map( - (e) => RadioChip( + associationKinds.when( + data: (value) { + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + physics: const BouncingScrollPhysics(), + child: Row(children: [ + const SizedBox(width: 15), + ...value.kinds + .map((e) => RadioChip( label: e, selected: e == kind.value, onTap: () async { kind.value = e; }, - )).toList(), - const Spacer(), - ] - ) - ); - }, - error: (error, stack) { - return const Text(PhonebookTextConstants.errorKindsLoading); - }, - loading: () { - return const CircularProgressIndicator(); - }, - ), - Container( + )) + .toList(), + const SizedBox(width: 15), + ])); + }, + error: (error, stack) { + return const Text(PhonebookTextConstants.errorKindsLoading); + }, + loading: () { + return const CircularProgressIndicator(); + }, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: Column( + children: [ + Container( margin: const EdgeInsets.symmetric( - vertical: 20, + vertical: 10, ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: const EdgeInsets.only(bottom: 3), - child: const Text( - AdminTextConstants.name, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, - color: Color.fromARGB(255, 158, 158, 158), - ), - ), - ), - SizedBox( - child: TextFormField( - controller: name, - decoration: const InputDecoration( - contentPadding: EdgeInsets.all(10), - isDense: true, - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: ColorConstants.gradient1))), - validator: (value) { - if (value == null) { - return AdminTextConstants.emptyFieldError; - } else if (value.isEmpty) { - return AdminTextConstants.emptyFieldError; - } else { - return null; - } - }, - ), - ), - ], - )), - Container( - margin: const EdgeInsets.symmetric(vertical: 20), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: const EdgeInsets.only(bottom: 3), - child: const Text( - AdminTextConstants.description, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, - color: Color.fromARGB(255, 158, 158, 158), - ), - ), + ), + AddAssociationTextEntry( + controller: name, title: AdminTextConstants.name), + AddAssociationTextEntry( + controller: description, + title: AdminTextConstants.description), + ShrinkButton( + waitChild: Container( + width: double.infinity, + margin: const EdgeInsets.symmetric(vertical: 20), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], ), - SizedBox( - child: TextFormField( - controller: description, - decoration: const InputDecoration( - contentPadding: EdgeInsets.all(10), - isDense: true, - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: ColorConstants.gradient1))), - validator: (value) { - if (value == null) { - return AdminTextConstants.emptyFieldError; - } else if (value.isEmpty) { - return AdminTextConstants.emptyFieldError; - } else { - return null; - } - }, + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, ), - ), - ], - ) - ), - - ShrinkButton( - waitChild: Container( - width: double.infinity, - margin: const EdgeInsets.symmetric(vertical: 20), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, ], + borderRadius: BorderRadius.circular(15), ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, + child: const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + color: Colors.white, ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: const SizedBox( - height: 20, - width: 20, - child: CircularProgressIndicator( - color: Colors.white, ), ), - ), - onTap: () async { - if (!key.currentState!.validate()) { - displayToastWithContext(TypeMsg.error, PhonebookTextConstants.emptyFieldError); - return; - } - if (kind.value == '') { - displayToastWithContext(TypeMsg.error, PhonebookTextConstants.emptyKindError); - return; - } - await tokenExpireWrapper(ref, () async { - final value = await associationListNotifier.createAssociation( - Association.empty().copyWith( - name: name.text, - description: description.text, - kind: kind.value)); - if (value) { - displayToastWithContext( - TypeMsg.msg, PhonebookTextConstants.addedAssociation); - associations.when(data: (d) { - associationNotifier.setAssociation(d.last); - pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); - }, - error: (e, s) => displayToastWithContext( - TypeMsg.error, PhonebookTextConstants.errorAssociationLoading), - loading: () {}); - - } else { - displayToastWithContext( - TypeMsg.error, AdminTextConstants.addingError); + onTap: () async { + if (!key.currentState!.validate()) { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.emptyFieldError); + return; } - }); - }, - child: Container( - width: double.infinity, - margin: const EdgeInsets.symmetric(vertical: 20), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, + if (kind.value == '') { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.emptyKindError); + return; + } + await tokenExpireWrapper(ref, () async { + final value = await associationListNotifier + .createAssociation(Association.empty().copyWith( + name: name.text, + description: description.text, + kind: kind.value)); + if (value) { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.addedAssociation); + associations.when( + data: (d) { + associationNotifier.setAssociation(d.last); + pageNotifier.setPhonebookPage( + PhonebookPage.associationEditor); + }, + error: (e, s) => displayToastWithContext( + TypeMsg.error, + PhonebookTextConstants + .errorAssociationLoading), + loading: () {}); + } else { + displayToastWithContext( + TypeMsg.error, AdminTextConstants.addingError); + } + }); + }, + child: Container( + width: double.infinity, + margin: const EdgeInsets.symmetric(vertical: 20), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), ], + borderRadius: BorderRadius.circular(15), ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, + child: const Text( + AdminTextConstants.add, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: const Text( - AdminTextConstants.add, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color.fromARGB(255, 255, 255, 255), ), ), ), - ) - ]), - ))); + ], + ), + ) + ]), + )); } } diff --git a/lib/phonebook/ui/pages/association_creation_page/text_entry.dart b/lib/phonebook/ui/pages/association_creation_page/text_entry.dart new file mode 100644 index 000000000..55084fb6a --- /dev/null +++ b/lib/phonebook/ui/pages/association_creation_page/text_entry.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; +import 'package:myecl/admin/tools/constants.dart'; +import 'package:myecl/tools/constants.dart'; + +class AddAssociationTextEntry extends StatelessWidget { + final TextEditingController controller; + final String title; + const AddAssociationTextEntry( + {Key? key, required this.controller, required this.title}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + margin: const EdgeInsets.symmetric(vertical: 20), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + alignment: Alignment.centerLeft, + child: Text( + title, + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + color: Color.fromARGB(255, 158, 158, 158), + ), + ), + ), + SizedBox( + child: TextFormField( + controller: controller, + decoration: const InputDecoration( + isDense: true, + focusedBorder: UnderlineInputBorder( + borderSide: + BorderSide(color: ColorConstants.gradient1))), + validator: (value) { + if (value == null) { + return AdminTextConstants.emptyFieldError; + } else if (value.isEmpty) { + return AdminTextConstants.emptyFieldError; + } else { + return null; + } + }, + ), + ), + ], + )); + } +} From d211d6b268afea184f83f216d4af8c92760a73ca Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:01 +0100 Subject: [PATCH 022/123] Cleanup Signed-off-by: Maxime Roucher --- .../providers/association_provider.dart | 25 +++--- .../association_member_repository.dart | 10 +-- .../repositories/association_repository.dart | 78 +++++-------------- .../repositories/role_tags_repository.dart | 2 - .../ui/pages/admin_page/admin_page.dart | 4 +- .../association_editor_page.dart | 2 - .../ui/pages/main_page/main_page.dart | 5 +- 7 files changed, 42 insertions(+), 84 deletions(-) diff --git a/lib/phonebook/providers/association_provider.dart b/lib/phonebook/providers/association_provider.dart index 8960d3129..526cf1eac 100644 --- a/lib/phonebook/providers/association_provider.dart +++ b/lib/phonebook/providers/association_provider.dart @@ -1,13 +1,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/member.dart'; import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/repositories/association_repository.dart'; import 'package:myecl/tools/providers/single_notifier.dart'; - class AssociationNotifier extends SingleNotifier { final AssociationRepository associationRepository = AssociationRepository(); AssociationNotifier({required String token}) @@ -16,28 +14,35 @@ class AssociationNotifier extends SingleNotifier { } Future> loadAssociation(String associationId) async { - return await load(() async => associationRepository.getAssociation(associationId)); + return await load( + () async => associationRepository.getAssociation(associationId)); } - Future addMember(Association association, Member member, List rolesTags, String apparentName) async { + Future addMember(Association association, Member member, + List rolesTags, String apparentName) async { return await update( - (association) async => associationRepository.addMember(association, member, rolesTags, apparentName), association); + (association) async => associationRepository.addMember( + association, member, rolesTags, apparentName), + association); } Future deleteMember(Membership membership) async { return await update( - (association) async => associationRepository.deleteMember(membership), membership.association); + (association) async => associationRepository.deleteMember(membership), + membership.association); } - Future updateMember(Association association, Member user, List rolesTags, String apparentName) async { + Future updateMember(Association association, Member user, + List rolesTags, String apparentName) async { return await update( - (association) async => associationRepository.updateMember(association, user, rolesTags, apparentName), association); + (association) async => associationRepository.updateMember( + association, user, rolesTags, apparentName), + association); } void setAssociation(Association association) { state = AsyncValue.data(association); } - } final asyncAssociationProvider = @@ -50,4 +55,4 @@ final associationProvider = Provider((ref) { final association = ref.watch(asyncAssociationProvider); return association.maybeWhen( data: (association) => association, orElse: () => Association.empty()); -}); \ No newline at end of file +}); diff --git a/lib/phonebook/repositories/association_member_repository.dart b/lib/phonebook/repositories/association_member_repository.dart index d98bcf166..4c25415e8 100644 --- a/lib/phonebook/repositories/association_member_repository.dart +++ b/lib/phonebook/repositories/association_member_repository.dart @@ -1,5 +1,4 @@ import 'package:myecl/phonebook/class/complete_member.dart'; -import 'package:myecl/phonebook/tools/fake_class.dart'; import 'package:myecl/tools/repository/repository.dart'; class AssociationMemberRepository extends Repository { @@ -7,9 +6,10 @@ class AssociationMemberRepository extends Repository { // ignore: overridden_fields final ext = "phonebook/associations/"; - Future> getAssociationMemberList(String associationId) async { - // return fakeMembersList.where((element) => element.memberships.map((e) => e.association.id).contains(associationId)).toList(); + Future> getAssociationMemberList( + String associationId) async { return List.from( - (await getList(suffix: "$associationId/members")).map((x) => CompleteMember.fromJSON(x))); + (await getList(suffix: "$associationId/members")) + .map((x) => CompleteMember.fromJSON(x))); } -} \ No newline at end of file +} diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index aee0c1a56..276ec6f48 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -1,13 +1,7 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:flutter/material.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/association_kinds.dart'; -import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/member.dart'; import 'package:myecl/phonebook/class/membership.dart'; -import 'package:myecl/phonebook/tools/fake_class.dart'; -import 'package:myecl/tools/exception.dart'; import 'package:myecl/tools/repository/repository.dart'; class AssociationRepository extends Repository { @@ -16,87 +10,51 @@ class AssociationRepository extends Repository { final ext = "phonebook/associations/"; Future> getAssociationList() async { - // return fakeAssociations; return List.from( - (await getList()).map((x) => Association.fromJSON(x))); + (await getList()).map((x) => Association.fromJSON(x))); } Future getAssociation(String associationId) async { - // return fakeAssociations.firstWhere((element) => element.id == associationId); return Association.fromJSON(await getOne(associationId)); } Future deleteAssociation(String associationId) async { - //fakeAssociations.removeWhere((element) => element.id == associationId); - // return true; return await delete(associationId); } Future updateAssociation(Association association) async { - //fakeAssociations[fakeAssociations.indexWhere((element) => element.id == association.id)] = association; - // return true; return await update(association.toJSON(), association.id); } Future createAssociation(Association association) async { - // List ids = fakeAssociations.map((e) => e.id).toList(); - // String newId = "1"; - // while (ids.contains(newId)) { - // newId = (int.parse(newId) + 1).toString(); - // } - // association = association.copyWith(id: newId); - // return association; return Association.fromJSON(await create(association.toJSON())); } - Future addMember(Association association, Member member, List rolesTags, String apparentName) async { - // if (fakeMembersList.indexWhere((element) => element.member.id == member.id) == -1) { - // fakeMembersList.add(CompleteMember(member: member, memberships: [])); - // } - // if (fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.id)] - // .memberships - // .indexWhere((element) => element.association.id == association.id) != - // -1) { - // return false; - // } - // fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.id)] - // .memberships - // .add(Membership(association: association, rolesTags: rolesTags, apparentName: apparentName)); - return await create({"member_id": member.id, "association_id": association.id, "rolesTags": rolesTags, "apparentName": apparentName}, - suffix: "memberships"); - // return true; + Future addMember(Association association, Member member, + List rolesTags, String apparentName) async { + return await create({ + "member_id": member.id, + "association_id": association.id, + "rolesTags": rolesTags, + "apparentName": apparentName + }, suffix: "memberships"); } Future deleteMember(Membership membership) async { - // fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.member.id)] - // .memberships - // .removeWhere((element) => element.association.id == association.id); - // return true; - final response = await http.delete( - Uri.parse("$host${ext}memberships/${membership.id}"), - headers: headers); - if (response.statusCode == 204) { - return true; - } else if (response.statusCode == 403) { - throw AppException(ErrorType.tokenExpire, response.body); - } else { - throw AppException(ErrorType.notFound, "Failed to update item"); - } + return await delete("/memberships/${membership.id}"); } - Future updateMember(Association association, Member member, List rolesTags, String apparentName) async { - // debugPrint("updateMember"); - // fakeMembersList[fakeMembersList.indexWhere((element) => element.member.id == member.id)] - // .memberships - // .where((element) => element.association.id == association.id).toList()[0] = - // Membership(association: association, rolesTags: rolesTags, apparentName: apparentName); - return await update({"member_id": member.id, "association_id": association.id, "rolesTags": rolesTags, "apparentName": apparentName}, association.id, - suffix: "memberships"); - // return true; + Future updateMember(Association association, Member member, + List rolesTags, String apparentName) async { + return await update({ + "member_id": member.id, + "association_id": association.id, + "rolesTags": rolesTags, + "apparentName": apparentName + }, association.id, suffix: "memberships"); } Future getAssociationKinds() async { - // return fakeAssociationKinds ; return AssociationKinds.fromJSON(await getOne("kinds")); } } diff --git a/lib/phonebook/repositories/role_tags_repository.dart b/lib/phonebook/repositories/role_tags_repository.dart index db0334218..955c381c8 100644 --- a/lib/phonebook/repositories/role_tags_repository.dart +++ b/lib/phonebook/repositories/role_tags_repository.dart @@ -1,5 +1,4 @@ import 'package:myecl/phonebook/class/roles_tags.dart'; -import 'package:myecl/phonebook/tools/fake_class.dart'; import 'package:myecl/tools/repository/repository.dart'; import 'package:tuple/tuple.dart'; @@ -9,7 +8,6 @@ class RolesTagsRepository extends Repository { final ext = "phonebook/"; Future>> getRolesTags() async { - // return Tuple2(fakeRolesTags,List.filled(fakeRolesTags.tags.length, false)); RolesTags rolesTags = RolesTags.fromJSON(await getOne("roletags")); return Tuple2(rolesTags,List.filled(rolesTags.tags.length, false)); } diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 5d14def44..dec45f1e4 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -88,8 +88,8 @@ class AdminPage extends HookConsumerWidget { ), height: 58, margin: const EdgeInsets.all(10), - child: Row( - children: const [Spacer(), Icon(Icons.add), Spacer()])), + child: const Row( + children: [Spacer(), Icon(Icons.add), Spacer()])), ), ...associations.when( data: (associations) { diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index f0fd83c71..4bef7f728 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -10,8 +10,6 @@ import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/providers/edition_provider.dart'; -import 'package:myecl/phonebook/providers/member_provider.dart'; -import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 2a7b15b4b..77d5843f2 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -7,7 +7,6 @@ import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; -import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/admin/providers/is_admin.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; @@ -118,8 +117,8 @@ class MainPage extends HookConsumerWidget { blurRadius: 10, offset: const Offset(0, 5)) ]), - child: Row( - children: const [ + child: const Row( + children: [ HeroIcon(HeroIcons.userGroup, color: Colors.white), SizedBox(width: 10), Text(PhonebookTextConstants.admin, From 4a52fb938e1b1eed5d6c1820c82472cecff5a397 Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:01 +0100 Subject: [PATCH 023/123] Image loading optimisation + reformating Signed-off-by: Maxime Roucher --- lib/phonebook/class/association.dart | 32 ++-- lib/phonebook/class/association_kinds.dart | 18 +-- lib/phonebook/class/complete_member.dart | 44 +++--- lib/phonebook/class/member.dart | 28 ++-- lib/phonebook/class/membership.dart | 22 +-- lib/phonebook/class/roles_tags.dart | 20 +-- .../providers/association_id_provider.dart | 3 +- .../providers/association_kind_provider.dart | 6 +- .../providers/association_kinds_provider.dart | 19 +-- .../providers/association_list_provider.dart | 52 ++++--- .../association_member_list_provider.dart | 19 ++- .../association_picture_provider.dart | 16 +- .../associations_pictures_provider.dart | 5 +- .../providers/complete_member_provider.dart | 6 +- lib/phonebook/providers/edition_provider.dart | 3 +- lib/phonebook/providers/member_provider.dart | 3 +- .../providers/member_role_tags_provider.dart | 8 +- .../providers/membership_provider.dart | 9 +- .../providers/phonebook_page_provider.dart | 6 +- lib/phonebook/providers/reload_provider.dart | 3 +- .../providers/research_filter_provider.dart | 7 +- .../providers/roles_tags_provider.dart | 24 +-- .../association_kind_repository.dart | 0 .../association_picture_repository.dart | 3 +- .../repositories/member_repository.dart | 6 +- .../repositories/role_tags_repository.dart | 6 +- lib/phonebook/tools/constants.dart | 37 +++-- lib/phonebook/tools/fake_class.dart | 101 ------------- lib/phonebook/ui/association_card.dart | 26 ++-- lib/phonebook/ui/delete_button.dart | 113 +++++++-------- lib/phonebook/ui/edition_button.dart | 45 +++--- .../ui/pages/admin_page/admin_page.dart | 56 +++---- .../admin_page/editable_association_card.dart | 137 +++++++++--------- .../association_editor_page.dart | 17 ++- .../member_editable_card.dart | 8 +- .../membership_dialog.dart | 35 +++-- .../association_page/association_page.dart | 20 +-- .../pages/association_page/member_card.dart | 8 +- .../ui/pages/main_page/main_page.dart | 92 ++++++------ .../ui/pages/main_page/research_bar.dart | 4 +- .../member_detail_page.dart | 18 +-- .../membership_editor_page.dart | 120 ++++++++------- .../membership_editor_page/search_result.dart | 3 +- lib/phonebook/ui/text_input_dialog.dart | 85 ++++++----- lib/phonebook/ui/top_bar.dart | 6 +- 45 files changed, 612 insertions(+), 687 deletions(-) delete mode 100644 lib/phonebook/repositories/association_kind_repository.dart delete mode 100644 lib/phonebook/tools/fake_class.dart diff --git a/lib/phonebook/class/association.dart b/lib/phonebook/class/association.dart index 8e2f77feb..12a9934ed 100644 --- a/lib/phonebook/class/association.dart +++ b/lib/phonebook/class/association.dart @@ -1,4 +1,4 @@ -class Association{ +class Association { Association({ required this.id, required this.name, @@ -6,22 +6,22 @@ class Association{ required this.kind, required this.mandateYear, }); - + late final String id; late final String name; late final String description; late final String kind; late final String mandateYear; - Association.fromJSON(Map json){ - id = json['id']; - name = json['name']; - description = json['description']; - kind = json['kind']; - mandateYear = json['mandateYear']; - } + Association.fromJSON(Map json) { + id = json['id']; + name = json['name']; + description = json['description']; + kind = json['kind']; + mandateYear = json['mandateYear']; + } - Map toJSON(){ + Map toJSON() { final data = { 'id': id, 'name': name, @@ -48,7 +48,7 @@ class Association{ ); } - Association.empty(){ + Association.empty() { id = ""; name = ""; description = ""; @@ -56,14 +56,12 @@ class Association{ mandateYear = ""; } - void newMandate(){ - mandateYear = (int.parse(mandateYear) + 1).toString(); + void newMandate() { + mandateYear = (int.parse(mandateYear) + 1).toString(); } @override - String toString(){ + String toString() { return "Nom : $name, id : $id, description : $description, kind : $kind, mandate_year : $mandateYear"; } - - -} \ No newline at end of file +} diff --git a/lib/phonebook/class/association_kinds.dart b/lib/phonebook/class/association_kinds.dart index 826285496..99c3fc87c 100644 --- a/lib/phonebook/class/association_kinds.dart +++ b/lib/phonebook/class/association_kinds.dart @@ -1,22 +1,22 @@ class AssociationKinds { AssociationKinds({ required this.kinds, - }); - + }); + late final List kinds; - AssociationKinds.fromJSON(Map json){ - kinds = json['kinds']; - } - - Map toJSON(){ + AssociationKinds.fromJSON(Map json) { + kinds = json['kinds']; + } + + Map toJSON() { final data = { 'kinds': kinds, }; return data; } - AssociationKinds empty(){ + AssociationKinds empty() { return AssociationKinds(kinds: []); } @@ -24,4 +24,4 @@ class AssociationKinds { String toString() { return 'AssociationKinds(kinds: $kinds)'; } -} \ No newline at end of file +} diff --git a/lib/phonebook/class/complete_member.dart b/lib/phonebook/class/complete_member.dart index b0ce4eb20..a71c1beba 100644 --- a/lib/phonebook/class/complete_member.dart +++ b/lib/phonebook/class/complete_member.dart @@ -1,7 +1,7 @@ import 'package:myecl/phonebook/class/membership.dart'; import 'member.dart'; -class CompleteMember{ +class CompleteMember { CompleteMember({ required this.member, required this.memberships, @@ -9,20 +9,21 @@ class CompleteMember{ late final Member member; late final List memberships; - - CompleteMember.fromJSON(Map json){ - String name = json['name']; - String firstname = json['firstname']; - String nickname = json['nickname']; - String id = json['id']; - String email = json['email']; - String promotion = json['promotion']; - member = Member(name: name, firstname: firstname, nickname: nickname, id: id, email: email, promotion: promotion); - memberships = json['memberships'].map((membership) => Membership.fromJSON(membership)).toList(); - } - - Map toJSON(){ + CompleteMember.fromJSON(Map json) { + member = Member( + name: json['name'], + firstname: json['firstname'], + nickname: json['nickname'], + id: json['id'], + email: json['email'], + promotion: json['promotion']); + memberships = json['memberships'] + .map((membership) => Membership.fromJSON(membership)) + .toList(); + } + + Map toJSON() { final data = { 'member': member.id, 'memberships': memberships.map((e) => e.toJSON()).toList(), @@ -40,19 +41,20 @@ class CompleteMember{ ); } - CompleteMember.empty(){ + CompleteMember.empty() { member = Member.empty(); memberships = []; } - Member toMember(){ + Member toMember() { return Member( name: member.name, firstname: member.firstname, nickname: member.nickname, id: member.id, email: member.email, - promotion: member.promotion,); + promotion: member.promotion, + ); } @override @@ -60,7 +62,9 @@ class CompleteMember{ return 'CompleteMember(member: $member, memberships: $memberships)'; } - List getRolesTags(String associationId){ - return memberships.firstWhere((element) => element.association.id == associationId).rolesTags; + List getRolesTags(String associationId) { + return memberships + .firstWhere((element) => element.association.id == associationId) + .rolesTags; } -} +} diff --git a/lib/phonebook/class/member.dart b/lib/phonebook/class/member.dart index 29a177988..3eb4f9a46 100644 --- a/lib/phonebook/class/member.dart +++ b/lib/phonebook/class/member.dart @@ -1,6 +1,6 @@ import 'package:myecl/user/class/list_users.dart'; -class Member{ +class Member { Member({ required this.name, required this.firstname, @@ -17,16 +17,16 @@ class Member{ late final String email; late final String promotion; - Member.fromJSON(Map json){ - name = json['name']; - firstname = json['firstname']; - nickname = json['nickname']; - id = json['id']; - email = json['email']; - promotion = json['promotion']; - } - - Map toJSON(){ + Member.fromJSON(Map json) { + name = json['name']; + firstname = json['firstname']; + nickname = json['nickname']; + id = json['id']; + email = json['email']; + promotion = json['promotion']; + } + + Map toJSON() { final data = { 'name': name, 'firstname': firstname, @@ -56,7 +56,7 @@ class Member{ ); } - Member.empty(){ + Member.empty() { name = "nom"; firstname = "prénom"; nickname = null; @@ -65,7 +65,7 @@ class Member{ promotion = "Exx"; } - Member.fromUser(SimpleUser user){ + Member.fromUser(SimpleUser user) { name = user.name; firstname = user.firstname; nickname = user.nickname; @@ -82,4 +82,4 @@ class Member{ String getName() { return "$firstname $name ($nickname)"; } -} \ No newline at end of file +} diff --git a/lib/phonebook/class/membership.dart b/lib/phonebook/class/membership.dart index 981ee414f..9bd05e5ff 100644 --- a/lib/phonebook/class/membership.dart +++ b/lib/phonebook/class/membership.dart @@ -1,6 +1,6 @@ import 'package:myecl/phonebook/class/association.dart'; -class Membership{ +class Membership { Membership({ required this.id, required this.association, @@ -13,14 +13,14 @@ class Membership{ late final List rolesTags; late final String apparentName; - Membership.fromJSON(Map json){ - id = json['id']; - association = json['association']; - rolesTags = json['roleTags']; - apparentName = json['apparentName']; - } - - Map toJSON(){ + Membership.fromJSON(Map json) { + id = json['id']; + association = json['association']; + rolesTags = json['roleTags']; + apparentName = json['apparentName']; + } + + Map toJSON() { final data = { 'id': id, 'association': association.id, @@ -44,7 +44,7 @@ class Membership{ ); } - Membership.empty(){ + Membership.empty() { id = ""; association = Association.empty(); rolesTags = []; @@ -67,4 +67,4 @@ class Membership{ String toString() { return 'Membership(id: $id, association: $association, rolesTags: $rolesTags, apparentName: $apparentName)'; } -} \ No newline at end of file +} diff --git a/lib/phonebook/class/roles_tags.dart b/lib/phonebook/class/roles_tags.dart index b1b320848..8346784d2 100644 --- a/lib/phonebook/class/roles_tags.dart +++ b/lib/phonebook/class/roles_tags.dart @@ -1,22 +1,22 @@ -class RolesTags{ +class RolesTags { RolesTags({ required this.tags, - }); - + }); + late final List tags; - RolesTags.fromJSON(Map json){ - tags = json['tags']; - } - - Map toJSON(){ + RolesTags.fromJSON(Map json) { + tags = json['tags']; + } + + Map toJSON() { final data = { 'tags': tags, }; return data; } - RolesTags empty(){ + RolesTags empty() { return RolesTags(tags: []); } -} \ No newline at end of file +} diff --git a/lib/phonebook/providers/association_id_provider.dart b/lib/phonebook/providers/association_id_provider.dart index c8385d61b..1ce49655a 100644 --- a/lib/phonebook/providers/association_id_provider.dart +++ b/lib/phonebook/providers/association_id_provider.dart @@ -9,4 +9,5 @@ class AssociationIdNotifier extends StateNotifier { } final associationIdProvider = - StateNotifierProvider((ref) => AssociationIdNotifier()); \ No newline at end of file + StateNotifierProvider( + (ref) => AssociationIdNotifier()); diff --git a/lib/phonebook/providers/association_kind_provider.dart b/lib/phonebook/providers/association_kind_provider.dart index 5b9b3026c..2c209423a 100644 --- a/lib/phonebook/providers/association_kind_provider.dart +++ b/lib/phonebook/providers/association_kind_provider.dart @@ -1,7 +1,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; - -final associationKindProvider = StateNotifierProvider((ref) { +final associationKindProvider = + StateNotifierProvider((ref) { return AssociationKindNotifier(); }); @@ -11,4 +11,4 @@ class AssociationKindNotifier extends StateNotifier { void setKind(String i) { state = i; } -} \ No newline at end of file +} diff --git a/lib/phonebook/providers/association_kinds_provider.dart b/lib/phonebook/providers/association_kinds_provider.dart index a4005f0bc..07fa98429 100644 --- a/lib/phonebook/providers/association_kinds_provider.dart +++ b/lib/phonebook/providers/association_kinds_provider.dart @@ -6,13 +6,12 @@ import 'package:myecl/phonebook/repositories/association_repository.dart'; import 'package:myecl/tools/providers/single_notifier.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; - class AssociationKindsNotifier extends SingleNotifier { final AssociationRepository associationRepository = AssociationRepository(); - AssociationKindsNotifier({required String token}) - : super(const AsyncValue.loading()) { - associationRepository.setToken(token); - } + AssociationKindsNotifier({required String token}) + : super(const AsyncValue.loading()) { + associationRepository.setToken(token); + } void setKind(AssociationKinds i) { state = AsyncValue.data(i); @@ -20,17 +19,19 @@ class AssociationKindsNotifier extends SingleNotifier { Future> loadAssociationKinds() async { debugPrint("loadAssociationKinds"); - AsyncValue result = await load(() async => associationRepository.getAssociationKinds()); + AsyncValue result = + await load(() async => associationRepository.getAssociationKinds()); debugPrint("loadAssociationKinds result: $result"); return result; } } -final associationKindsProvider = StateNotifierProvider>((ref) { +final associationKindsProvider = StateNotifierProvider>((ref) { final token = ref.watch(tokenProvider); - AssociationKindsNotifier notifier = AssociationKindsNotifier(token: token); + AssociationKindsNotifier notifier = AssociationKindsNotifier(token: token); tokenExpireWrapperAuth(ref, () async { await notifier.loadAssociationKinds(); }); return notifier; -}); \ No newline at end of file +}); diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index 51f80e124..169979117 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -9,19 +9,20 @@ class AssociationListNotifier extends ListNotifier { final AssociationRepository associationRepository = AssociationRepository(); AsyncValue> associationList = const AsyncValue.loading(); AssociationListNotifier({ - required String token,}) - : super(const AsyncValue.loading()) { + required String token, + }) : super(const AsyncValue.loading()) { associationRepository.setToken(token); } - Future>> loadAssociations() async { - associationList = await loadList(() async => associationRepository.getAssociationList()); + associationList = + await loadList(() async => associationRepository.getAssociationList()); return associationList; } Future createAssociation(Association association) async { - final result = await add(associationRepository.createAssociation, association); + final result = + await add(associationRepository.createAssociation, association); if (result) { associationList = state; } @@ -31,8 +32,9 @@ class AssociationListNotifier extends ListNotifier { Future updateAssociation(Association association) async { final result = await update( associationRepository.updateAssociation, - (associations, association) => - associations..[associations.indexWhere((g) => g.id == association.id)] = association, + (associations, association) => associations + ..[associations.indexWhere((g) => g.id == association.id)] = + association, association); if (result) { associationList = state; @@ -43,7 +45,8 @@ class AssociationListNotifier extends ListNotifier { Future deleteAssociation(Association association) async { final result = await delete( associationRepository.deleteAssociation, - (associations, association) => associations..removeWhere((i) => i.id == association.id), + (associations, association) => + associations..removeWhere((i) => i.id == association.id), association.id, association); if (result) { @@ -55,32 +58,35 @@ class AssociationListNotifier extends ListNotifier { void filterAssociationList(String nameFilter, String kindFilter) async { if (kindFilter == "") { associationList.maybeWhen( - data: (data) => state = AsyncValue.data(data.where((element) => - element.name.toLowerCase().contains(nameFilter.toLowerCase())).toList()), - orElse: () => state = const AsyncLoading(),); - } - else { - associationList.maybeWhen( - data: (data) => state = AsyncValue.data(data.where((element) => - (element.name.toLowerCase().contains(nameFilter.toLowerCase()) & (element.kind == kindFilter)) - ).toList()), - orElse: () => state = const AsyncLoading(),); + data: (data) => state = AsyncValue.data(data + .where((element) => + element.name.toLowerCase().contains(nameFilter.toLowerCase())) + .toList()), + orElse: () => state = const AsyncLoading(), + ); + } else { + associationList.maybeWhen( + data: (data) => state = AsyncValue.data(data + .where((element) => + (element.name.toLowerCase().contains(nameFilter.toLowerCase()) & + (element.kind == kindFilter))) + .toList()), + orElse: () => state = const AsyncLoading(), + ); } } void setAssociationList(List associationList) { state.whenData( (d) { - state = - AsyncValue.data(associationList); + state = AsyncValue.data(associationList); }, ); } } -final associationListProvider = - StateNotifierProvider>>( - (ref) { +final associationListProvider = StateNotifierProvider>>((ref) { final token = ref.watch(tokenProvider); AssociationListNotifier notifier = AssociationListNotifier(token: token); tokenExpireWrapperAuth(ref, () async { diff --git a/lib/phonebook/providers/association_member_list_provider.dart b/lib/phonebook/providers/association_member_list_provider.dart index 242753ea7..56c02e85e 100644 --- a/lib/phonebook/providers/association_member_list_provider.dart +++ b/lib/phonebook/providers/association_member_list_provider.dart @@ -7,25 +7,28 @@ import 'package:myecl/tools/providers/list_notifier.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; class AssociationMemberListNotifier extends ListNotifier { - final AssociationMemberRepository associationMemberRepository = AssociationMemberRepository(); + final AssociationMemberRepository associationMemberRepository = + AssociationMemberRepository(); AssociationMemberListNotifier({required String token}) : super(const AsyncValue.loading()) { associationMemberRepository.setToken(token); } - Future>> loadMembers(String associationId) async { - return await loadList(() async => associationMemberRepository.getAssociationMemberList(associationId)); + Future>> loadMembers( + String associationId) async { + return await loadList(() async => + associationMemberRepository.getAssociationMemberList(associationId)); } } -final associationMemberListProvider = - StateNotifierProvider>>( - (ref) { +final associationMemberListProvider = StateNotifierProvider< + AssociationMemberListNotifier, AsyncValue>>((ref) { final token = ref.watch(tokenProvider); - AssociationMemberListNotifier provider = AssociationMemberListNotifier(token: token); + AssociationMemberListNotifier provider = + AssociationMemberListNotifier(token: token); tokenExpireWrapperAuth(ref, () async { final association = ref.watch(associationProvider); await provider.loadMembers(association.id); }); return provider; -}); \ No newline at end of file +}); diff --git a/lib/phonebook/providers/association_picture_provider.dart b/lib/phonebook/providers/association_picture_provider.dart index a2ce9d64b..45a32e794 100644 --- a/lib/phonebook/providers/association_picture_provider.dart +++ b/lib/phonebook/providers/association_picture_provider.dart @@ -1,4 +1,3 @@ - import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; @@ -12,7 +11,6 @@ final associationPictureProvider = return notifier; }); - class AssociationPictureNotifier extends SingleNotifier { final AssociationPictureRepository associationPictureRepository = AssociationPictureRepository(); @@ -20,14 +18,14 @@ class AssociationPictureNotifier extends SingleNotifier { associationPictureRepository.setToken(token); } - Future> getAssociationPicture(String associationId) async { - return await load( - () async => associationPictureRepository.getAssociationPicture(associationId)); + Future getAssociationPicture(String associationId) async { + return await associationPictureRepository + .getAssociationPicture(associationId); } - Future> updateAssociationPicture(String associationId, String path) async { - return await load( - () => associationPictureRepository.addAssociationPicture(path, associationId)); + Future updateAssociationPicture( + String associationId, String path) async { + return await associationPictureRepository.addAssociationPicture( + path, associationId); } } - diff --git a/lib/phonebook/providers/associations_pictures_provider.dart b/lib/phonebook/providers/associations_pictures_provider.dart index 6462b2e1c..5207db8d2 100644 --- a/lib/phonebook/providers/associations_pictures_provider.dart +++ b/lib/phonebook/providers/associations_pictures_provider.dart @@ -9,7 +9,8 @@ class AssociationPictureNotifier extends MapNotifier { AssociationPictureNotifier() : super(); } -final associationPicturesProvider = StateNotifierProvider>>>>((ref) { AssociationPictureNotifier associationPictureNotifier = AssociationPictureNotifier(); @@ -29,4 +30,4 @@ final associationPicturesProvider = StateNotifierProvider((ref) { +final completeMemberProvider = + StateNotifierProvider((ref) { return CompleteMemberProvider(); }); @@ -17,4 +17,4 @@ class CompleteMemberProvider extends StateNotifier { void setMember(Member i) { state = state.copyWith(member: i); } -} \ No newline at end of file +} diff --git a/lib/phonebook/providers/edition_provider.dart b/lib/phonebook/providers/edition_provider.dart index fff792a62..ecaec63a6 100644 --- a/lib/phonebook/providers/edition_provider.dart +++ b/lib/phonebook/providers/edition_provider.dart @@ -1,6 +1,5 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; - final editionProvider = StateNotifierProvider((ref) { return EditionProvider(); }); @@ -11,4 +10,4 @@ class EditionProvider extends StateNotifier { void setStatus(bool i) { state = i; } -} \ No newline at end of file +} diff --git a/lib/phonebook/providers/member_provider.dart b/lib/phonebook/providers/member_provider.dart index 71311c3bf..74c016769 100644 --- a/lib/phonebook/providers/member_provider.dart +++ b/lib/phonebook/providers/member_provider.dart @@ -1,7 +1,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/phonebook/class/member.dart'; - final memberProvider = StateNotifierProvider((ref) { return MemberProvider(); }); @@ -12,4 +11,4 @@ class MemberProvider extends StateNotifier { void setMember(Member i) { state = i; } -} \ No newline at end of file +} diff --git a/lib/phonebook/providers/member_role_tags_provider.dart b/lib/phonebook/providers/member_role_tags_provider.dart index d0e09a7c0..363f63fef 100644 --- a/lib/phonebook/providers/member_role_tags_provider.dart +++ b/lib/phonebook/providers/member_role_tags_provider.dart @@ -3,15 +3,15 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/phonebook/class/roles_tags.dart'; import 'package:tuple/tuple.dart'; - -final memberRoleTagsProvider = StateNotifierProvider>((ref) { +final memberRoleTagsProvider = + StateNotifierProvider>((ref) { return MemberRoleTagsProvider(); }); class MemberRoleTagsProvider extends StateNotifier> { MemberRoleTagsProvider() : super([]); - void setRoleTagsWithFilter(Tuple2> data) { + void setRoleTagsWithFilter(Tuple2> data) { debugPrint(data.item1.tags.toString()); debugPrint(data.item2.toString()); List newRoleTags = []; @@ -23,4 +23,4 @@ class MemberRoleTagsProvider extends StateNotifier> { state = newRoleTags; debugPrint(state.toString()); } -} \ No newline at end of file +} diff --git a/lib/phonebook/providers/membership_provider.dart b/lib/phonebook/providers/membership_provider.dart index e47ee35a1..883a2012c 100644 --- a/lib/phonebook/providers/membership_provider.dart +++ b/lib/phonebook/providers/membership_provider.dart @@ -1,16 +1,15 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/phonebook/class/membership.dart'; - - -final membershipProvider = StateNotifierProvider((ref) { +final membershipProvider = + StateNotifierProvider((ref) { return MembershipProvider(); }); class MembershipProvider extends StateNotifier { -MembershipProvider() : super(Membership.empty()); + MembershipProvider() : super(Membership.empty()); void setMembership(Membership i) { state = i; } -} \ No newline at end of file +} diff --git a/lib/phonebook/providers/phonebook_page_provider.dart b/lib/phonebook/providers/phonebook_page_provider.dart index 00548b3ef..681562e0e 100644 --- a/lib/phonebook/providers/phonebook_page_provider.dart +++ b/lib/phonebook/providers/phonebook_page_provider.dart @@ -10,8 +10,8 @@ enum PhonebookPage { membershipEdition } - -final phonebookPageProvider = StateNotifierProvider((ref) { +final phonebookPageProvider = + StateNotifierProvider((ref) { return PhonebookPageNotifier(); }); @@ -21,4 +21,4 @@ class PhonebookPageNotifier extends StateNotifier { void setPhonebookPage(PhonebookPage i) { state = i; } -} \ No newline at end of file +} diff --git a/lib/phonebook/providers/reload_provider.dart b/lib/phonebook/providers/reload_provider.dart index 3fd1f1ae7..6594cb959 100644 --- a/lib/phonebook/providers/reload_provider.dart +++ b/lib/phonebook/providers/reload_provider.dart @@ -1,6 +1,5 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; - final reloadProvider = StateNotifierProvider((ref) { return ReloadProvider(); }); @@ -11,4 +10,4 @@ class ReloadProvider extends StateNotifier { void setStatus(bool i) { state = i; } -} \ No newline at end of file +} diff --git a/lib/phonebook/providers/research_filter_provider.dart b/lib/phonebook/providers/research_filter_provider.dart index 8791da651..27a37b7f1 100644 --- a/lib/phonebook/providers/research_filter_provider.dart +++ b/lib/phonebook/providers/research_filter_provider.dart @@ -1,16 +1,13 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; - final filterProvider = StateNotifierProvider((ref) { return FilterNotifier(); }); class FilterNotifier extends StateNotifier { - FilterNotifier( - ) : super(""); - + FilterNotifier() : super(""); void setFilter(String i) { state = i; } -} \ No newline at end of file +} diff --git a/lib/phonebook/providers/roles_tags_provider.dart b/lib/phonebook/providers/roles_tags_provider.dart index 6ea272041..12e3f9dec 100644 --- a/lib/phonebook/providers/roles_tags_provider.dart +++ b/lib/phonebook/providers/roles_tags_provider.dart @@ -8,25 +8,25 @@ import 'package:myecl/tools/providers/single_notifier.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:tuple/tuple.dart'; - -class RolesTagsNotifier extends SingleNotifier>> { +class RolesTagsNotifier extends SingleNotifier>> { final RolesTagsRepository rolesTagsRepository = RolesTagsRepository(); - RolesTagsNotifier({required String token}) - : super(const AsyncValue.loading()) { - rolesTagsRepository.setToken(token); - } + RolesTagsNotifier({required String token}) + : super(const AsyncValue.loading()) { + rolesTagsRepository.setToken(token); + } void setRole(RolesTags i) { state = AsyncValue.data(Tuple2(i, state.value!.item2)); } - Future>>> loadRolesTags() async { + Future>>> loadRolesTags() async { return await load(() async => rolesTagsRepository.getRolesTags()); } void resetChecked() { final checked = state.value!.item2; - state = AsyncValue.data(Tuple2(state.value!.item1, List.filled(checked.length, false))); + state = AsyncValue.data( + Tuple2(state.value!.item1, List.filled(checked.length, false))); } void setChecked(int index, bool value) { @@ -43,14 +43,14 @@ class RolesTagsNotifier extends SingleNotifier>> { } state = AsyncValue.data(Tuple2(state.value!.item1, checked)); } - } -final rolesTagsProvider = StateNotifierProvider>>>((ref) { +final rolesTagsProvider = StateNotifierProvider>>>((ref) { final token = ref.watch(tokenProvider); - RolesTagsNotifier notifier = RolesTagsNotifier(token: token); + RolesTagsNotifier notifier = RolesTagsNotifier(token: token); tokenExpireWrapperAuth(ref, () async { await notifier.loadRolesTags(); }); return notifier; -}); \ No newline at end of file +}); diff --git a/lib/phonebook/repositories/association_kind_repository.dart b/lib/phonebook/repositories/association_kind_repository.dart deleted file mode 100644 index e69de29bb..000000000 diff --git a/lib/phonebook/repositories/association_picture_repository.dart b/lib/phonebook/repositories/association_picture_repository.dart index 4e03e7864..e0b469d30 100644 --- a/lib/phonebook/repositories/association_picture_repository.dart +++ b/lib/phonebook/repositories/association_picture_repository.dart @@ -16,7 +16,8 @@ class AssociationPictureRepository extends LogoRepository { Future addAssociationPicture(String path, String associationId) async { final image = await saveLogoToTemp(path); - final uint8List = await addLogo(image.path, associationId, suffix: "/picture"); + final uint8List = + await addLogo(image.path, associationId, suffix: "/picture"); return Image.memory(uint8List); } } diff --git a/lib/phonebook/repositories/member_repository.dart b/lib/phonebook/repositories/member_repository.dart index 3ec3c8b98..ed68b469e 100644 --- a/lib/phonebook/repositories/member_repository.dart +++ b/lib/phonebook/repositories/member_repository.dart @@ -9,8 +9,8 @@ class MemberRepository extends Repository { final ext = "phonebook/member/"; Future> getMemberMembershipList(int memberId) async { - return List.from( - (await getList(suffix: "/$memberId/posts")).map((x) => Membership.fromJSON(x))); + return List.from((await getList(suffix: "/$memberId/posts")) + .map((x) => Membership.fromJSON(x))); } Future getMember(String memberId) async { @@ -20,4 +20,4 @@ class MemberRepository extends Repository { Future getCompleteMember(String memberId) async { return CompleteMember.fromJSON(await getOne(memberId, suffix: "complete")); } -} \ No newline at end of file +} diff --git a/lib/phonebook/repositories/role_tags_repository.dart b/lib/phonebook/repositories/role_tags_repository.dart index 955c381c8..14ee70ece 100644 --- a/lib/phonebook/repositories/role_tags_repository.dart +++ b/lib/phonebook/repositories/role_tags_repository.dart @@ -7,10 +7,8 @@ class RolesTagsRepository extends Repository { // ignore: overridden_fields final ext = "phonebook/"; - Future>> getRolesTags() async { + Future>> getRolesTags() async { RolesTags rolesTags = RolesTags.fromJSON(await getOne("roletags")); - return Tuple2(rolesTags,List.filled(rolesTags.tags.length, false)); + return Tuple2(rolesTags, List.filled(rolesTags.tags.length, false)); } } - - diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index ba2c6f49c..59f2add72 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -9,11 +9,13 @@ class PhonebookTextConstants { static const String phonebookSearchRole = "Poste"; static const String phonebookSearchAssociation = "Association"; static const String phonebookSearchField = "Rechercher :"; - static const String updatedAssociationPicture = "La photo d'association a été changée"; + static const String updatedAssociationPicture = + "La photo d'association a été changée"; static const String tooHeavyAssociationPicture = "L'image est trop lourde (max 4Mo)"; static const String membershipRole = "Rôle :"; - static const String membershipAssociationError = "Veuillez choisir une association"; + static const String membershipAssociationError = + "Veuillez choisir une association"; static const String membershipRoleError = "Veuillez choisir un rôle"; static const String validation = "Valider"; static const String cancel = "Annuler"; @@ -30,23 +32,29 @@ class PhonebookTextConstants { static const String adminPage = "Page Administrateur"; static const String admin = "Admin"; static const String addAssociation = "Ajouter une association"; - static const String errorLoadAssociationPicture = "Erreur lors du chargement de la photo d'association"; + static const String errorLoadAssociationPicture = + "Erreur lors du chargement de la photo d'association"; static const String deleting = "Suppression"; static const String deleteAssociation = "Supprimer l'association ?"; static const String deletedAssociation = "Association supprimée"; static const String deletingError = "Erreur lors de la suppression"; - static const String errorLoadAssociationList = "Erreur lors du chargement de la liste des associations"; + static const String errorLoadAssociationList = + "Erreur lors du chargement de la liste des associations"; static const String associationDetail = "Détail de l'association :"; - static const String errorLoadAssociationMember = "Erreur lors du chargement des membres de l'association"; + static const String errorLoadAssociationMember = + "Erreur lors du chargement des membres de l'association"; static const String updatingError = "Erreur lors de la modification"; static const String errorLoadProfilePicture = "Erreur"; static const String updatedAssociation = "Association modifiée"; - static const String errorAssociationLoading = "Erreur lors du chargement de l'association"; - static const String errorAssociationNameEmpty = "Veuillez entrer un nom d'association"; + static const String errorAssociationLoading = + "Erreur lors du chargement de l'association"; + static const String errorAssociationNameEmpty = + "Veuillez entrer un nom d'association"; static const String addedAssociation = "Association ajoutée"; static const String deletedMember = "Membre supprimé"; static const String associationKind = "Type d'association :"; - static const String errorKindsLoading = "Erreur lors du chargement des types d'association"; + static const String errorKindsLoading = + "Erreur lors du chargement des types d'association"; static const String emptyFieldError = "Un champ n'est pas rempli"; static const String emptyKindError = "Veuillez choisir un type d'association"; static const String edit = "Modifier"; @@ -61,17 +69,20 @@ class PhonebookTextConstants { static const String add = "Ajouter"; static const String emptyMember = "Aucun membre sélectionné"; static const String emptyApparentName = "Veuillez entrer un nom de role"; - static const String errorRoleTagsLoading = "Erreur lors du chargement des tags de rôle"; + static const String errorRoleTagsLoading = + "Erreur lors du chargement des tags de rôle"; static const String promotion = "Promotion :"; static const String newMandateConfirmed = "Mandat changé"; - static const String mandateChangingError = "Erreur lors du changement de mandat"; - static const String changeMandateConfirm = "Êtes-vous sûr de vouloir changer tout le mandat ?\nCette action est irréversible !"; + static const String mandateChangingError = + "Erreur lors du changement de mandat"; + static const String changeMandateConfirm = + "Êtes-vous sûr de vouloir changer tout le mandat ?\nCette action est irréversible !"; static const String newMandate = "Nouveau mandat"; static const String changeMandate = "Passer au mandat "; static const String activeMandate = "Mandat actif :"; } -class PhonebookColorConstants{ +class PhonebookColorConstants { static const Color textDark = Color(0xFF1D1D1D); -} \ No newline at end of file +} diff --git a/lib/phonebook/tools/fake_class.dart b/lib/phonebook/tools/fake_class.dart deleted file mode 100644 index 07122c2aa..000000000 --- a/lib/phonebook/tools/fake_class.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/class/association_kinds.dart'; -import 'package:myecl/phonebook/class/complete_member.dart'; -import 'package:myecl/phonebook/class/member.dart'; -import 'package:myecl/phonebook/class/membership.dart'; -import 'package:myecl/phonebook/class/roles_tags.dart'; - -String printFakeAssociations() { - String result = ''; - for (Association association in fakeAssociations) { - result += '$association\n'; - } - return result; -} - - -List fakeAssociations = [ - Association(id: '1', name: 'test1', description: 'description test1', kind: 'Section', mandateYear: "2023"), - Association(id: '2', name: 'test2', description: 'description test2', kind: 'Club', mandateYear: "2023"), -]; - -RolesTags fakeRolesTags = RolesTags(tags: [ - 'Prez\'', - 'Trez\'', - 'SG', - 'VP com', - 'VP sponsor', -]); - -AssociationKinds fakeAssociationKinds = AssociationKinds(kinds: [ - 'Section', - 'Club', - 'Comité', - 'Fédération', - 'Association', - 'Autre', -]); - - -List fakeMembersList = [ - CompleteMember( - member: Member( - name: 'Dupond', - firstname: 'Michel', - nickname: 'Testouille', - id: '1', - email: 'test1@useless', - promotion: 'E21'), - memberships: [Membership(id:"1", association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[0]], apparentName: 'Prez\'')]), - CompleteMember( - member: Member( - name: 'Debouck', - firstname: 'Frank', - nickname: 'Chad', - id: '2', - email: 'test2@useless', - promotion: 'E22'), - memberships: [Membership(id:"2", association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[1]], apparentName: 'Trez\'')]), - CompleteMember( - member: Member( - name: 'Ray', - firstname: 'Pascal', - nickname: 'Salut', - id: '3', - email: 'test3@useless', - promotion: 'E21'), - memberships: [Membership(id:"3", association: fakeAssociations[1], rolesTags: [fakeRolesTags.tags[2]], apparentName: 'SG')]), - CompleteMember( - member: Member( - name: 'Guarriguenc', - firstname: 'Jean-Luc', - nickname: 'Cascouille', - id: '4', - email: 'test4@useless', - promotion: 'E20'), - memberships: [ - Membership(id:"4", association: fakeAssociations[1], rolesTags: [fakeRolesTags.tags[0]], apparentName: 'Prez\''), - Membership(id:"5", association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[4]], apparentName: 'VP sponsor'), - ]), - CompleteMember( - member: Member( - name: 'Boulet', - firstname: 'Jean', - nickname: 'Jean', - id: '5', - email: 'test5@useless', - promotion: 'E20'), - memberships: [Membership(id:"6", association: fakeAssociations[1], rolesTags: [], apparentName: 'VP Emprunt')]), - CompleteMember( - member: Member( - name: 'Sarrazin', - firstname: 'François', - nickname: 'Zarzou', - id: '6', - email: 'test6@useless', - promotion: 'E21'), - memberships: [ - Membership(id:"7", association: fakeAssociations[0], rolesTags: [fakeRolesTags.tags[3]], apparentName: 'VP com'), - Membership(id:"8", association: fakeAssociations[0], rolesTags: [], apparentName: 'VP Event')]), - ]; - diff --git a/lib/phonebook/ui/association_card.dart b/lib/phonebook/ui/association_card.dart index 47e9116e0..c3ad8c219 100644 --- a/lib/phonebook/ui/association_card.dart +++ b/lib/phonebook/ui/association_card.dart @@ -5,6 +5,7 @@ import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/associations_pictures_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; class AssociationCard extends HookConsumerWidget { const AssociationCard({ @@ -55,20 +56,17 @@ class AssociationCard extends HookConsumerWidget { ), ); } else { - associationPictureNotifier - .getAssociationPicture(association.id) - .then((value) { - associationPicturesNotifier.setTData( - association, - AsyncData([ - value.when( - data: (picture) => picture, - loading: () => - Image.asset("assets/images/logo.png"), - error: (e, s) => - Image.asset("assets/images/logo.png"), - ) - ])); + Future.delayed( + const Duration(milliseconds: 1), + () => associationPicturesNotifier.setTData( + association, const AsyncLoading())); + tokenExpireWrapper(ref, () async { + associationPictureNotifier + .getAssociationPicture(association.id) + .then((value) { + associationPicturesNotifier.setTData( + association, AsyncData([value])); + }); }); return const HeroIcon( HeroIcons.userCircle, diff --git a/lib/phonebook/ui/delete_button.dart b/lib/phonebook/ui/delete_button.dart index 8e505b545..0d2a50976 100644 --- a/lib/phonebook/ui/delete_button.dart +++ b/lib/phonebook/ui/delete_button.dart @@ -6,65 +6,64 @@ import 'package:myecl/tools/ui/shrink_button.dart'; class DeleteButton extends StatelessWidget { final Future Function() onDelete; - const DeleteButton({Key? key, - required this.onDelete}) : super(key: key); + const DeleteButton({Key? key, required this.onDelete}) : super(key: key); @override Widget build(BuildContext context) { return ShrinkButton( - waitChild: Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.3), - spreadRadius: 2, - blurRadius: 4, - offset: const Offset(2, 3), - ), - ], - borderRadius: BorderRadius.circular(10), - ), - child: const Center( - child: CircularProgressIndicator( - color: Colors.white, - ), - ), - ), - onTap: onDelete, - child: Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.3), - spreadRadius: 2, - blurRadius: 4, - offset: const Offset(2, 3), - ), - ], - borderRadius: BorderRadius.circular(10), - ), - child: const HeroIcon( - HeroIcons.xMark, - color: Colors.white, - ), - )); + waitChild: Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.3), + spreadRadius: 2, + blurRadius: 4, + offset: const Offset(2, 3), + ), + ], + borderRadius: BorderRadius.circular(10), + ), + child: const Center( + child: CircularProgressIndicator( + color: Colors.white, + ), + ), + ), + onTap: onDelete, + child: Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.3), + spreadRadius: 2, + blurRadius: 4, + offset: const Offset(2, 3), + ), + ], + borderRadius: BorderRadius.circular(10), + ), + child: const HeroIcon( + HeroIcons.xMark, + color: Colors.white, + ), + )); } -} \ No newline at end of file +} diff --git a/lib/phonebook/ui/edition_button.dart b/lib/phonebook/ui/edition_button.dart index 2d2588166..f40b88235 100644 --- a/lib/phonebook/ui/edition_button.dart +++ b/lib/phonebook/ui/edition_button.dart @@ -1,4 +1,3 @@ - import 'package:flutter/material.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -9,28 +8,26 @@ class EditionButton extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - return GestureDetector( - onTap: (){ - onEdition(); - }, - child: Container( - width: 40, - height: 40, - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.grey.shade200, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.2), - blurRadius: 10, - offset: const Offset(2, 3)) - ], - ), - child: const HeroIcon(HeroIcons.pencil, - color: Colors.black), - ), - ); + onTap: () { + onEdition(); + }, + child: Container( + width: 40, + height: 40, + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.grey.shade200, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 10, + offset: const Offset(2, 3)) + ], + ), + child: const HeroIcon(HeroIcons.pencil, color: Colors.black), + ), + ); } -} \ No newline at end of file +} diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index dec45f1e4..860642964 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -42,35 +42,35 @@ class AdminPage extends HookConsumerWidget { child: Column(children: [ const SizedBox(width: 10), associationKinds.when( - data: (data) { - return SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row(children: [ - RadioChip( - label: "Toutes", - selected: kind.value == "", - onTap: () { - kind.value = ""; - kindNotifier.setKind(""); - associationsNotifier.filterAssociationList(nameFilter, kind.value); - }), - ...data.kinds - .map((e) => RadioChip( - label: e, - selected: kind.value == e, + data: (data) { + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row(children: [ + RadioChip( + label: "Toutes", + selected: kind.value == "", onTap: () { - kind.value = e; - kindNotifier.setKind(e); - associationsNotifier.filterAssociationList(nameFilter, kind.value); - })) - .toList() - ] - ) - ); - }, - error: (error, stackTrace) => - const Text(PhonebookTextConstants.errorRoleTagsLoading), - loading: () => const CircularProgressIndicator()), + kind.value = ""; + kindNotifier.setKind(""); + associationsNotifier.filterAssociationList( + nameFilter, kind.value); + }), + ...data.kinds + .map((e) => RadioChip( + label: e, + selected: kind.value == e, + onTap: () { + kind.value = e; + kindNotifier.setKind(e); + associationsNotifier.filterAssociationList( + nameFilter, kind.value); + })) + .toList() + ])); + }, + error: (error, stackTrace) => + const Text(PhonebookTextConstants.errorRoleTagsLoading), + loading: () => const CircularProgressIndicator()), const SizedBox(height: 10), const AssociationResearchBar(), const SizedBox(height: 10), diff --git a/lib/phonebook/ui/pages/admin_page/editable_association_card.dart b/lib/phonebook/ui/pages/admin_page/editable_association_card.dart index 5b0248544..0d3802d87 100644 --- a/lib/phonebook/ui/pages/admin_page/editable_association_card.dart +++ b/lib/phonebook/ui/pages/admin_page/editable_association_card.dart @@ -7,6 +7,7 @@ import 'package:myecl/phonebook/providers/associations_pictures_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/delete_button.dart'; import 'package:myecl/phonebook/ui/edition_button.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; class EditableAssociationCard extends HookConsumerWidget { final Association association; @@ -43,81 +44,75 @@ class EditableAssociationCard extends HookConsumerWidget { width: 10, ), associationPictures.when( - data: (pictures) { - if (pictures[association] != null) { - return pictures[association]!.when( - data: (picture) { - if (picture.isNotEmpty) { - return Container( - width: 40, - height: 40, - decoration: BoxDecoration( - shape: BoxShape.circle, - image: DecorationImage( - image: picture.first.image, - fit: BoxFit.cover, - ), - ), - ); - } else { - associationPictureNotifier - .getAssociationPicture(association.id) - .then((value) { - associationPicturesNotifier.setTData( - association, - AsyncData([ - value.when( - data: (picture) => picture, - loading: () => - Image.asset("assets/images/logo.png"), - error: (e, s) => - Image.asset("assets/images/logo.png"), - ) - ])); - }); - return const HeroIcon( - HeroIcons.userCircle, - size: 40, - ); - } - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: Text(PhonebookTextConstants - .errorLoadAssociationPicture), - ); - }, + data: (pictures) { + if (pictures[association] != null) { + return pictures[association]!.when( + data: (picture) { + if (picture.isNotEmpty) { + return Container( + width: 40, + height: 40, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: picture.first.image, + fit: BoxFit.cover, + ), + ), + ); + } else { + Future.delayed( + const Duration(milliseconds: 1), + () => associationPicturesNotifier.setTData( + association, const AsyncLoading())); + tokenExpireWrapper(ref, () async { + associationPictureNotifier + .getAssociationPicture(association.id) + .then((value) { + associationPicturesNotifier.setTData( + association, AsyncData([value])); + }); + }); + return const HeroIcon( + HeroIcons.userCircle, + size: 40, + ); + } + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), ); - } - return const HeroIcon( - HeroIcons.userCircle, - size: 40, - ); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: Text( - PhonebookTextConstants.errorLoadAssociationPicture), - ); - }, - ), + }, + error: (e, s) { + return const Center( + child: Text( + PhonebookTextConstants.errorLoadAssociationPicture), + ); + }, + ); + } + return const HeroIcon( + HeroIcons.userCircle, + size: 40, + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return const Center( + child: Text(PhonebookTextConstants.errorLoadAssociationPicture), + ); + }, + ), const SizedBox(width: 10), Text( association.name, style: const TextStyle( - color: Colors.black, - fontSize: 20, - fontWeight: FontWeight.bold), + color: Colors.black, fontSize: 20, fontWeight: FontWeight.bold), ), const Spacer(), Text(association.kind, @@ -133,8 +128,6 @@ class EditableAssociationCard extends HookConsumerWidget { DeleteButton(onDelete: () async { await onDelete(); }), - - ], ), ); diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 4bef7f728..badf349aa 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -288,9 +288,11 @@ class AssociationEditorPage extends HookConsumerWidget { ShrinkButton( onTap: () async { rolesTagsNotifier.resetChecked(); - completeMemberNotifier.setCompleteMember(CompleteMember.empty()); + completeMemberNotifier + .setCompleteMember(CompleteMember.empty()); editionNotifier.setStatus(false); - pageNotifier.setPhonebookPage(PhonebookPage.membershipEdition); + pageNotifier + .setPhonebookPage(PhonebookPage.membershipEdition); }, child: Container( width: 40, @@ -364,7 +366,8 @@ class AssociationEditorPage extends HookConsumerWidget { context: context, builder: (context) => AlertDialog( title: const Text(PhonebookTextConstants.newMandate), - content: const Text(PhonebookTextConstants.changeMandateConfirm), + content: + const Text(PhonebookTextConstants.changeMandateConfirm), actions: [ TextButton( onPressed: () { @@ -378,7 +381,9 @@ class AssociationEditorPage extends HookConsumerWidget { await tokenExpireWrapper(ref, () async { final value = await associationListNotifier .updateAssociation(association.copyWith( - mandateYear: (int.parse(association.mandateYear)+1).toString())); + mandateYear: + (int.parse(association.mandateYear) + 1) + .toString())); if (value) { displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.newMandateConfirmed); @@ -392,7 +397,7 @@ class AssociationEditorPage extends HookConsumerWidget { ), ], ), - ); + ); }, child: Container( width: double.infinity, @@ -417,7 +422,7 @@ class AssociationEditorPage extends HookConsumerWidget { borderRadius: BorderRadius.circular(15), ), child: Text( - "${PhonebookTextConstants.changeMandate} ${(int.parse(association.mandateYear)+1).toString()}", + "${PhonebookTextConstants.changeMandate} ${(int.parse(association.mandateYear) + 1).toString()}", style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w600, diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index a732c025c..bfd6d0b60 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -121,11 +121,9 @@ class MemberEditableCard extends HookConsumerWidget { const SizedBox(width: 10), DeleteButton( onDelete: () async { - final result = - await associationNotifier.deleteMember( - member.memberships.firstWhere( - (element) => element.association.id == association.id) - ); + final result = await associationNotifier.deleteMember( + member.memberships.firstWhere( + (element) => element.association.id == association.id)); await associationMembersNotifier.loadMembers(association.id); if (result) { displayToastWithContext( diff --git a/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart b/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart index 44cd55a69..81dcc47ee 100644 --- a/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart +++ b/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart @@ -12,17 +12,16 @@ import 'package:myecl/user/providers/user_list_provider.dart'; import 'package:tuple/tuple.dart'; import 'package:myecl/phonebook/ui/pages/membership_editor_page/search_result.dart'; - class MembershipDialog extends HookConsumerWidget { - const MembershipDialog({ - Key? key, - required this.apparentNameController, - required this.title, - required this.defaultText, - required this.onConfirm, - required this.member, - required this.association - }) : super(key: key); + const MembershipDialog( + {Key? key, + required this.apparentNameController, + required this.title, + required this.defaultText, + required this.onConfirm, + required this.member, + required this.association}) + : super(key: key); final String title; final String defaultText; @@ -67,7 +66,7 @@ class MembershipDialog extends HookConsumerWidget { child: SingleChildScrollView( child: Column( children: [ - if (member.member.id == "") + if (member.member.id == "") TextFormField( enabled: member.member.id == "", onChanged: (value) { @@ -92,15 +91,19 @@ class MembershipDialog extends HookConsumerWidget { ), ), ), - const SizedBox( - height: 10, - ), - SearchResult(queryController: queryController), + const SizedBox( + height: 10, + ), + SearchResult(queryController: queryController), ...rolesTags.when( data: (data) { if (member.member.id != "") { for (int i = 0; i < data.item2.length; i++) { - if (member.memberships.where((e) => e.association.id == association.id).toList()[0].rolesTags.contains(data.item1.tags[i])) { + if (member.memberships + .where((e) => e.association.id == association.id) + .toList()[0] + .rolesTags + .contains(data.item1.tags[i])) { data.item2[i] = true; } } diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index aba99177d..5d76e28a1 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -47,16 +47,16 @@ class AssociationPage extends HookConsumerWidget { child: associationPicture.when( data: (picture) { return Container( - width: 40, - height: 40, - decoration: BoxDecoration( - shape: BoxShape.circle, - image: DecorationImage( - image: picture.image, - fit: BoxFit.cover, - ), - ), - ); + width: 40, + height: 40, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: picture.image, + fit: BoxFit.cover, + ), + ), + ); }, loading: () { return const Center( diff --git a/lib/phonebook/ui/pages/association_page/member_card.dart b/lib/phonebook/ui/pages/association_page/member_card.dart index 67a5e186e..cd65ae642 100644 --- a/lib/phonebook/ui/pages/association_page/member_card.dart +++ b/lib/phonebook/ui/pages/association_page/member_card.dart @@ -19,9 +19,7 @@ class MemberCard extends HookConsumerWidget { final profilePicture = ref.watch(profilePictureProvider); final association = ref.watch(associationProvider); final profilePictureNotifier = ref.watch(profilePictureProvider.notifier); - - //profilePictureNotifier.getProfilePicture(member.member.id); return GestureDetector( onTap: () { memberNotifier.setCompleteMember(member); @@ -95,7 +93,11 @@ class MemberCard extends HookConsumerWidget { ), ), const Spacer(), - Text(member.memberships.firstWhere((element) => element.association.id == association.id).apparentName, + Text( + member.memberships + .firstWhere((element) => + element.association.id == association.id) + .apparentName, style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 77d5843f2..473664614 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -39,23 +39,23 @@ class MainPage extends HookConsumerWidget { await associationKindsNotifier.loadAssociationKinds(); await associationListNotifier.loadAssociations(); }, - child: Column( - children: [ - const SizedBox(height: 70), - associationKinds.when( - data: (data) { - debugPrint("associationKinds.when data: ${data.kinds}"); - return SingleChildScrollView( + child: Column(children: [ + const SizedBox(height: 70), + associationKinds.when( + data: (data) { + debugPrint("associationKinds.when data: ${data.kinds}"); + return SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row(children: [ RadioChip( - label: "Toutes", - selected: kind.value == "", - onTap: () { - kind.value = ""; - kindNotifier.setKind(""); - associationListNotifier.filterAssociationList(nameFilter, kind.value); - }), + label: "Toutes", + selected: kind.value == "", + onTap: () { + kind.value = ""; + kindNotifier.setKind(""); + associationListNotifier.filterAssociationList( + nameFilter, kind.value); + }), ...data.kinds .map((e) => RadioChip( label: e, @@ -63,40 +63,40 @@ class MainPage extends HookConsumerWidget { onTap: () { kind.value = e; kindNotifier.setKind(e); - associationListNotifier.filterAssociationList(nameFilter, kind.value); + associationListNotifier + .filterAssociationList( + nameFilter, kind.value); })) .toList() - ] - ) - ); - }, - error: (error, stackTrace) => - const Text(PhonebookTextConstants.errorKindsLoading), - loading: () => const CircularProgressIndicator()), - const SizedBox(height: 30), - const ResearchBar(), - const SizedBox(height: 10), - ...associationList.when( - data: (associations) { - return associations - .map((association) => AssociationCard( - association: association, - onClicked: () { - associationNotifier - .setAssociation(association); - pageNotifier.setPhonebookPage( - PhonebookPage.associationPage); - }, - )) - .toList(); - }, - loading: () => - const [Center(child: CircularProgressIndicator())], - error: (error, stack) => [ - const Center( - child: Text(PhonebookTextConstants - .errorLoadAssociationList)) - ])])), + ])); + }, + error: (error, stackTrace) => + const Text(PhonebookTextConstants.errorKindsLoading), + loading: () => const CircularProgressIndicator()), + const SizedBox(height: 30), + const ResearchBar(), + const SizedBox(height: 10), + ...associationList.when( + data: (associations) { + return associations + .map((association) => AssociationCard( + association: association, + onClicked: () { + associationNotifier.setAssociation(association); + pageNotifier.setPhonebookPage( + PhonebookPage.associationPage); + }, + )) + .toList(); + }, + loading: () => + const [Center(child: CircularProgressIndicator())], + error: (error, stack) => [ + const Center( + child: Text(PhonebookTextConstants + .errorLoadAssociationList)) + ]) + ])), if (isAdmin) Positioned( top: 15, diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart index 22c5b891c..352181412 100644 --- a/lib/phonebook/ui/pages/main_page/research_bar.dart +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -16,7 +16,7 @@ class ResearchBar extends HookConsumerWidget { final filterNotifier = ref.watch(filterProvider.notifier); final associationsNotifier = ref.watch(associationListProvider.notifier); final associationKind = ref.watch(associationKindProvider); - + return Container( decoration: BoxDecoration( border: Border.all(), @@ -27,7 +27,7 @@ class ResearchBar extends HookConsumerWidget { color: Colors.grey.withOpacity(0.5), spreadRadius: 1, blurRadius: 7, - offset: const Offset(0, 3), // changes position of shadow + offset: const Offset(0, 3), ), ], ), diff --git a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart index 8ec32b0d6..06a906cfb 100644 --- a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart +++ b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart @@ -12,8 +12,7 @@ class MemberDetailPage extends HookConsumerWidget { return Container( margin: const EdgeInsets.all(10), width: MediaQuery.of(context).size.width, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(50)), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(50)), child: Column(children: [ const Text(PhonebookTextConstants.detail), Text("${PhonebookTextConstants.name} ${memberProvider.member.name}"), @@ -22,20 +21,21 @@ class MemberDetailPage extends HookConsumerWidget { if (memberProvider.member.nickname != null) Text( "${PhonebookTextConstants.nickname} ${memberProvider.member.nickname!}"), - Text("${PhonebookTextConstants.promotion} ${memberProvider.member.promotion}"), + Text( + "${PhonebookTextConstants.promotion} ${memberProvider.member.promotion}"), Text( "${PhonebookTextConstants.email} ${memberProvider.member.email}"), const Text(PhonebookTextConstants - .association), //à changer pour dépendre du nombre d'associatione + .association), //TODO: à changer pour dépendre du nombre d'associatione Column(children: [ for (var membership in memberProvider.memberships) Container( margin: const EdgeInsets.all(10), - child: Row( - children: [ - const Spacer(flex: 1), - Text("${membership.association.name} : ${membership.apparentName}"), - const Spacer(flex: 1), + child: Row(children: [ + const Spacer(flex: 1), + Text( + "${membership.association.name} : ${membership.apparentName}"), + const Spacer(flex: 1), ])) ]), ])); diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index 6faa4859f..529faf3cd 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -24,8 +24,6 @@ class MembershipEditorPage extends HookConsumerWidget { Key? key, }) : super(key: key); - - String nameConstructor(Tuple2> data) { String name = ''; for (int i = 0; i < data.item2.length; i++) { @@ -60,7 +58,8 @@ class MembershipEditorPage extends HookConsumerWidget { final association = ref.watch(associationProvider); final edition = ref.watch(editionProvider); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); - final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); + final associationMemberListNotifier = + ref.watch(associationMemberListProvider.notifier); final pageNotifier = ref.watch(phonebookPageProvider.notifier); final memberRoleTagsNotifier = ref.watch(memberRoleTagsProvider.notifier); final memberRoleTags = ref.watch(memberRoleTagsProvider); @@ -69,28 +68,30 @@ class MembershipEditorPage extends HookConsumerWidget { displayToast(context, type, msg); } - if (edition){ - apparentNameController.text = member.memberships.where((e) => e.association.id == association.id).toList()[0].apparentName; + if (edition) { + apparentNameController.text = member.memberships + .where((e) => e.association.id == association.id) + .toList()[0] + .apparentName; } return Padding( - padding: const EdgeInsets.all(20.0), - child: SingleChildScrollView( - child : Column( - children : [ + padding: const EdgeInsets.all(20.0), + child: SingleChildScrollView( + child: Column( + children: [ Center( - child: Container( - decoration: const BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.black)), - color: Colors.white, - ), - child: Text( - edition? PhonebookTextConstants.editMembership : PhonebookTextConstants.addMember, - style: const TextStyle(fontSize: 20) - ) - ) - ), - if (!edition) + child: Container( + decoration: const BoxDecoration( + border: Border(bottom: BorderSide(color: Colors.black)), + color: Colors.white, + ), + child: Text( + edition + ? PhonebookTextConstants.editMembership + : PhonebookTextConstants.addMember, + style: const TextStyle(fontSize: 20)))), + if (!edition) TextFormField( onChanged: (value) { tokenExpireWrapper(ref, () async { @@ -114,10 +115,10 @@ class MembershipEditorPage extends HookConsumerWidget { ), ), ), - const SizedBox( - height: 10, - ), - SearchResult(queryController: queryController), + const SizedBox( + height: 10, + ), + SearchResult(queryController: queryController), SizedBox( width: min(MediaQuery.of(context).size.width, 300), child: Column(children: [ @@ -129,13 +130,18 @@ class MembershipEditorPage extends HookConsumerWidget { const Spacer(), Checkbox( value: data.item2[data.item1.tags.indexOf(e)], - fillColor: MaterialStateProperty.all(Colors.black), + fillColor: + MaterialStateProperty.all(Colors.black), onChanged: (value) { - data.item2[data.item1.tags.indexOf(e)] = value!; + data.item2[data.item1.tags.indexOf(e)] = + value!; debugPrint(data.item2.toString()); - apparentNameController.text = nameConstructor(data); - memberRoleTagsNotifier.setRoleTagsWithFilter(data); - rolesTagsNotifier.setChecked(data.item1.tags.indexOf(e), value); + apparentNameController.text = + nameConstructor(data); + memberRoleTagsNotifier + .setRoleTagsWithFilter(data); + rolesTagsNotifier.setChecked( + data.item1.tags.indexOf(e), value); }, ), ])) @@ -153,14 +159,18 @@ class MembershipEditorPage extends HookConsumerWidget { ), const SizedBox(height: 5), ShrinkButton( - child: Text(!edition ? PhonebookTextConstants.add : PhonebookTextConstants.edit), + child: Text(!edition + ? PhonebookTextConstants.add + : PhonebookTextConstants.edit), onTap: () async { if (member.member.id == "") { - displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.emptyMember); + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.emptyMember); return; } if (apparentNameController.text == "") { - displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.emptyApparentName); + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.emptyApparentName); return; } debugPrint("Appui sur le bouton avec les paramètres:\n" @@ -170,36 +180,42 @@ class MembershipEditorPage extends HookConsumerWidget { "apparentName: ${apparentNameController.text}"); tokenExpireWrapper(ref, () async { if (edition) { - final value = await associationNotifier.updateMember(association, member.member, memberRoleTags, apparentNameController.text); + final value = await associationNotifier.updateMember( + association, + member.member, + memberRoleTags, + apparentNameController.text); if (value) { - associationMemberListNotifier - .loadMembers(association.id); - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.updatedMember); - pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); + associationMemberListNotifier.loadMembers(association.id); + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.updatedMember); + pageNotifier + .setPhonebookPage(PhonebookPage.associationEditor); } else { - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.updatingError); + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.updatingError); } } else { - final value = await associationNotifier.addMember(association, member.member, memberRoleTags, apparentNameController.text); + final value = await associationNotifier.addMember( + association, + member.member, + memberRoleTags, + apparentNameController.text); if (value) { - associationMemberListNotifier - .loadMembers(association.id); - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.addedMember); - pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); + associationMemberListNotifier.loadMembers(association.id); + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.addedMember); + pageNotifier + .setPhonebookPage(PhonebookPage.associationEditor); } else { - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.addingError); + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.addingError); } } }); }, ), ], - ) - ) - ); + ))); } } diff --git a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart index dcbc09525..9a5ab73a4 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart @@ -6,8 +6,7 @@ import 'package:myecl/user/providers/user_list_provider.dart'; class SearchResult extends HookConsumerWidget { final TextEditingController queryController; - const SearchResult( - {super.key, required this.queryController}); + const SearchResult({super.key, required this.queryController}); @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/lib/phonebook/ui/text_input_dialog.dart b/lib/phonebook/ui/text_input_dialog.dart index eccafffe5..d47334b1d 100644 --- a/lib/phonebook/ui/text_input_dialog.dart +++ b/lib/phonebook/ui/text_input_dialog.dart @@ -2,15 +2,15 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -class TextInputDialog extends HookConsumerWidget{ - const TextInputDialog({ - Key? key, - required this.controller, - required this.title, - required this.text, - required this.defaultText, - required this.onConfirm - }) : super(key: key); +class TextInputDialog extends HookConsumerWidget { + const TextInputDialog( + {Key? key, + required this.controller, + required this.title, + required this.text, + required this.defaultText, + required this.onConfirm}) + : super(key: key); final String title; final String text; @@ -21,45 +21,44 @@ class TextInputDialog extends HookConsumerWidget{ @override Widget build(BuildContext context, WidgetRef ref) { controller.text = defaultText; - return AlertDialog( - title: Center( + return AlertDialog( + title: Center( child: Container( - decoration: const BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.black)), - color: Colors.white, + decoration: const BoxDecoration( + border: Border(bottom: BorderSide(color: Colors.black)), + color: Colors.white, ), - child: Text(title, style: const TextStyle(fontSize: 20)) - ) - ), - content: SizedBox( - height: 100, - child: Column( + child: Text(title, style: const TextStyle(fontSize: 20)))), + content: SizedBox( + height: 100, + child: Column( children: [ const SizedBox(height: 25), Text(text), const SizedBox(height: 5), SizedBox( - width: 200, - child:TextField( - controller: controller, - ),) - ], - )), - actions: [ - TextButton( - onPressed: (){ - Navigator.of(context).pop(); - }, - child: const Text(PhonebookTextConstants.cancel), - ), - TextButton( - onPressed: () { - Navigator.of(context).pop(); - onConfirm(); - }, - child: const Text(PhonebookTextConstants.validation), - ), - ], - ); + width: 200, + child: TextField( + controller: controller, + ), + ) + ], + )), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text(PhonebookTextConstants.cancel), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + onConfirm(); + }, + child: const Text(PhonebookTextConstants.validation), + ), + ], + ); } -} \ No newline at end of file +} diff --git a/lib/phonebook/ui/top_bar.dart b/lib/phonebook/ui/top_bar.dart index 4ab40982b..a94d66aaa 100644 --- a/lib/phonebook/ui/top_bar.dart +++ b/lib/phonebook/ui/top_bar.dart @@ -32,7 +32,8 @@ class TopBar extends HookConsumerWidget { controllerNotifier.toggle(); break; case PhonebookPage.memberDetail: - pageNotifier.setPhonebookPage(PhonebookPage.associationPage); + pageNotifier.setPhonebookPage( + PhonebookPage.associationPage); break; case PhonebookPage.admin: pageNotifier.setPhonebookPage(PhonebookPage.main); @@ -47,7 +48,8 @@ class TopBar extends HookConsumerWidget { pageNotifier.setPhonebookPage(PhonebookPage.admin); break; case PhonebookPage.membershipEdition: - pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); + pageNotifier.setPhonebookPage( + PhonebookPage.associationEditor); break; } }, From 7074906bbdb0320c44ab4078d97bf02690c9094d Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:01 +0100 Subject: [PATCH 024/123] Updating main page UI Signed-off-by: Maxime Roucher --- lib/phonebook/tools/constants.dart | 2 + .../ui/pages/main_page/main_page.dart | 192 +++++++++--------- .../ui/pages/main_page/research_bar.dart | 37 +--- 3 files changed, 108 insertions(+), 123 deletions(-) diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index 59f2add72..e42239bc1 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -81,6 +81,8 @@ class PhonebookTextConstants { static const String changeMandate = "Passer au mandat "; static const String activeMandate = "Mandat actif :"; + + static const String all = "Toutes"; } class PhonebookColorConstants { diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 473664614..8d3e204ac 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -32,106 +32,104 @@ class MainPage extends HookConsumerWidget { final kindNotifier = ref.watch(associationKindProvider.notifier); final nameFilter = ref.watch(filterProvider); - return Stack( - children: [ - Refresher( - onRefresh: () async { - await associationKindsNotifier.loadAssociationKinds(); - await associationListNotifier.loadAssociations(); - }, - child: Column(children: [ - const SizedBox(height: 70), - associationKinds.when( - data: (data) { - debugPrint("associationKinds.when data: ${data.kinds}"); - return SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row(children: [ - RadioChip( - label: "Toutes", - selected: kind.value == "", + return Refresher( + onRefresh: () async { + await associationKindsNotifier.loadAssociationKinds(); + await associationListNotifier.loadAssociations(); + }, + child: Column(children: [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 30.0, horizontal: 20), + child: Row( + children: [ + const ResearchBar(), + if (isAdmin) const SizedBox(width: 20), + if (isAdmin) + GestureDetector( + onTap: () { + pageNotifier.setPhonebookPage(PhonebookPage.admin); + }, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + blurRadius: 10, + offset: const Offset(0, 5)) + ]), + child: const Row( + children: [ + HeroIcon(HeroIcons.userGroup, color: Colors.white), + SizedBox(width: 10), + Text(PhonebookTextConstants.admin, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.white)), + ], + ), + ), + ), + ], + ), + ), + const SizedBox(height: 10), + associationKinds.when( + data: (data) { + debugPrint("associationKinds.when data: ${data.kinds}"); + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + physics: const BouncingScrollPhysics(), + child: Row(children: [ + RadioChip( + label: PhonebookTextConstants.all, + selected: kind.value == "", + onTap: () { + kind.value = ""; + kindNotifier.setKind(""); + associationListNotifier.filterAssociationList( + nameFilter, kind.value); + }), + ...data.kinds + .map((e) => RadioChip( + label: e, + selected: kind.value == e, onTap: () { - kind.value = ""; - kindNotifier.setKind(""); + kind.value = e; + kindNotifier.setKind(e); associationListNotifier.filterAssociationList( nameFilter, kind.value); - }), - ...data.kinds - .map((e) => RadioChip( - label: e, - selected: kind.value == e, - onTap: () { - kind.value = e; - kindNotifier.setKind(e); - associationListNotifier - .filterAssociationList( - nameFilter, kind.value); - })) - .toList() - ])); - }, - error: (error, stackTrace) => - const Text(PhonebookTextConstants.errorKindsLoading), - loading: () => const CircularProgressIndicator()), - const SizedBox(height: 30), - const ResearchBar(), - const SizedBox(height: 10), - ...associationList.when( - data: (associations) { - return associations - .map((association) => AssociationCard( - association: association, - onClicked: () { - associationNotifier.setAssociation(association); - pageNotifier.setPhonebookPage( - PhonebookPage.associationPage); - }, - )) - .toList(); - }, - loading: () => - const [Center(child: CircularProgressIndicator())], - error: (error, stack) => [ - const Center( - child: Text(PhonebookTextConstants - .errorLoadAssociationList)) - ]) - ])), - if (isAdmin) - Positioned( - top: 15, - right: 15, - child: GestureDetector( - onTap: () { - pageNotifier.setPhonebookPage(PhonebookPage.admin); + })) + .toList() + ])); }, - child: Container( - padding: - const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 10, - offset: const Offset(0, 5)) - ]), - child: const Row( - children: [ - HeroIcon(HeroIcons.userGroup, color: Colors.white), - SizedBox(width: 10), - Text(PhonebookTextConstants.admin, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.white)), - ], - ), - ), - ), - ) - ], - ); + error: (error, stackTrace) => + const Text(PhonebookTextConstants.errorKindsLoading), + loading: () => const CircularProgressIndicator()), + const SizedBox(height: 30), + ...associationList.when( + data: (associations) { + return associations + .map((association) => AssociationCard( + association: association, + onClicked: () { + associationNotifier.setAssociation(association); + pageNotifier.setPhonebookPage( + PhonebookPage.associationPage); + }, + )) + .toList(); + }, + loading: () => const [Center(child: CircularProgressIndicator())], + error: (error, stack) => [ + const Center( + child: Text( + PhonebookTextConstants.errorLoadAssociationList)) + ]) + ])); } } diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart index 352181412..8325b79f5 100644 --- a/lib/phonebook/ui/pages/main_page/research_bar.dart +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -5,6 +5,7 @@ import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/tools/constants.dart'; class ResearchBar extends HookConsumerWidget { const ResearchBar({Key? key}) : super(key: key); @@ -17,21 +18,7 @@ class ResearchBar extends HookConsumerWidget { final associationsNotifier = ref.watch(associationListProvider.notifier); final associationKind = ref.watch(associationKindProvider); - return Container( - decoration: BoxDecoration( - border: Border.all(), - color: Colors.white, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 1, - blurRadius: 7, - offset: const Offset(0, 3), - ), - ], - ), - width: 300, + return Expanded( child: TextField( onChanged: (value) { associationsNotifier.filterAssociationList(value, associationKind); @@ -41,17 +28,15 @@ class ResearchBar extends HookConsumerWidget { controller: editingController, cursorColor: PhonebookColorConstants.textDark, decoration: const InputDecoration( - labelText: PhonebookTextConstants.associationPureSearch, - labelStyle: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: PhonebookColorConstants.textDark), - suffixIcon: Icon( - Icons.search, - color: PhonebookColorConstants.textDark, - size: 30, - ), - ), + isDense: true, + suffixIcon: Icon( + Icons.search, + color: PhonebookColorConstants.textDark, + size: 30, + ), + focusedBorder: UnderlineInputBorder( + borderSide: + BorderSide(color: ColorConstants.gradient1))), )); } } From 570cfc55b8d3baa8237c40b5f4a98b66be8f1491 Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:01 +0100 Subject: [PATCH 025/123] Adding label on search bar Signed-off-by: Maxime Roucher --- lib/phonebook/tools/constants.dart | 2 ++ lib/phonebook/ui/pages/main_page/research_bar.dart | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index e42239bc1..97e40d9e5 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -83,6 +83,8 @@ class PhonebookTextConstants { static const String activeMandate = "Mandat actif :"; static const String all = "Toutes"; + + static const String research = "Rechercher"; } class PhonebookColorConstants { diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart index 8325b79f5..c81fd3b54 100644 --- a/lib/phonebook/ui/pages/main_page/research_bar.dart +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -27,13 +27,18 @@ class ResearchBar extends HookConsumerWidget { focusNode: focusNode, controller: editingController, cursorColor: PhonebookColorConstants.textDark, - decoration: const InputDecoration( + decoration: InputDecoration( isDense: true, suffixIcon: Icon( Icons.search, color: PhonebookColorConstants.textDark, size: 30, ), + label: Text( + PhonebookTextConstants.research, + style: TextStyle( + color: PhonebookColorConstants.textDark,), + ), focusedBorder: UnderlineInputBorder( borderSide: BorderSide(color: ColorConstants.gradient1))), From 6e749ed00a3e2c93067946c9f24be534a5e1e728 Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:01 +0100 Subject: [PATCH 026/123] Updating admin page UI Signed-off-by: Maxime Roucher --- .../ui/pages/admin_page/admin_page.dart | 8 ++- .../admin_page/association_research_bar.dart | 58 ++++++++----------- .../ui/pages/main_page/main_page.dart | 2 +- .../ui/pages/main_page/research_bar.dart | 2 +- 4 files changed, 32 insertions(+), 38 deletions(-) diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 860642964..fc01ea1b1 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -40,11 +40,16 @@ class AdminPage extends HookConsumerWidget { await roleNotifier.loadRolesTags(); }, child: Column(children: [ - const SizedBox(width: 10), + const Padding( + padding: EdgeInsets.all(30), + child: AssociationResearchBar(), + ), + const SizedBox(height: 10), associationKinds.when( data: (data) { return SingleChildScrollView( scrollDirection: Axis.horizontal, + physics: const BouncingScrollPhysics(), child: Row(children: [ RadioChip( label: "Toutes", @@ -72,7 +77,6 @@ class AdminPage extends HookConsumerWidget { const Text(PhonebookTextConstants.errorRoleTagsLoading), loading: () => const CircularProgressIndicator()), const SizedBox(height: 10), - const AssociationResearchBar(), const SizedBox(height: 10), Column( children: [ diff --git a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart index b956a2334..b2bac602c 100644 --- a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart +++ b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart @@ -5,6 +5,7 @@ import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/tools/constants.dart'; class AssociationResearchBar extends HookConsumerWidget { const AssociationResearchBar({Key? key}) : super(key: key); @@ -17,40 +18,29 @@ class AssociationResearchBar extends HookConsumerWidget { final associationsNotifier = ref.watch(associationListProvider.notifier); final associationKind = ref.watch(associationKindProvider); - return Container( - decoration: BoxDecoration( - border: Border.all(), - color: Colors.white, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 1, - blurRadius: 7, - offset: const Offset(0, 3), // changes position of shadow + return TextField( + onChanged: (value) async { + associationsNotifier.filterAssociationList(value, associationKind); + filterNotifier.setFilter(value); + }, + focusNode: focusNode, + controller: editingController, + cursorColor: PhonebookColorConstants.textDark, + decoration: const InputDecoration( + isDense: true, + suffixIcon: Icon( + Icons.search, + color: PhonebookColorConstants.textDark, + size: 30, + ), + label: Text( + PhonebookTextConstants.research, + style: TextStyle( + color: PhonebookColorConstants.textDark, ), - ], - ), - width: 300, - child: TextField( - onChanged: (value) async { - associationsNotifier.filterAssociationList(value, associationKind); - filterNotifier.setFilter(value); - }, - focusNode: focusNode, - controller: editingController, - cursorColor: PhonebookColorConstants.textDark, - decoration: const InputDecoration( - labelText: PhonebookTextConstants.associationPureSearch, - labelStyle: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: PhonebookColorConstants.textDark), - suffixIcon: Icon( - Icons.search, - color: PhonebookColorConstants.textDark, - size: 30, - )), - )); + ), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(color: ColorConstants.gradient1))), + ); } } diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 8d3e204ac..fceacd161 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -39,7 +39,7 @@ class MainPage extends HookConsumerWidget { }, child: Column(children: [ Padding( - padding: const EdgeInsets.symmetric(vertical: 30.0, horizontal: 20), + padding: const EdgeInsets.all(30.0), child: Row( children: [ const ResearchBar(), diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart index c81fd3b54..c32ea544a 100644 --- a/lib/phonebook/ui/pages/main_page/research_bar.dart +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -27,7 +27,7 @@ class ResearchBar extends HookConsumerWidget { focusNode: focusNode, controller: editingController, cursorColor: PhonebookColorConstants.textDark, - decoration: InputDecoration( + decoration: const InputDecoration( isDense: true, suffixIcon: Icon( Icons.search, From 226137a4efca3fe1f18ed93d36205259896986fd Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:02 +0100 Subject: [PATCH 027/123] Extracting text Signed-off-by: Maxime Roucher --- lib/phonebook/ui/pages/admin_page/admin_page.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index fc01ea1b1..abe13450e 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -52,7 +52,7 @@ class AdminPage extends HookConsumerWidget { physics: const BouncingScrollPhysics(), child: Row(children: [ RadioChip( - label: "Toutes", + label: PhonebookTextConstants.all, selected: kind.value == "", onTap: () { kind.value = ""; From f7db3b00435b4d051e35a0f256ad74260d20e252 Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:02 +0100 Subject: [PATCH 028/123] Updating add button UI Signed-off-by: Maxime Roucher --- .../ui/pages/admin_page/admin_page.dart | 109 +++++++++--------- 1 file changed, 56 insertions(+), 53 deletions(-) diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index abe13450e..2cff219d7 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -76,60 +76,63 @@ class AdminPage extends HookConsumerWidget { error: (error, stackTrace) => const Text(PhonebookTextConstants.errorRoleTagsLoading), loading: () => const CircularProgressIndicator()), - const SizedBox(height: 10), - const SizedBox(height: 10), - Column( - children: [ - GestureDetector( - onTap: () { - pageNotifier - .setPhonebookPage(PhonebookPage.associationCreation); - }, - child: Container( - decoration: BoxDecoration( - border: Border.all(color: Colors.black), - borderRadius: const BorderRadius.all(Radius.circular(20)), - ), - height: 58, - margin: const EdgeInsets.all(10), - child: const Row( - children: [Spacer(), Icon(Icons.add), Spacer()])), - ), - ...associations.when( - data: (associations) { - return associations - .map((association) => EditableAssociationCard( - association: association, - onEdit: () { - associationNotifier.setAssociation(association); - pageNotifier.setPhonebookPage( - PhonebookPage.associationEditor); - }, - onDelete: () async { - final result = await associationsNotifier - .deleteAssociation(association); - if (result) { - displayToastWithContext( - TypeMsg.msg, - PhonebookTextConstants - .deletedAssociation); - } else { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.deletingError); - } - associationsNotifier.loadAssociations(); - }, - )) - .toList(); + Padding( + padding: const EdgeInsets.all(30.0), + child: Column( + children: [ + GestureDetector( + onTap: () { + pageNotifier + .setPhonebookPage(PhonebookPage.associationCreation); }, - loading: () => - const [Center(child: CircularProgressIndicator())], - error: (error, stack) => [ - const Center( - child: Text(PhonebookTextConstants - .errorLoadAssociationList)) - ]) - ], + child: Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.black), + borderRadius: + const BorderRadius.all(Radius.circular(20)), + ), + height: 60, + child: const Center( + child: + Icon(Icons.add, color: Colors.black, size: 40))), + ), + ...associations.when( + data: (associations) { + return associations + .map((association) => EditableAssociationCard( + association: association, + onEdit: () { + associationNotifier + .setAssociation(association); + pageNotifier.setPhonebookPage( + PhonebookPage.associationEditor); + }, + onDelete: () async { + final result = await associationsNotifier + .deleteAssociation(association); + if (result) { + displayToastWithContext( + TypeMsg.msg, + PhonebookTextConstants + .deletedAssociation); + } else { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.deletingError); + } + associationsNotifier.loadAssociations(); + }, + )) + .toList(); + }, + loading: () => + const [Center(child: CircularProgressIndicator())], + error: (error, stack) => [ + const Center( + child: Text(PhonebookTextConstants + .errorLoadAssociationList)) + ]) + ], + ), ), ])); } From 3be6413620e31b749907df70c0adfc68c08e285a Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:02 +0100 Subject: [PATCH 029/123] Fixing to work with image upload correction Signed-off-by: Maxime Roucher --- .../providers/association_picture_provider.dart | 6 ++++-- .../repositories/association_picture_repository.dart | 9 +++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/phonebook/providers/association_picture_provider.dart b/lib/phonebook/providers/association_picture_provider.dart index 45a32e794..d551b25a2 100644 --- a/lib/phonebook/providers/association_picture_provider.dart +++ b/lib/phonebook/providers/association_picture_provider.dart @@ -1,3 +1,5 @@ +import 'dart:typed_data'; + import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; @@ -24,8 +26,8 @@ class AssociationPictureNotifier extends SingleNotifier { } Future updateAssociationPicture( - String associationId, String path) async { + String associationId, Uint8List bytes) async { return await associationPictureRepository.addAssociationPicture( - path, associationId); + bytes, associationId); } } diff --git a/lib/phonebook/repositories/association_picture_repository.dart b/lib/phonebook/repositories/association_picture_repository.dart index e0b469d30..5ca09b705 100644 --- a/lib/phonebook/repositories/association_picture_repository.dart +++ b/lib/phonebook/repositories/association_picture_repository.dart @@ -1,3 +1,5 @@ +import 'dart:typed_data'; + import 'package:flutter/material.dart'; import 'package:myecl/tools/repository/logo_repository.dart'; @@ -14,10 +16,9 @@ class AssociationPictureRepository extends LogoRepository { return Image.memory(uint8List); } - Future addAssociationPicture(String path, String associationId) async { - final image = await saveLogoToTemp(path); - final uint8List = - await addLogo(image.path, associationId, suffix: "/picture"); + Future addAssociationPicture( + Uint8List bytes, String associationId) async { + final uint8List = await addLogo(bytes, associationId, suffix: "/picture"); return Image.memory(uint8List); } } From 45161f6aafe537e4084f0f8b9fff8c176d4715a7 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:02 +0100 Subject: [PATCH 030/123] fix JSON keys to match back --- lib/phonebook/class/association.dart | 29 ++++++++++--------- lib/phonebook/class/membership.dart | 22 +++++++------- .../providers/association_list_provider.dart | 5 ++-- .../association_member_list_provider.dart | 9 +++--- .../association_member_repository.dart | 1 + .../association_editor_page.dart | 6 ++-- 6 files changed, 38 insertions(+), 34 deletions(-) diff --git a/lib/phonebook/class/association.dart b/lib/phonebook/class/association.dart index 12a9934ed..1ff1168f6 100644 --- a/lib/phonebook/class/association.dart +++ b/lib/phonebook/class/association.dart @@ -1,4 +1,6 @@ -class Association { +import 'package:flutter/material.dart'; + +class Association{ Association({ required this.id, required this.name, @@ -11,15 +13,16 @@ class Association { late final String name; late final String description; late final String kind; - late final String mandateYear; + late final int mandateYear; - Association.fromJSON(Map json) { - id = json['id']; - name = json['name']; - description = json['description']; - kind = json['kind']; - mandateYear = json['mandateYear']; - } + Association.fromJSON(Map json){ + debugPrint("Association.fromJSON: $json"); + id = json['id']; + name = json['name']; + description = json['description']; + kind = json['kind']; + mandateYear = json['mandate_year']; + } Map toJSON() { final data = { @@ -37,7 +40,7 @@ class Association { String? name, String? description, String? kind, - String? mandateYear, + int? mandateYear, }) { return Association( id: id ?? this.id, @@ -53,11 +56,11 @@ class Association { name = ""; description = ""; kind = ""; - mandateYear = ""; + mandateYear = 0; } - void newMandate() { - mandateYear = (int.parse(mandateYear) + 1).toString(); + void newMandate(){ + mandateYear = mandateYear + 1; } @override diff --git a/lib/phonebook/class/membership.dart b/lib/phonebook/class/membership.dart index 9bd05e5ff..8555fdb8f 100644 --- a/lib/phonebook/class/membership.dart +++ b/lib/phonebook/class/membership.dart @@ -13,19 +13,19 @@ class Membership { late final List rolesTags; late final String apparentName; - Membership.fromJSON(Map json) { - id = json['id']; - association = json['association']; - rolesTags = json['roleTags']; - apparentName = json['apparentName']; - } - - Map toJSON() { + Membership.fromJSON(Map json){ + id = json['id']; + association = json['association']; + rolesTags = json['role_tags']; + apparentName = json['role_name']; + } + + Map toJSON(){ final data = { 'id': id, 'association': association.id, - 'roleTags': rolesTags, - 'apparentName': apparentName, + 'role_tags': rolesTags.join(";"), + 'role_name': apparentName, }; return data; } @@ -65,6 +65,6 @@ class Membership { @override String toString() { - return 'Membership(id: $id, association: $association, rolesTags: $rolesTags, apparentName: $apparentName)'; + return 'Membership(id: $id, association: $association, rolesTags: ${rolesTags.join(";")}, apparentName: $apparentName)'; } } diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index 169979117..e18e5a230 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -1,3 +1,4 @@ +import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/repositories/association_repository.dart'; @@ -15,8 +16,8 @@ class AssociationListNotifier extends ListNotifier { } Future>> loadAssociations() async { - associationList = - await loadList(() async => associationRepository.getAssociationList()); + associationList = await loadList(() async => associationRepository.getAssociationList()); + debugPrint("associationList: $associationList"); return associationList; } diff --git a/lib/phonebook/providers/association_member_list_provider.dart b/lib/phonebook/providers/association_member_list_provider.dart index 56c02e85e..9c235a99f 100644 --- a/lib/phonebook/providers/association_member_list_provider.dart +++ b/lib/phonebook/providers/association_member_list_provider.dart @@ -1,3 +1,4 @@ +import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; @@ -14,10 +15,10 @@ class AssociationMemberListNotifier extends ListNotifier { associationMemberRepository.setToken(token); } - Future>> loadMembers( - String associationId) async { - return await loadList(() async => - associationMemberRepository.getAssociationMemberList(associationId)); + Future>> loadMembers(String associationId) async { + dynamic members = await loadList(() async => associationMemberRepository.getAssociationMemberList(associationId)); + debugPrint("Membres : $members"); + return members; } } diff --git a/lib/phonebook/repositories/association_member_repository.dart b/lib/phonebook/repositories/association_member_repository.dart index 4c25415e8..b258544a6 100644 --- a/lib/phonebook/repositories/association_member_repository.dart +++ b/lib/phonebook/repositories/association_member_repository.dart @@ -1,3 +1,4 @@ +import 'package:flutter/material.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/tools/repository/repository.dart'; diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index badf349aa..400599f4f 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -381,9 +381,7 @@ class AssociationEditorPage extends HookConsumerWidget { await tokenExpireWrapper(ref, () async { final value = await associationListNotifier .updateAssociation(association.copyWith( - mandateYear: - (int.parse(association.mandateYear) + 1) - .toString())); + mandateYear: association.mandateYear+1)); if (value) { displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.newMandateConfirmed); @@ -422,7 +420,7 @@ class AssociationEditorPage extends HookConsumerWidget { borderRadius: BorderRadius.circular(15), ), child: Text( - "${PhonebookTextConstants.changeMandate} ${(int.parse(association.mandateYear) + 1).toString()}", + "${PhonebookTextConstants.changeMandate} ${association.mandateYear+1}", style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w600, From 9cf959d9f7922ea0dce072063bf0a9bb7249691a Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:02 +0100 Subject: [PATCH 031/123] Updating association cards UI Signed-off-by: Maxime Roucher --- .../association_member_repository.dart | 1 - lib/phonebook/ui/association_card.dart | 128 ----------------- .../ui/pages/admin_page/admin_page.dart | 21 ++- .../{ => pages/admin_page}/delete_button.dart | 12 +- .../admin_page/editable_association_card.dart | 6 +- .../admin_page}/edition_button.dart | 6 +- .../member_editable_card.dart | 4 +- .../ui/pages/main_page/association_card.dart | 129 ++++++++++++++++++ .../ui/pages/main_page/main_page.dart | 10 +- 9 files changed, 164 insertions(+), 153 deletions(-) delete mode 100644 lib/phonebook/ui/association_card.dart rename lib/phonebook/ui/{ => pages/admin_page}/delete_button.dart (86%) rename lib/phonebook/ui/{ => pages/admin_page}/edition_button.dart (90%) create mode 100644 lib/phonebook/ui/pages/main_page/association_card.dart diff --git a/lib/phonebook/repositories/association_member_repository.dart b/lib/phonebook/repositories/association_member_repository.dart index b258544a6..4c25415e8 100644 --- a/lib/phonebook/repositories/association_member_repository.dart +++ b/lib/phonebook/repositories/association_member_repository.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/tools/repository/repository.dart'; diff --git a/lib/phonebook/ui/association_card.dart b/lib/phonebook/ui/association_card.dart deleted file mode 100644 index c3ad8c219..000000000 --- a/lib/phonebook/ui/association_card.dart +++ /dev/null @@ -1,128 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:heroicons/heroicons.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/providers/association_picture_provider.dart'; -import 'package:myecl/phonebook/providers/associations_pictures_provider.dart'; -import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/tools/token_expire_wrapper.dart'; - -class AssociationCard extends HookConsumerWidget { - const AssociationCard({ - super.key, - required this.association, - required this.onClicked, - }); - - final Association association; - final VoidCallback onClicked; - - @override - Widget build(BuildContext context, WidgetRef ref) { - final associationPictures = ref.watch(associationPicturesProvider); - final associationPicturesNotifier = - ref.watch(associationPicturesProvider.notifier); - final associationPictureNotifier = - ref.watch(associationPictureProvider.notifier); - - return GestureDetector( - onTap: () { - onClicked(); - }, - child: Container( - margin: const EdgeInsets.all(10), - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - border: Border.all(), - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(20)), - ), - child: Row(children: [ - associationPictures.when( - data: (pictures) { - if (pictures[association] != null) { - return pictures[association]!.when( - data: (picture) { - if (picture.isNotEmpty) { - return Container( - width: 40, - height: 40, - decoration: BoxDecoration( - shape: BoxShape.circle, - image: DecorationImage( - image: picture.first.image, - fit: BoxFit.cover, - ), - ), - ); - } else { - Future.delayed( - const Duration(milliseconds: 1), - () => associationPicturesNotifier.setTData( - association, const AsyncLoading())); - tokenExpireWrapper(ref, () async { - associationPictureNotifier - .getAssociationPicture(association.id) - .then((value) { - associationPicturesNotifier.setTData( - association, AsyncData([value])); - }); - }); - return const HeroIcon( - HeroIcons.userCircle, - size: 40, - ); - } - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: Text(PhonebookTextConstants - .errorLoadAssociationPicture), - ); - }, - ); - } - return const HeroIcon( - HeroIcons.userCircle, - size: 40, - ); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: Text( - PhonebookTextConstants.errorLoadAssociationPicture), - ); - }, - ), - const SizedBox(width: 10), - SizedBox( - width: 200, - child: Text( - association.name, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - const Spacer(flex: 1), - Text( - association.kind, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ]))); - } -} diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 2cff219d7..ba6430c4a 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -51,6 +51,9 @@ class AdminPage extends HookConsumerWidget { scrollDirection: Axis.horizontal, physics: const BouncingScrollPhysics(), child: Row(children: [ + const SizedBox( + width: 20, + ), RadioChip( label: PhonebookTextConstants.all, selected: kind.value == "", @@ -70,7 +73,10 @@ class AdminPage extends HookConsumerWidget { associationsNotifier.filterAssociationList( nameFilter, kind.value); })) - .toList() + .toList(), + const SizedBox( + width: 20, + ), ])); }, error: (error, stackTrace) => @@ -87,11 +93,16 @@ class AdminPage extends HookConsumerWidget { }, child: Container( decoration: BoxDecoration( - border: Border.all(color: Colors.black), - borderRadius: - const BorderRadius.all(Radius.circular(20)), - ), + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 5, + spreadRadius: 2) + ]), height: 60, + margin: const EdgeInsets.only(bottom: 10), child: const Center( child: Icon(Icons.add, color: Colors.black, size: 40))), diff --git a/lib/phonebook/ui/delete_button.dart b/lib/phonebook/ui/pages/admin_page/delete_button.dart similarity index 86% rename from lib/phonebook/ui/delete_button.dart rename to lib/phonebook/ui/pages/admin_page/delete_button.dart index 0d2a50976..62f736fae 100644 --- a/lib/phonebook/ui/delete_button.dart +++ b/lib/phonebook/ui/pages/admin_page/delete_button.dart @@ -12,7 +12,7 @@ class DeleteButton extends StatelessWidget { Widget build(BuildContext context) { return ShrinkButton( waitChild: Container( - padding: const EdgeInsets.all(10), + padding: const EdgeInsets.all(8), decoration: BoxDecoration( gradient: const LinearGradient( colors: [ @@ -24,9 +24,8 @@ class DeleteButton extends StatelessWidget { ), boxShadow: [ BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.3), - spreadRadius: 2, - blurRadius: 4, + color: ColorConstants.gradient2.withOpacity(0.2), + blurRadius: 10, offset: const Offset(2, 3), ), ], @@ -40,7 +39,7 @@ class DeleteButton extends StatelessWidget { ), onTap: onDelete, child: Container( - padding: const EdgeInsets.all(10), + padding: const EdgeInsets.all(8), decoration: BoxDecoration( gradient: const LinearGradient( colors: [ @@ -53,8 +52,7 @@ class DeleteButton extends StatelessWidget { boxShadow: [ BoxShadow( color: ColorConstants.gradient2.withOpacity(0.3), - spreadRadius: 2, - blurRadius: 4, + blurRadius: 10, offset: const Offset(2, 3), ), ], diff --git a/lib/phonebook/ui/pages/admin_page/editable_association_card.dart b/lib/phonebook/ui/pages/admin_page/editable_association_card.dart index 0d3802d87..7fd57802c 100644 --- a/lib/phonebook/ui/pages/admin_page/editable_association_card.dart +++ b/lib/phonebook/ui/pages/admin_page/editable_association_card.dart @@ -5,8 +5,8 @@ import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/associations_pictures_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/ui/delete_button.dart'; -import 'package:myecl/phonebook/ui/edition_button.dart'; +import 'package:myecl/phonebook/ui/pages/admin_page/delete_button.dart'; +import 'package:myecl/phonebook/ui/pages/admin_page/edition_button.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; class EditableAssociationCard extends HookConsumerWidget { @@ -31,7 +31,7 @@ class EditableAssociationCard extends HookConsumerWidget { padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.white, - borderRadius: BorderRadius.circular(10), + borderRadius: BorderRadius.circular(15), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.2), diff --git a/lib/phonebook/ui/edition_button.dart b/lib/phonebook/ui/pages/admin_page/edition_button.dart similarity index 90% rename from lib/phonebook/ui/edition_button.dart rename to lib/phonebook/ui/pages/admin_page/edition_button.dart index f40b88235..176e91c11 100644 --- a/lib/phonebook/ui/edition_button.dart +++ b/lib/phonebook/ui/pages/admin_page/edition_button.dart @@ -9,12 +9,8 @@ class EditionButton extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return GestureDetector( - onTap: () { - onEdition(); - }, + onTap: onEdition, child: Container( - width: 40, - height: 40, padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.grey.shade200, diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index bfd6d0b60..3db6f0493 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -7,8 +7,8 @@ import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/providers/edition_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; -import 'package:myecl/phonebook/ui/delete_button.dart'; -import 'package:myecl/phonebook/ui/edition_button.dart'; +import 'package:myecl/phonebook/ui/pages/admin_page/delete_button.dart'; +import 'package:myecl/phonebook/ui/pages/admin_page/edition_button.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/user/providers/profile_picture_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; diff --git a/lib/phonebook/ui/pages/main_page/association_card.dart b/lib/phonebook/ui/pages/main_page/association_card.dart new file mode 100644 index 000000000..312ff1de1 --- /dev/null +++ b/lib/phonebook/ui/pages/main_page/association_card.dart @@ -0,0 +1,129 @@ +import 'package:flutter/material.dart'; +import 'package:heroicons/heroicons.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/providers/association_picture_provider.dart'; +import 'package:myecl/phonebook/providers/associations_pictures_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; + +class AssociationCard extends HookConsumerWidget { + const AssociationCard({ + super.key, + required this.association, + required this.onClicked, + }); + + final Association association; + final VoidCallback onClicked; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final associationPictures = ref.watch(associationPicturesProvider); + final associationPicturesNotifier = + ref.watch(associationPicturesProvider.notifier); + final associationPictureNotifier = + ref.watch(associationPictureProvider.notifier); + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: GestureDetector( + onTap: onClicked, + child: Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 5, + spreadRadius: 2) + ]), + child: Row(children: [ + associationPictures.when( + data: (pictures) { + if (pictures[association] != null) { + return pictures[association]!.when( + data: (picture) { + if (picture.isNotEmpty) { + return Container( + width: 40, + height: 40, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: picture.first.image, + fit: BoxFit.cover, + ), + ), + ); + } else { + Future.delayed( + const Duration(milliseconds: 1), + () => associationPicturesNotifier.setTData( + association, const AsyncLoading())); + tokenExpireWrapper(ref, () async { + associationPictureNotifier + .getAssociationPicture(association.id) + .then((value) { + associationPicturesNotifier.setTData( + association, AsyncData([value])); + }); + }); + return const HeroIcon( + HeroIcons.userCircle, + size: 40, + ); + } + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return const Center( + child: Text(PhonebookTextConstants + .errorLoadAssociationPicture), + ); + }, + ); + } + return const HeroIcon( + HeroIcons.userCircle, + size: 40, + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return const Center( + child: Text( + PhonebookTextConstants.errorLoadAssociationPicture), + ); + }, + ), + const SizedBox(width: 10), + Text( + association.name, + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + const Spacer(flex: 1), + Text( + association.kind, + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ]))), + ); + } +} diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index fceacd161..039ba3e68 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -10,7 +10,7 @@ import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/admin/providers/is_admin.dart'; import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; -import 'package:myecl/phonebook/ui/association_card.dart'; +import 'package:myecl/phonebook/ui/pages/main_page/association_card.dart'; import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/phonebook/ui/pages/main_page/research_bar.dart'; import 'package:myecl/tools/ui/refresher.dart'; @@ -85,6 +85,9 @@ class MainPage extends HookConsumerWidget { scrollDirection: Axis.horizontal, physics: const BouncingScrollPhysics(), child: Row(children: [ + const SizedBox( + width: 20, + ), RadioChip( label: PhonebookTextConstants.all, selected: kind.value == "", @@ -104,7 +107,10 @@ class MainPage extends HookConsumerWidget { associationListNotifier.filterAssociationList( nameFilter, kind.value); })) - .toList() + .toList(), + const SizedBox( + width: 20, + ), ])); }, error: (error, stackTrace) => From 267425f50709385fa04a2a98fd386c6b2a3213b7 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:02 +0100 Subject: [PATCH 032/123] Fix dynamic types --- lib/phonebook/class/association_kinds.dart | 4 ++-- lib/phonebook/class/roles_tags.dart | 4 ++-- lib/phonebook/providers/roles_tags_provider.dart | 2 ++ lib/phonebook/repositories/role_tags_repository.dart | 2 ++ 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/phonebook/class/association_kinds.dart b/lib/phonebook/class/association_kinds.dart index 99c3fc87c..b2ff65b5b 100644 --- a/lib/phonebook/class/association_kinds.dart +++ b/lib/phonebook/class/association_kinds.dart @@ -3,10 +3,10 @@ class AssociationKinds { required this.kinds, }); - late final List kinds; + late final List kinds; AssociationKinds.fromJSON(Map json) { - kinds = json['kinds']; + kinds = json['kinds'].map((dynamic tag) => tag.toString()).toList(); } Map toJSON() { diff --git a/lib/phonebook/class/roles_tags.dart b/lib/phonebook/class/roles_tags.dart index 8346784d2..d6f66aa37 100644 --- a/lib/phonebook/class/roles_tags.dart +++ b/lib/phonebook/class/roles_tags.dart @@ -3,10 +3,10 @@ class RolesTags { required this.tags, }); - late final List tags; + late final List tags; RolesTags.fromJSON(Map json) { - tags = json['tags']; + tags = json['tags'].map((dynamic tag) => tag.toString()).toList(); } Map toJSON() { diff --git a/lib/phonebook/providers/roles_tags_provider.dart b/lib/phonebook/providers/roles_tags_provider.dart index 12e3f9dec..bce3a9852 100644 --- a/lib/phonebook/providers/roles_tags_provider.dart +++ b/lib/phonebook/providers/roles_tags_provider.dart @@ -1,3 +1,4 @@ +import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/association.dart'; @@ -20,6 +21,7 @@ class RolesTagsNotifier extends SingleNotifier>> { } Future>>> loadRolesTags() async { + debugPrint('loadRolesTags'); return await load(() async => rolesTagsRepository.getRolesTags()); } diff --git a/lib/phonebook/repositories/role_tags_repository.dart b/lib/phonebook/repositories/role_tags_repository.dart index 14ee70ece..7c2a8a5b9 100644 --- a/lib/phonebook/repositories/role_tags_repository.dart +++ b/lib/phonebook/repositories/role_tags_repository.dart @@ -1,3 +1,4 @@ +import 'package:flutter/material.dart'; import 'package:myecl/phonebook/class/roles_tags.dart'; import 'package:myecl/tools/repository/repository.dart'; import 'package:tuple/tuple.dart'; @@ -9,6 +10,7 @@ class RolesTagsRepository extends Repository { Future>> getRolesTags() async { RolesTags rolesTags = RolesTags.fromJSON(await getOne("roletags")); + debugPrint(rolesTags.toString()); return Tuple2(rolesTags, List.filled(rolesTags.tags.length, false)); } } From 225aede5df8a145a19c8a632c38d3145e0cec93e Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:02 +0100 Subject: [PATCH 033/123] Change to new routing system --- .../providers/phonebook_admin_provider.dart | 29 + .../providers/phonebook_page_provider.dart | 24 - .../repositories/member_repository.dart | 4 + lib/phonebook/router.dart | 59 ++ lib/phonebook/ui/page_switcher.dart | 37 - .../ui/pages/admin_page/admin_page.dart | 224 +++--- .../association_creation_page.dart | 329 ++++---- .../association_editor_page.dart | 720 +++++++++--------- .../member_editable_card.dart | 10 +- .../association_page/association_page.dart | 161 ++-- .../pages/association_page/member_card.dart | 6 +- .../ui/pages/main_page/main_page.dart | 215 +++--- .../member_detail_page.dart | 8 +- .../membership_editor_page.dart | 274 +++---- lib/phonebook/ui/phonebook.dart | 74 +- lib/phonebook/ui/top_bar.dart | 35 +- lib/router.dart | 2 + .../providers/module_list_provider.dart | 2 + 18 files changed, 1112 insertions(+), 1101 deletions(-) create mode 100644 lib/phonebook/providers/phonebook_admin_provider.dart delete mode 100644 lib/phonebook/providers/phonebook_page_provider.dart create mode 100644 lib/phonebook/router.dart delete mode 100644 lib/phonebook/ui/page_switcher.dart diff --git a/lib/phonebook/providers/phonebook_admin_provider.dart b/lib/phonebook/providers/phonebook_admin_provider.dart new file mode 100644 index 000000000..ca36c2f87 --- /dev/null +++ b/lib/phonebook/providers/phonebook_admin_provider.dart @@ -0,0 +1,29 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; +import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/user/providers/user_provider.dart'; + +final isPhonebookAdminProvider = StateProvider((ref) { + final user = ref.watch(userProvider); + if (user.groups.map((e) => e.id).contains("53a669d6-84b1-4352-8d7c-421c1fbd9c6a")) { + return true; + } + return false; +}); + +final isAssociationPresidentProvider = StateProvider((ref) { + final association = ref.watch(associationProvider); + final membersList = ref.watch(associationMemberListProvider); + final me = ref.watch(userProvider); + membersList.whenData((members) { + if (members.map((e) => e.member.id).contains(me.id)) { + if (members.firstWhere((member) => member.member.id == me.id) + .memberships.firstWhere((membership) => membership.association.id == association.id) + .rolesTags.contains("Prez'")) { + return true; + } + } + }); + return false; +}); + diff --git a/lib/phonebook/providers/phonebook_page_provider.dart b/lib/phonebook/providers/phonebook_page_provider.dart deleted file mode 100644 index 681562e0e..000000000 --- a/lib/phonebook/providers/phonebook_page_provider.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; - -enum PhonebookPage { - main, - admin, - memberDetail, - associationEditor, - associationPage, - associationCreation, - membershipEdition -} - -final phonebookPageProvider = - StateNotifierProvider((ref) { - return PhonebookPageNotifier(); -}); - -class PhonebookPageNotifier extends StateNotifier { - PhonebookPageNotifier() : super(PhonebookPage.main); - - void setPhonebookPage(PhonebookPage i) { - state = i; - } -} diff --git a/lib/phonebook/repositories/member_repository.dart b/lib/phonebook/repositories/member_repository.dart index ed68b469e..97ceb30e5 100644 --- a/lib/phonebook/repositories/member_repository.dart +++ b/lib/phonebook/repositories/member_repository.dart @@ -20,4 +20,8 @@ class MemberRepository extends Repository { Future getCompleteMember(String memberId) async { return CompleteMember.fromJSON(await getOne(memberId, suffix: "complete")); } + + Future getMe() async { + return CompleteMember.fromJSON(await getOne("me", suffix: "complete")); + } } diff --git a/lib/phonebook/router.dart b/lib/phonebook/router.dart new file mode 100644 index 000000000..e241ab6ae --- /dev/null +++ b/lib/phonebook/router.dart @@ -0,0 +1,59 @@ +import 'package:heroicons/heroicons.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/drawer/class/module.dart'; +import 'package:myecl/phonebook/providers/phonebook_admin_provider.dart'; +import 'package:myecl/phonebook/ui/pages/admin_page/admin_page.dart'; +import 'package:myecl/phonebook/ui/pages/association_creation_page/association_creation_page.dart'; +import 'package:myecl/phonebook/ui/pages/association_editor_page/association_editor_page.dart'; +import 'package:myecl/phonebook/ui/pages/main_page/main_page.dart'; +import 'package:myecl/phonebook/ui/pages/member_detail_page/member_detail_page.dart'; +import 'package:myecl/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart'; +import 'package:myecl/tools/middlewares/admin_middleware.dart'; +import 'package:myecl/tools/middlewares/authenticated_middleware.dart'; +import 'package:qlevar_router/qlevar_router.dart'; + +class PhonebookRouter { + final ProviderRef ref; + static const String root = '/phonebook'; + static const String admin = '/admin'; + static const String createAssociaiton = '/create_association'; + static const String editAssociation = '/edit_association'; + static const String associationDetail = '/association_detail'; + static const String memberDetail = '/member_detail'; + static const String addEditMember = '/add_edit_member'; + static final Module module = Module( + name: "Annuaire", + icon: HeroIcons.phone, + root: PhonebookRouter.root, + selected: false); + PhonebookRouter(this.ref); + + QRoute route() => QRoute( + path: PhonebookRouter.root, + builder: () => const PhonebookMainPage(), + middleware: [AuthenticatedMiddleware(ref)], + children: [ + QRoute(path: admin, builder: () => const AdminPage(), middleware: [ + AdminMiddleware(ref, isPhonebookAdminProvider), + ], children: [ + QRoute(path: editAssociation, builder: () => const AssociationEditorPage(), + children: [ + QRoute(path: addEditMember, builder: () => const MembershipEditorPage()), + ], + ), + QRoute(path: createAssociaiton, builder: () => const AssociationCreationPage()), + ]), + QRoute(path: associationDetail, builder: () => const AssociationEditorPage(), + children: [ + QRoute(path: editAssociation, builder: () => const AssociationEditorPage(), + middleware: [ + AdminMiddleware(ref, isAssociationPresidentProvider), + ], + children: [ + QRoute(path: addEditMember, builder: () => const MembershipEditorPage()), + ]) + ]), + QRoute(path: memberDetail, builder: () => const MemberDetailPage()), + ], + ); +} \ No newline at end of file diff --git a/lib/phonebook/ui/page_switcher.dart b/lib/phonebook/ui/page_switcher.dart deleted file mode 100644 index 309452d66..000000000 --- a/lib/phonebook/ui/page_switcher.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; -import 'package:myecl/phonebook/ui/pages/admin_page/admin_page.dart'; -import 'package:myecl/phonebook/ui/pages/association_creation_page/association_creation_page.dart'; -import 'package:myecl/phonebook/ui/pages/association_editor_page/association_editor_page.dart'; -import 'package:myecl/phonebook/ui/pages/association_page/association_page.dart'; -import 'package:myecl/phonebook/ui/pages/main_page/main_page.dart'; -import 'package:myecl/phonebook/ui/pages/member_detail_page/member_detail_page.dart'; -import 'package:myecl/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart'; - -class PageSwitcher extends ConsumerWidget { - const PageSwitcher({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final page = ref.watch(phonebookPageProvider); - switch (page) { - case PhonebookPage.main: - return const MainPage(); - case PhonebookPage.admin: - return const AdminPage(); - case PhonebookPage.memberDetail: - return const MemberDetailPage(); - case PhonebookPage.associationEditor: - return const AssociationEditorPage(); - case PhonebookPage.associationPage: - return const AssociationPage(); - case PhonebookPage.associationCreation: - return const AssociationCreationPage(); - case PhonebookPage.membershipEdition: - return const MembershipEditorPage(); - default: - return const Text('Unknown page'); - } - } -} diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index ba6430c4a..55e22119b 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -5,22 +5,23 @@ import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; -import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; +import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/association_research_bar.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/editable_association_card.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/ui/refresher.dart'; +import 'package:qlevar_router/qlevar_router.dart'; class AdminPage extends HookConsumerWidget { const AdminPage({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { - final pageNotifier = ref.watch(phonebookPageProvider.notifier); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationsNotifier = ref.watch(associationListProvider.notifier); final associations = ref.watch(associationListProvider); @@ -34,117 +35,122 @@ class AdminPage extends HookConsumerWidget { displayToast(context, type, msg); } - return Refresher( - onRefresh: () async { - await associationsNotifier.loadAssociations(); - await roleNotifier.loadRolesTags(); - }, - child: Column(children: [ - const Padding( - padding: EdgeInsets.all(30), - child: AssociationResearchBar(), - ), - const SizedBox(height: 10), - associationKinds.when( - data: (data) { - return SingleChildScrollView( - scrollDirection: Axis.horizontal, - physics: const BouncingScrollPhysics(), - child: Row(children: [ - const SizedBox( - width: 20, - ), - RadioChip( - label: PhonebookTextConstants.all, - selected: kind.value == "", - onTap: () { - kind.value = ""; - kindNotifier.setKind(""); - associationsNotifier.filterAssociationList( - nameFilter, kind.value); - }), - ...data.kinds - .map((e) => RadioChip( - label: e, - selected: kind.value == e, + return PhonebookTemplate( + child: Refresher( + onRefresh: () async { + await associationsNotifier.loadAssociations(); + await roleNotifier.loadRolesTags(); + }, + child: Column(children: [ + const Padding( + padding: EdgeInsets.all(30), + child: AssociationResearchBar(), + ), + const SizedBox(height: 10), + associationKinds.when( + data: (data) { + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + physics: const BouncingScrollPhysics(), + child: Row(children: [ + const SizedBox( + width: 20, + ), + RadioChip( + label: PhonebookTextConstants.all, + selected: kind.value == "", onTap: () { - kind.value = e; - kindNotifier.setKind(e); + kind.value = ""; + kindNotifier.setKind(""); associationsNotifier.filterAssociationList( nameFilter, kind.value); - })) - .toList(), - const SizedBox( - width: 20, - ), - ])); - }, - error: (error, stackTrace) => - const Text(PhonebookTextConstants.errorRoleTagsLoading), - loading: () => const CircularProgressIndicator()), - Padding( - padding: const EdgeInsets.all(30.0), - child: Column( - children: [ - GestureDetector( - onTap: () { - pageNotifier - .setPhonebookPage(PhonebookPage.associationCreation); + }), + ...data.kinds + .map((e) => RadioChip( + label: e, + selected: kind.value == e, + onTap: () { + kind.value = e; + kindNotifier.setKind(e); + associationsNotifier.filterAssociationList( + nameFilter, kind.value); + })) + .toList(), + const SizedBox( + width: 20, + ), + ])); }, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(15), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.2), - blurRadius: 5, - spreadRadius: 2) - ]), - height: 60, - margin: const EdgeInsets.only(bottom: 10), - child: const Center( - child: - Icon(Icons.add, color: Colors.black, size: 40))), + error: (error, stackTrace) => + const Text(PhonebookTextConstants.errorRoleTagsLoading), + loading: () => const CircularProgressIndicator()), + Padding( + padding: const EdgeInsets.all(30.0), + child: Column( + children: [ + GestureDetector( + onTap: () { + QR.to(PhonebookRouter.root + + PhonebookRouter.admin + + PhonebookRouter.createAssociaiton); + }, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 5, + spreadRadius: 2) + ]), + height: 60, + margin: const EdgeInsets.only(bottom: 10), + child: const Center( + child: Icon(Icons.add, + color: Colors.black, size: 40))), + ), + ...associations.when( + data: (associations) { + return associations + .map((association) => EditableAssociationCard( + association: association, + onEdit: () { + associationNotifier + .setAssociation(association); + QR.to(PhonebookRouter.root + + PhonebookRouter.admin + + PhonebookRouter.editAssociation); + }, + onDelete: () async { + final result = await associationsNotifier + .deleteAssociation(association); + if (result) { + displayToastWithContext( + TypeMsg.msg, + PhonebookTextConstants + .deletedAssociation); + } else { + displayToastWithContext( + TypeMsg.error, + PhonebookTextConstants + .deletingError); + } + associationsNotifier.loadAssociations(); + }, + )) + .toList(); + }, + loading: () => + const [Center(child: CircularProgressIndicator())], + error: (error, stack) => [ + const Center( + child: Text(PhonebookTextConstants + .errorLoadAssociationList)) + ]) + ], ), - ...associations.when( - data: (associations) { - return associations - .map((association) => EditableAssociationCard( - association: association, - onEdit: () { - associationNotifier - .setAssociation(association); - pageNotifier.setPhonebookPage( - PhonebookPage.associationEditor); - }, - onDelete: () async { - final result = await associationsNotifier - .deleteAssociation(association); - if (result) { - displayToastWithContext( - TypeMsg.msg, - PhonebookTextConstants - .deletedAssociation); - } else { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.deletingError); - } - associationsNotifier.loadAssociations(); - }, - )) - .toList(); - }, - loading: () => - const [Center(child: CircularProgressIndicator())], - error: (error, stack) => [ - const Center( - child: Text(PhonebookTextConstants - .errorLoadAssociationList)) - ]) - ], - ), - ), - ])); + ), + ]))); } } diff --git a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart index 64d2985aa..fe73d797b 100644 --- a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart +++ b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart @@ -6,14 +6,16 @@ import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; -import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/pages/association_creation_page/text_entry.dart'; +import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:myecl/tools/ui/shrink_button.dart'; +import 'package:qlevar_router/qlevar_router.dart'; class AssociationCreationPage extends HookConsumerWidget { const AssociationCreationPage({Key? key}) : super(key: key); @@ -23,7 +25,6 @@ class AssociationCreationPage extends HookConsumerWidget { final key = GlobalKey(); final name = useTextEditingController(); final description = useTextEditingController(); - final pageNotifier = ref.watch(phonebookPageProvider.notifier); final associationListNotifier = ref.watch(associationListProvider.notifier); final associations = ref.watch(associationListProvider); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); @@ -34,174 +35,178 @@ class AssociationCreationPage extends HookConsumerWidget { displayToast(context, type, msg); } - return SingleChildScrollView( - physics: const AlwaysScrollableScrollPhysics( - parent: BouncingScrollPhysics(), - ), - child: Form( - key: key, - child: Column(children: [ - const SizedBox( - height: 30, + return PhonebookTemplate( + child: SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics( + parent: BouncingScrollPhysics(), ), - const Padding( - padding: EdgeInsets.symmetric(horizontal: 30.0), - child: Align( - alignment: Alignment.centerLeft, - child: Text(AdminTextConstants.addAssociation, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.w700, - color: ColorConstants.gradient1)), - ), - ), - const SizedBox( - height: 30, - ), - associationKinds.when( - data: (value) { - return SingleChildScrollView( - scrollDirection: Axis.horizontal, - physics: const BouncingScrollPhysics(), - child: Row(children: [ - const SizedBox(width: 15), - ...value.kinds - .map((e) => RadioChip( - label: e, - selected: e == kind.value, - onTap: () async { - kind.value = e; - }, - )) - .toList(), - const SizedBox(width: 15), - ])); - }, - error: (error, stack) { - return const Text(PhonebookTextConstants.errorKindsLoading); - }, - loading: () { - return const CircularProgressIndicator(); - }, - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 30.0), - child: Column( - children: [ - Container( - margin: const EdgeInsets.symmetric( - vertical: 10, - ), + child: Form( + key: key, + child: Column(children: [ + const SizedBox( + height: 30, + ), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 30.0), + child: Align( + alignment: Alignment.centerLeft, + child: Text(AdminTextConstants.addAssociation, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w700, + color: ColorConstants.gradient1)), ), - AddAssociationTextEntry( - controller: name, title: AdminTextConstants.name), - AddAssociationTextEntry( - controller: description, - title: AdminTextConstants.description), - ShrinkButton( - waitChild: Container( - width: double.infinity, - margin: const EdgeInsets.symmetric(vertical: 20), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, - ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: const SizedBox( - height: 20, - width: 20, - child: CircularProgressIndicator( - color: Colors.white, + ), + const SizedBox( + height: 30, + ), + associationKinds.when( + data: (value) { + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + physics: const BouncingScrollPhysics(), + child: Row(children: [ + const SizedBox(width: 15), + ...value.kinds + .map((e) => RadioChip( + label: e, + selected: e == kind.value, + onTap: () async { + kind.value = e; + }, + )) + .toList(), + const SizedBox(width: 15), + ])); + }, + error: (error, stack) { + return const Text(PhonebookTextConstants.errorKindsLoading); + }, + loading: () { + return const CircularProgressIndicator(); + }, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: Column( + children: [ + Container( + margin: const EdgeInsets.symmetric( + vertical: 10, ), ), - ), - onTap: () async { - if (!key.currentState!.validate()) { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.emptyFieldError); - return; - } - if (kind.value == '') { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.emptyKindError); - return; - } - await tokenExpireWrapper(ref, () async { - final value = await associationListNotifier - .createAssociation(Association.empty().copyWith( - name: name.text, - description: description.text, - kind: kind.value)); - if (value) { - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.addedAssociation); - associations.when( - data: (d) { - associationNotifier.setAssociation(d.last); - pageNotifier.setPhonebookPage( - PhonebookPage.associationEditor); - }, - error: (e, s) => displayToastWithContext( - TypeMsg.error, - PhonebookTextConstants - .errorAssociationLoading), - loading: () {}); - } else { - displayToastWithContext( - TypeMsg.error, AdminTextConstants.addingError); - } - }); - }, - child: Container( - width: double.infinity, - margin: const EdgeInsets.symmetric(vertical: 20), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], + AddAssociationTextEntry( + controller: name, title: AdminTextConstants.name), + AddAssociationTextEntry( + controller: description, + title: AdminTextConstants.description), + ShrinkButton( + waitChild: Container( + width: double.infinity, + margin: const EdgeInsets.symmetric(vertical: 20), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + ), + boxShadow: [ + BoxShadow( + color: + ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), + ], + borderRadius: BorderRadius.circular(15), + ), + child: const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + color: Colors.white, + ), + ), ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, + onTap: () async { + if (!key.currentState!.validate()) { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.emptyFieldError); + return; + } + if (kind.value == '') { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.emptyKindError); + return; + } + await tokenExpireWrapper(ref, () async { + final value = await associationListNotifier + .createAssociation(Association.empty().copyWith( + name: name.text, + description: description.text, + kind: kind.value)); + if (value) { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.addedAssociation); + associations.when( + data: (d) { + associationNotifier.setAssociation(d.last); + QR.to(PhonebookRouter.root + + PhonebookRouter.admin + + PhonebookRouter.editAssociation); + }, + error: (e, s) => displayToastWithContext( + TypeMsg.error, + PhonebookTextConstants + .errorAssociationLoading), + loading: () {}); + } else { + displayToastWithContext(TypeMsg.error, + AdminTextConstants.addingError); + } + }); + }, + child: Container( + width: double.infinity, + margin: const EdgeInsets.symmetric(vertical: 20), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + ), + boxShadow: [ + BoxShadow( + color: + ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), + ], + borderRadius: BorderRadius.circular(15), + ), + child: const Text( + AdminTextConstants.add, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), + ), ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: const Text( - AdminTextConstants.add, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color.fromARGB(255, 255, 255, 255), ), ), - ), + ], ), - ], - ), - ) - ]), - )); + ) + ]), + ))); } } diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 400599f4f..c23553b0d 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -10,9 +10,10 @@ import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/providers/edition_provider.dart'; -import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; +import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/phonebook/ui/pages/association_editor_page/member_editable_card.dart'; import 'package:myecl/tools/constants.dart'; @@ -20,6 +21,7 @@ import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:myecl/tools/ui/refresher.dart'; import 'package:myecl/tools/ui/shrink_button.dart'; +import 'package:qlevar_router/qlevar_router.dart'; class AssociationEditorPage extends HookConsumerWidget { const AssociationEditorPage({Key? key}) : super(key: key); @@ -41,395 +43,395 @@ class AssociationEditorPage extends HookConsumerWidget { final rolesTagsNotifier = ref.watch(rolesTagsProvider.notifier); final editionNotifier = ref.watch(editionProvider.notifier); final completeMemberNotifier = ref.watch(completeMemberProvider.notifier); - final pageNotifier = ref.watch(phonebookPageProvider.notifier); void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); } - return Refresher( - onRefresh: () async { - await associationMemberListNotifier.loadMembers(association.id); - await associationPictureNotifier.getAssociationPicture(association.id); - }, - child: Column(children: [ - const SizedBox( - height: 20, - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 30), - alignment: Alignment.centerLeft, - child: const Text(PhonebookTextConstants.edit, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.w700, - color: ColorConstants.gradient1)), - ), - const SizedBox( - height: 20, - ), - Form( - key: key, + return PhonebookTemplate( + child: + Refresher( + onRefresh: () async { + await associationMemberListNotifier.loadMembers(association.id); + await associationPictureNotifier.getAssociationPicture(association.id); + }, child: Column(children: [ - associationKinds.when( - data: (value) { - return SingleChildScrollView( - physics: const BouncingScrollPhysics(), - scrollDirection: Axis.horizontal, - child: Row( - children: value.kinds - .map((e) => RadioChip( - label: e, - selected: e == kind.value, - onTap: () async { - kind.value = e; - }, - )) - .toList())); - }, - error: (error, stack) { - return const Text(PhonebookTextConstants.errorKindsLoading); - }, - loading: () { - return const CircularProgressIndicator(); - }, + const SizedBox( + height: 20, ), - Padding( + Container( padding: const EdgeInsets.symmetric(horizontal: 30), - child: Column( - children: [ - Container( - margin: const EdgeInsets.symmetric(vertical: 10), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - child: TextFormField( - controller: name, - cursorColor: ColorConstants.gradient1, - decoration: InputDecoration( - labelText: "Name", - labelStyle: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - suffixIcon: Container( - padding: const EdgeInsets.all(10), - child: const HeroIcon( - HeroIcons.pencil, - ), + alignment: Alignment.centerLeft, + child: const Text(PhonebookTextConstants.edit, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w700, + color: ColorConstants.gradient1)), + ), + const SizedBox( + height: 20, + ), + Form( + key: key, + child: Column(children: [ + associationKinds.when( + data: (value) { + return SingleChildScrollView( + physics: const BouncingScrollPhysics(), + scrollDirection: Axis.horizontal, + child: Row( + children: value.kinds + .map((e) => RadioChip( + label: e, + selected: e == kind.value, + onTap: () async { + kind.value = e; + }, + )) + .toList())); + }, + error: (error, stack) { + return const Text(PhonebookTextConstants.errorKindsLoading); + }, + loading: () { + return const CircularProgressIndicator(); + }, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: Column( + children: [ + Container( + margin: const EdgeInsets.symmetric(vertical: 10), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + child: TextFormField( + controller: name, + cursorColor: ColorConstants.gradient1, + decoration: InputDecoration( + labelText: "Name", + labelStyle: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + suffixIcon: Container( + padding: const EdgeInsets.all(10), + child: const HeroIcon( + HeroIcons.pencil, + ), + ), + enabledBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: Colors.transparent, + ), + ), + focusedBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: ColorConstants.gradient1))), + validator: (value) { + if (value == null) { + return PhonebookTextConstants + .emptyFieldError; + } else if (value.isEmpty) { + return PhonebookTextConstants + .emptyFieldError; + } else { + return null; + } + }, ), - enabledBorder: const UnderlineInputBorder( - borderSide: BorderSide( - color: Colors.transparent, - ), + ), + ], + )), + Container( + margin: const EdgeInsets.symmetric(vertical: 10), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + child: TextFormField( + controller: description, + cursorColor: ColorConstants.gradient1, + decoration: InputDecoration( + labelText: "Description", + labelStyle: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + suffixIcon: Container( + padding: const EdgeInsets.all(10), + child: const HeroIcon( + HeroIcons.pencil, + ), + ), + enabledBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: Colors.transparent, + ), + ), + focusedBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: ColorConstants.gradient1))), + validator: (value) { + if (value == null) { + return PhonebookTextConstants + .emptyFieldError; + } else if (value.isEmpty) { + return PhonebookTextConstants + .emptyFieldError; + } else { + return null; + } + }, ), - focusedBorder: const UnderlineInputBorder( - borderSide: BorderSide( - color: ColorConstants.gradient1))), - validator: (value) { - if (value == null) { - return PhonebookTextConstants - .emptyFieldError; - } else if (value.isEmpty) { - return PhonebookTextConstants - .emptyFieldError; - } else { - return null; - } - }, + ), + ], + )), + ShrinkButton( + waitChild: Container( + width: double.infinity, + margin: const EdgeInsets.symmetric(vertical: 20), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), + ], + borderRadius: BorderRadius.circular(15), ), - ), - ], - )), - Container( - margin: const EdgeInsets.symmetric(vertical: 10), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - child: TextFormField( - controller: description, - cursorColor: ColorConstants.gradient1, - decoration: InputDecoration( - labelText: "Description", - labelStyle: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - suffixIcon: Container( - padding: const EdgeInsets.all(10), - child: const HeroIcon( - HeroIcons.pencil, - ), - ), - enabledBorder: const UnderlineInputBorder( - borderSide: BorderSide( - color: Colors.transparent, - ), - ), - focusedBorder: const UnderlineInputBorder( - borderSide: BorderSide( - color: ColorConstants.gradient1))), - validator: (value) { - if (value == null) { - return PhonebookTextConstants - .emptyFieldError; - } else if (value.isEmpty) { - return PhonebookTextConstants - .emptyFieldError; - } else { - return null; - } - }, + child: const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + color: Colors.white, + ), ), ), - ], - )), - ShrinkButton( - waitChild: Container( - width: double.infinity, - margin: const EdgeInsets.symmetric(vertical: 20), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, + onTap: () async { + if (!key.currentState!.validate()) { + return; + } + if (kind.value == '') { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.emptyKindError); + return; + } + await tokenExpireWrapper(ref, () async { + final value = await associationListNotifier + .updateAssociation(association.copyWith( + name: name.text, + description: description.text, + kind: kind.value)); + if (value) { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.updatedAssociation); + } else { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.updatingError); + } + }); + }, + child: Container( + width: double.infinity, + margin: const EdgeInsets.symmetric(vertical: 20), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), + ], + borderRadius: BorderRadius.circular(15), + ), + child: const Text( + PhonebookTextConstants.edit, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), + ), + ), ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: const SizedBox( - height: 20, - width: 20, - child: CircularProgressIndicator( - color: Colors.white, - ), - ), + ) + ], ), + ) + ])), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: Row( + children: [ + const Text(PhonebookTextConstants.members), + const Spacer(), + ShrinkButton( onTap: () async { - if (!key.currentState!.validate()) { - return; - } - if (kind.value == '') { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.emptyKindError); - return; - } - await tokenExpireWrapper(ref, () async { - final value = await associationListNotifier - .updateAssociation(association.copyWith( - name: name.text, - description: description.text, - kind: kind.value)); - if (value) { - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.updatedAssociation); - } else { - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.updatingError); - } - }); + rolesTagsNotifier.resetChecked(); + completeMemberNotifier + .setCompleteMember(CompleteMember.empty()); + editionNotifier.setStatus(false); + QR.to(PhonebookRouter.root + PhonebookRouter.editAssociation + PhonebookRouter.addEditMember); }, child: Container( - width: double.infinity, - margin: const EdgeInsets.symmetric(vertical: 20), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, + width: 40, + height: 40, decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, - ), - ], - borderRadius: BorderRadius.circular(15), + color: ColorConstants.gradient1, + borderRadius: BorderRadius.circular(10), ), - child: const Text( - PhonebookTextConstants.edit, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color.fromARGB(255, 255, 255, 255), - ), + child: const Icon( + Icons.add, + color: Colors.white, ), ), - ) + ), ], ), - ) - ])), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), - child: Row( - children: [ - const Text(PhonebookTextConstants.members), - const Spacer(), - ShrinkButton( - onTap: () async { - rolesTagsNotifier.resetChecked(); - completeMemberNotifier - .setCompleteMember(CompleteMember.empty()); - editionNotifier.setStatus(false); - pageNotifier - .setPhonebookPage(PhonebookPage.membershipEdition); + ), + ...associationMemberList.when( + data: (data) { + return data + .map((member) => MemberEditableCard(member: member)) + .toList(); }, - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: ColorConstants.gradient1, - borderRadius: BorderRadius.circular(10), - ), - child: const Icon( - Icons.add, - color: Colors.white, + error: (error, stackTrace) { + return const [ + Text(PhonebookTextConstants.errorLoadAssociationMember), + ]; + }, + loading: () => [ + const Center( + child: CircularProgressIndicator(), ), - ), - ), - ], - ), - ), - ...associationMemberList.when( - data: (data) { - return data - .map((member) => MemberEditableCard(member: member)) - .toList(); - }, - error: (error, stackTrace) { - return const [ - Text(PhonebookTextConstants.errorLoadAssociationMember), - ]; - }, - loading: () => [ - const Center( - child: CircularProgressIndicator(), - ), - ], - ), - const SizedBox( - height: 10, - ), - ShrinkButton( - waitChild: Container( - width: double.infinity, - margin: const EdgeInsets.all(30), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, ], ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, - ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: const SizedBox( - height: 20, - width: 20, - child: CircularProgressIndicator( - color: Colors.white, + const SizedBox( + height: 10, ), - ), - ), - onTap: () async { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text(PhonebookTextConstants.newMandate), - content: - const Text(PhonebookTextConstants.changeMandateConfirm), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - }, - child: const Text(PhonebookTextConstants.cancel), + ShrinkButton( + waitChild: Container( + width: double.infinity, + margin: const EdgeInsets.all(30), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), + ], + borderRadius: BorderRadius.circular(15), ), - TextButton( - onPressed: () async { - Navigator.pop(context); - await tokenExpireWrapper(ref, () async { - final value = await associationListNotifier - .updateAssociation(association.copyWith( - mandateYear: association.mandateYear+1)); - if (value) { - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.newMandateConfirmed); - } else { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.mandateChangingError); - } - }); - }, - child: const Text(PhonebookTextConstants.validation), + child: const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + color: Colors.white, + ), ), - ], - ), - ); - }, - child: Container( - width: double.infinity, - margin: const EdgeInsets.all(30), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: Text( - "${PhonebookTextConstants.changeMandate} ${association.mandateYear+1}", - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color.fromARGB(255, 255, 255, 255), - ), - ), - ), - ) - ]), - ); + onTap: () async { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text(PhonebookTextConstants.newMandate), + content: + const Text(PhonebookTextConstants.changeMandateConfirm), + actions: [ + TextButton( + onPressed: () { + Navigator.pop(context); + }, + child: const Text(PhonebookTextConstants.cancel), + ), + TextButton( + onPressed: () async { + Navigator.pop(context); + await tokenExpireWrapper(ref, () async { + final value = await associationListNotifier + .updateAssociation(association.copyWith( + mandateYear: association.mandateYear + 1)); + if (value) { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.newMandateConfirmed); + } else { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.mandateChangingError); + } + }); + }, + child: const Text(PhonebookTextConstants.validation), + ), + ], + ), + ); + }, + child: Container( + width: double.infinity, + margin: const EdgeInsets.all(30), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), + ], + borderRadius: BorderRadius.circular(15), + ), + child: Text( + "${PhonebookTextConstants.changeMandate} ${association.mandateYear + 1}", + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), + ), + ), + ), + ) + ]), + )); } } diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index 3db6f0493..61c49b3e4 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -5,13 +5,14 @@ import 'package:myecl/phonebook/providers/association_member_list_provider.dart' import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/providers/edition_provider.dart'; -import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; +import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/delete_button.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/edition_button.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/user/providers/profile_picture_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:qlevar_router/qlevar_router.dart'; class MemberEditableCard extends HookConsumerWidget { const MemberEditableCard({super.key, required this.member}); @@ -28,8 +29,6 @@ class MemberEditableCard extends HookConsumerWidget { final roleTagsNotifier = ref.watch(rolesTagsProvider.notifier); final editionNotifier = ref.watch(editionProvider.notifier); final completeMemberNotifier = ref.watch(completeMemberProvider.notifier); - final pageNotifier = ref.watch(phonebookPageProvider.notifier); - void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); } @@ -116,7 +115,10 @@ class MemberEditableCard extends HookConsumerWidget { roleTagsNotifier.loadRoleTagsFromMember(member, association); completeMemberNotifier.setCompleteMember(member); editionNotifier.setStatus(true); - pageNotifier.setPhonebookPage(PhonebookPage.membershipEdition); + QR.to(PhonebookRouter.root + + PhonebookRouter.admin + + PhonebookRouter.editAssociation + + PhonebookRouter.addEditMember); }), const SizedBox(width: 10), DeleteButton( diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index 5d76e28a1..7a381ba95 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -5,6 +5,7 @@ import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/pages/association_page/member_card.dart'; +import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/tools/ui/refresher.dart'; class AssociationPage extends HookConsumerWidget { @@ -20,43 +21,86 @@ class AssociationPage extends HookConsumerWidget { final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); - return Refresher( - onRefresh: () async { - await associationMemberListNotifier.loadMembers(association.id); - await associationPictureNotifier - .getAssociationPicture(association.id); - }, - child: Column(children: [ - const Text(PhonebookTextConstants.associationDetail, - style: TextStyle(fontSize: 30)), - const SizedBox( - height: 20, - ), - Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - spreadRadius: 5, - blurRadius: 10, - offset: const Offset(2, 3), - ), - ], + return PhonebookTemplate( + child: + Refresher( + onRefresh: () async { + await associationMemberListNotifier.loadMembers(association.id); + await associationPictureNotifier + .getAssociationPicture(association.id); + }, + child: Column(children: [ + const Text(PhonebookTextConstants.associationDetail, + style: TextStyle(fontSize: 30)), + const SizedBox( + height: 20, ), - child: associationPicture.when( - data: (picture) { - return Container( - width: 40, - height: 40, - decoration: BoxDecoration( - shape: BoxShape.circle, - image: DecorationImage( - image: picture.image, - fit: BoxFit.cover, - ), + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + spreadRadius: 5, + blurRadius: 10, + offset: const Offset(2, 3), ), - ); + ], + ), + child: associationPicture.when( + data: (picture) { + return Container( + width: 40, + height: 40, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: picture.image, + fit: BoxFit.cover, + ), + ), + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return const Center( + child: + Text(PhonebookTextConstants.errorLoadAssociationPicture), + ); + }, + ), + ), + const SizedBox(height: 20), + Text( + association.name, + style: const TextStyle(fontSize: 40, color: Colors.black), + ), + const SizedBox(height: 10), + Text(association.kind, + style: const TextStyle(fontSize: 20, color: Colors.black)), + const SizedBox(height: 10), + Text( + association.description, + style: const TextStyle(fontSize: 15, color: Colors.black), + ), + const SizedBox(height: 10), + Text( + "${PhonebookTextConstants.activeMandate} ${association.mandateYear}", + style: const TextStyle(fontSize: 15, color: Colors.black), + ), + const SizedBox( + height: 20, + ), + associationMemberList.when( + data: (members) { + return Column( + children: members + .map((member) => MemberCard(member: member)) + .toList()); }, loading: () { return const Center( @@ -65,51 +109,10 @@ class AssociationPage extends HookConsumerWidget { }, error: (e, s) { return const Center( - child: - Text(PhonebookTextConstants.errorLoadAssociationPicture), + child: Text(PhonebookTextConstants.errorLoadAssociationMember), ); }, - ), - ), - const SizedBox(height: 20), - Text( - association.name, - style: const TextStyle(fontSize: 40, color: Colors.black), - ), - const SizedBox(height: 10), - Text(association.kind, - style: const TextStyle(fontSize: 20, color: Colors.black)), - const SizedBox(height: 10), - Text( - association.description, - style: const TextStyle(fontSize: 15, color: Colors.black), - ), - const SizedBox(height: 10), - Text( - "${PhonebookTextConstants.activeMandate} ${association.mandateYear}", - style: const TextStyle(fontSize: 15, color: Colors.black), - ), - const SizedBox( - height: 20, - ), - associationMemberList.when( - data: (members) { - return Column( - children: members - .map((member) => MemberCard(member: member)) - .toList()); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: Text(PhonebookTextConstants.errorLoadAssociationMember), - ); - }, - ) - ])); + ) + ]))); } } diff --git a/lib/phonebook/ui/pages/association_page/member_card.dart b/lib/phonebook/ui/pages/association_page/member_card.dart index cd65ae642..6068890be 100644 --- a/lib/phonebook/ui/pages/association_page/member_card.dart +++ b/lib/phonebook/ui/pages/association_page/member_card.dart @@ -2,10 +2,11 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/router.dart'; import 'package:myecl/user/providers/profile_picture_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; -import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:qlevar_router/qlevar_router.dart'; class MemberCard extends HookConsumerWidget { const MemberCard({super.key, required this.member}); @@ -14,7 +15,6 @@ class MemberCard extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final pageNotifier = ref.watch(phonebookPageProvider.notifier); final memberNotifier = ref.watch(completeMemberProvider.notifier); final profilePicture = ref.watch(profilePictureProvider); final association = ref.watch(associationProvider); @@ -23,7 +23,7 @@ class MemberCard extends HookConsumerWidget { return GestureDetector( onTap: () { memberNotifier.setCompleteMember(member); - pageNotifier.setPhonebookPage(PhonebookPage.memberDetail); + QR.to(PhonebookRouter.root + PhonebookRouter.memberDetail); profilePictureNotifier.getProfilePicture(member.member.id); }, child: Container( diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 039ba3e68..86d1298ad 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -7,21 +7,22 @@ import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; +import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/admin/providers/is_admin.dart'; -import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/ui/pages/main_page/association_card.dart'; +import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/phonebook/ui/pages/main_page/research_bar.dart'; import 'package:myecl/tools/ui/refresher.dart'; +import 'package:qlevar_router/qlevar_router.dart'; -class MainPage extends HookConsumerWidget { - const MainPage({Key? key}) : super(key: key); +class PhonebookMainPage extends HookConsumerWidget { + const PhonebookMainPage({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { final isAdmin = ref.watch(isAdminProvider); - final pageNotifier = ref.watch(phonebookPageProvider.notifier); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationListNotifier = ref.watch(associationListProvider.notifier); final associationList = ref.watch(associationListProvider); @@ -32,110 +33,112 @@ class MainPage extends HookConsumerWidget { final kindNotifier = ref.watch(associationKindProvider.notifier); final nameFilter = ref.watch(filterProvider); - return Refresher( - onRefresh: () async { - await associationKindsNotifier.loadAssociationKinds(); - await associationListNotifier.loadAssociations(); - }, - child: Column(children: [ - Padding( - padding: const EdgeInsets.all(30.0), - child: Row( - children: [ - const ResearchBar(), - if (isAdmin) const SizedBox(width: 20), - if (isAdmin) - GestureDetector( - onTap: () { - pageNotifier.setPhonebookPage(PhonebookPage.admin); - }, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 10, - offset: const Offset(0, 5)) - ]), - child: const Row( - children: [ - HeroIcon(HeroIcons.userGroup, color: Colors.white), - SizedBox(width: 10), - Text(PhonebookTextConstants.admin, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.white)), - ], + return PhonebookTemplate( + child: + Refresher( + onRefresh: () async { + await associationKindsNotifier.loadAssociationKinds(); + await associationListNotifier.loadAssociations(); + }, + child: Column(children: [ + Padding( + padding: const EdgeInsets.all(30.0), + child: Row( + children: [ + const ResearchBar(), + if (isAdmin) const SizedBox(width: 20), + if (isAdmin) + GestureDetector( + onTap: () { + QR.to(PhonebookRouter.root + PhonebookRouter.admin); + }, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + blurRadius: 10, + offset: const Offset(0, 5)) + ]), + child: const Row( + children: [ + HeroIcon(HeroIcons.userGroup, color: Colors.white), + SizedBox(width: 10), + Text(PhonebookTextConstants.admin, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.white)), + ], + ), ), ), - ), - ], + ], + ), ), - ), - const SizedBox(height: 10), - associationKinds.when( - data: (data) { - debugPrint("associationKinds.when data: ${data.kinds}"); - return SingleChildScrollView( - scrollDirection: Axis.horizontal, - physics: const BouncingScrollPhysics(), - child: Row(children: [ - const SizedBox( - width: 20, - ), - RadioChip( - label: PhonebookTextConstants.all, - selected: kind.value == "", - onTap: () { - kind.value = ""; - kindNotifier.setKind(""); - associationListNotifier.filterAssociationList( - nameFilter, kind.value); - }), - ...data.kinds - .map((e) => RadioChip( - label: e, - selected: kind.value == e, - onTap: () { - kind.value = e; - kindNotifier.setKind(e); - associationListNotifier.filterAssociationList( - nameFilter, kind.value); - })) - .toList(), - const SizedBox( - width: 20, - ), - ])); - }, - error: (error, stackTrace) => - const Text(PhonebookTextConstants.errorKindsLoading), - loading: () => const CircularProgressIndicator()), - const SizedBox(height: 30), - ...associationList.when( - data: (associations) { - return associations - .map((association) => AssociationCard( - association: association, - onClicked: () { - associationNotifier.setAssociation(association); - pageNotifier.setPhonebookPage( - PhonebookPage.associationPage); - }, - )) - .toList(); - }, - loading: () => const [Center(child: CircularProgressIndicator())], - error: (error, stack) => [ - const Center( - child: Text( - PhonebookTextConstants.errorLoadAssociationList)) - ]) - ])); + const SizedBox(height: 10), + associationKinds.when( + data: (data) { + debugPrint("associationKinds.when data: ${data.kinds}"); + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + physics: const BouncingScrollPhysics(), + child: Row(children: [ + const SizedBox( + width: 20, + ), + RadioChip( + label: PhonebookTextConstants.all, + selected: kind.value == "", + onTap: () { + kind.value = ""; + kindNotifier.setKind(""); + associationListNotifier.filterAssociationList( + nameFilter, kind.value); + }), + ...data.kinds + .map((e) => RadioChip( + label: e, + selected: kind.value == e, + onTap: () { + kind.value = e; + kindNotifier.setKind(e); + associationListNotifier.filterAssociationList( + nameFilter, kind.value); + })) + .toList(), + const SizedBox( + width: 20, + ), + ])); + }, + error: (error, stackTrace) => + const Text(PhonebookTextConstants.errorKindsLoading), + loading: () => const CircularProgressIndicator()), + const SizedBox(height: 30), + ...associationList.when( + data: (associations) { + return associations + .map((association) => AssociationCard( + association: association, + onClicked: () { + associationNotifier.setAssociation(association); + QR.to(PhonebookRouter.root + + PhonebookRouter.associationDetail); + }, + )) + .toList(); + }, + loading: () => const [Center(child: CircularProgressIndicator())], + error: (error, stack) => [ + const Center( + child: Text( + PhonebookTextConstants.errorLoadAssociationList)) + ]) + ]))); } } diff --git a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart index 06a906cfb..30fd8c1cd 100644 --- a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart +++ b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/phonebook/ui/phonebook.dart'; class MemberDetailPage extends HookConsumerWidget { const MemberDetailPage({Key? key}) : super(key: key); @@ -9,7 +10,10 @@ class MemberDetailPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final memberProvider = ref.watch(completeMemberProvider); - return Container( + + return PhonebookTemplate( + child: + Container( margin: const EdgeInsets.all(10), width: MediaQuery.of(context).size.width, decoration: BoxDecoration(borderRadius: BorderRadius.circular(50)), @@ -38,6 +42,6 @@ class MemberDetailPage extends HookConsumerWidget { const Spacer(flex: 1), ])) ]), - ])); + ]))); } } diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index 529faf3cd..c04be5d31 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -8,13 +8,14 @@ import 'package:myecl/phonebook/providers/association_member_list_provider.dart' import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/edition_provider.dart'; import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; -import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:myecl/tools/ui/shrink_button.dart'; import 'package:myecl/user/providers/user_list_provider.dart'; +import 'package:qlevar_router/qlevar_router.dart'; import 'package:tuple/tuple.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/ui/pages/membership_editor_page/search_result.dart'; @@ -60,7 +61,6 @@ class MembershipEditorPage extends HookConsumerWidget { final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); - final pageNotifier = ref.watch(phonebookPageProvider.notifier); final memberRoleTagsNotifier = ref.watch(memberRoleTagsProvider.notifier); final memberRoleTags = ref.watch(memberRoleTagsProvider); @@ -75,147 +75,147 @@ class MembershipEditorPage extends HookConsumerWidget { .apparentName; } - return Padding( - padding: const EdgeInsets.all(20.0), - child: SingleChildScrollView( - child: Column( - children: [ - Center( - child: Container( - decoration: const BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.black)), - color: Colors.white, + return PhonebookTemplate( + child: + Padding( + padding: const EdgeInsets.all(20.0), + child: SingleChildScrollView( + child: Column( + children: [ + Center( + child: Container( + decoration: const BoxDecoration( + border: Border(bottom: BorderSide(color: Colors.black)), + color: Colors.white, + ), + child: Text( + edition + ? PhonebookTextConstants.editMembership + : PhonebookTextConstants.addMember, + style: const TextStyle(fontSize: 20)))), + if (!edition) + TextFormField( + onChanged: (value) { + tokenExpireWrapper(ref, () async { + if (queryController.text.isNotEmpty) { + await usersNotifier.filterUsers(queryController.text); + } else { + usersNotifier.clear(); + } + }); + }, + cursorColor: Colors.black, + controller: queryController, + decoration: const InputDecoration( + labelText: PhonebookTextConstants.member, + floatingLabelStyle: TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + ), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.black, width: 2.0), ), - child: Text( - edition - ? PhonebookTextConstants.editMembership - : PhonebookTextConstants.addMember, - style: const TextStyle(fontSize: 20)))), - if (!edition) - TextFormField( - onChanged: (value) { + ), + ), + const SizedBox( + height: 10, + ), + SearchResult(queryController: queryController), + SizedBox( + width: min(MediaQuery.of(context).size.width, 300), + child: Column(children: [ + ...rolesTags.when( + data: (data) { + return data.item1.tags + .map((e) => Row(children: [ + Text(e), + const Spacer(), + Checkbox( + value: data.item2[data.item1.tags.indexOf(e)], + fillColor: + MaterialStateProperty.all(Colors.black), + onChanged: (value) { + data.item2[data.item1.tags.indexOf(e)] = + value!; + debugPrint(data.item2.toString()); + apparentNameController.text = + nameConstructor(data); + memberRoleTagsNotifier + .setRoleTagsWithFilter(data); + rolesTagsNotifier.setChecked( + data.item1.tags.indexOf(e), value); + }, + ), + ])) + .toList(); + }, + error: (e, s) => [const Text('Error')], + loading: () => [const Text('Loading')], + ), + ]), + ), + const SizedBox(height: 5), + const Text(PhonebookTextConstants.apparentName), + TextField( + controller: apparentNameController, + ), + const SizedBox(height: 5), + ShrinkButton( + child: Text(!edition + ? PhonebookTextConstants.add + : PhonebookTextConstants.edit), + onTap: () async { + if (member.member.id == "") { + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.emptyMember); + return; + } + if (apparentNameController.text == "") { + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.emptyApparentName); + return; + } + debugPrint("Appui sur le bouton avec les paramètres:\n" + "association: $association\n" + "member: ${member.member}\n" + "rolesTags: $memberRoleTags\n" + "apparentName: ${apparentNameController.text}"); tokenExpireWrapper(ref, () async { - if (queryController.text.isNotEmpty) { - await usersNotifier.filterUsers(queryController.text); + if (edition) { + final value = await associationNotifier.updateMember( + association, + member.member, + memberRoleTags, + apparentNameController.text); + if (value) { + associationMemberListNotifier.loadMembers(association.id); + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.updatedMember); + QR.back(); + } else { + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.updatingError); + } } else { - usersNotifier.clear(); + final value = await associationNotifier.addMember( + association, + member.member, + memberRoleTags, + apparentNameController.text); + if (value) { + associationMemberListNotifier.loadMembers(association.id); + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.addedMember); + QR.back(); + } else { + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.addingError); + } } }); }, - cursorColor: Colors.black, - controller: queryController, - decoration: const InputDecoration( - labelText: PhonebookTextConstants.member, - floatingLabelStyle: TextStyle( - color: Colors.black, - fontWeight: FontWeight.bold, - ), - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide(color: Colors.black, width: 2.0), - ), - ), ), - const SizedBox( - height: 10, - ), - SearchResult(queryController: queryController), - SizedBox( - width: min(MediaQuery.of(context).size.width, 300), - child: Column(children: [ - ...rolesTags.when( - data: (data) { - return data.item1.tags - .map((e) => Row(children: [ - Text(e), - const Spacer(), - Checkbox( - value: data.item2[data.item1.tags.indexOf(e)], - fillColor: - MaterialStateProperty.all(Colors.black), - onChanged: (value) { - data.item2[data.item1.tags.indexOf(e)] = - value!; - debugPrint(data.item2.toString()); - apparentNameController.text = - nameConstructor(data); - memberRoleTagsNotifier - .setRoleTagsWithFilter(data); - rolesTagsNotifier.setChecked( - data.item1.tags.indexOf(e), value); - }, - ), - ])) - .toList(); - }, - error: (e, s) => [const Text('Error')], - loading: () => [const Text('Loading')], - ), - ]), - ), - const SizedBox(height: 5), - const Text(PhonebookTextConstants.apparentName), - TextField( - controller: apparentNameController, - ), - const SizedBox(height: 5), - ShrinkButton( - child: Text(!edition - ? PhonebookTextConstants.add - : PhonebookTextConstants.edit), - onTap: () async { - if (member.member.id == "") { - displayToastWithContext( - TypeMsg.msg, PhonebookTextConstants.emptyMember); - return; - } - if (apparentNameController.text == "") { - displayToastWithContext( - TypeMsg.msg, PhonebookTextConstants.emptyApparentName); - return; - } - debugPrint("Appui sur le bouton avec les paramètres:\n" - "association: $association\n" - "member: ${member.member}\n" - "rolesTags: $memberRoleTags\n" - "apparentName: ${apparentNameController.text}"); - tokenExpireWrapper(ref, () async { - if (edition) { - final value = await associationNotifier.updateMember( - association, - member.member, - memberRoleTags, - apparentNameController.text); - if (value) { - associationMemberListNotifier.loadMembers(association.id); - displayToastWithContext( - TypeMsg.msg, PhonebookTextConstants.updatedMember); - pageNotifier - .setPhonebookPage(PhonebookPage.associationEditor); - } else { - displayToastWithContext( - TypeMsg.msg, PhonebookTextConstants.updatingError); - } - } else { - final value = await associationNotifier.addMember( - association, - member.member, - memberRoleTags, - apparentNameController.text); - if (value) { - associationMemberListNotifier.loadMembers(association.id); - displayToastWithContext( - TypeMsg.msg, PhonebookTextConstants.addedMember); - pageNotifier - .setPhonebookPage(PhonebookPage.associationEditor); - } else { - displayToastWithContext( - TypeMsg.msg, PhonebookTextConstants.addingError); - } - } - }); - }, - ), - ], - ))); + ], + )))); } } diff --git a/lib/phonebook/ui/phonebook.dart b/lib/phonebook/ui/phonebook.dart index 18dbdb4b2..ccf339c13 100644 --- a/lib/phonebook/ui/phonebook.dart +++ b/lib/phonebook/ui/phonebook.dart @@ -1,67 +1,39 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/drawer/providers/animation_provider.dart'; import 'package:myecl/drawer/providers/swipe_provider.dart'; -import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; -import 'package:myecl/phonebook/ui/page_switcher.dart'; import 'package:myecl/phonebook/ui/top_bar.dart'; -class PhonebookHomePage extends HookConsumerWidget { - final SwipeControllerNotifier controllerNotifier; - final AnimationController controller; - const PhonebookHomePage( - {Key? key, required this.controllerNotifier, required this.controller}) +class PhonebookTemplate extends HookConsumerWidget { + final Widget child; + const PhonebookTemplate( + {Key? key, required this.child}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { - final page = ref.watch(phonebookPageProvider); - final pageNotifier = ref.watch(phonebookPageProvider.notifier); + final animationNotifier = ref.watch(animationProvider.notifier); + final controller = + ref.watch(swipeControllerProvider(animationNotifier.animation!)); + final controllerNotifier = ref + .watch(swipeControllerProvider(animationNotifier.animation!).notifier); return Scaffold( - body: WillPopScope( - onWillPop: () async { - switch (page) { - case PhonebookPage.main: - if (!controller.isCompleted) { - controllerNotifier.toggle(); - break; - } else { - return true; - } - case PhonebookPage.memberDetail: - pageNotifier.setPhonebookPage(PhonebookPage.associationPage); - break; - case PhonebookPage.admin: - pageNotifier.setPhonebookPage(PhonebookPage.main); - break; - case PhonebookPage.associationEditor: - pageNotifier.setPhonebookPage(PhonebookPage.admin); - break; - case PhonebookPage.associationPage: - pageNotifier.setPhonebookPage(PhonebookPage.main); - break; - case PhonebookPage.associationCreation: - pageNotifier.setPhonebookPage(PhonebookPage.admin); - break; - case PhonebookPage.membershipEdition: - pageNotifier.setPhonebookPage(PhonebookPage.associationEditor); - break; - } - return false; - }, + body: Container( + color: Colors.white, child: SafeArea( - child: IgnorePointer( - ignoring: controller.isCompleted, - child: Column( - children: [ - TopBar( - controllerNotifier: controllerNotifier, - ), - const Expanded(child: PageSwitcher()), - ], + child: IgnorePointer( + ignoring: controller.isCompleted, + child: Column( + children: [ + TopBar( + controllerNotifier: controllerNotifier, + ), + Expanded(child: child), + ], + ), ), ), - ), ), ); } -} +} \ No newline at end of file diff --git a/lib/phonebook/ui/top_bar.dart b/lib/phonebook/ui/top_bar.dart index a94d66aaa..b9645564c 100644 --- a/lib/phonebook/ui/top_bar.dart +++ b/lib/phonebook/ui/top_bar.dart @@ -2,8 +2,9 @@ import 'package:flutter/material.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/drawer/providers/swipe_provider.dart'; -import 'package:myecl/phonebook/providers/phonebook_page_provider.dart'; +import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:qlevar_router/qlevar_router.dart'; class TopBar extends HookConsumerWidget { final SwipeControllerNotifier controllerNotifier; @@ -11,8 +12,6 @@ class TopBar extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final page = ref.watch(phonebookPageProvider); - final pageNotifier = ref.watch(phonebookPageProvider.notifier); return Column( children: [ const SizedBox( @@ -27,34 +26,14 @@ class TopBar extends HookConsumerWidget { builder: (BuildContext appBarContext) { return IconButton( onPressed: () { - switch (page) { - case PhonebookPage.main: - controllerNotifier.toggle(); - break; - case PhonebookPage.memberDetail: - pageNotifier.setPhonebookPage( - PhonebookPage.associationPage); - break; - case PhonebookPage.admin: - pageNotifier.setPhonebookPage(PhonebookPage.main); - break; - case PhonebookPage.associationEditor: - pageNotifier.setPhonebookPage(PhonebookPage.admin); - break; - case PhonebookPage.associationPage: - pageNotifier.setPhonebookPage(PhonebookPage.main); - break; - case PhonebookPage.associationCreation: - pageNotifier.setPhonebookPage(PhonebookPage.admin); - break; - case PhonebookPage.membershipEdition: - pageNotifier.setPhonebookPage( - PhonebookPage.associationEditor); - break; + if (QR.currentPath == PhonebookRouter.root) { + controllerNotifier.toggle(); + } else { + QR.back(); } }, icon: HeroIcon( - page == PhonebookPage.main + QR.currentPath == PhonebookRouter.root ? HeroIcons.bars3BottomLeft : HeroIcons.chevronLeft, color: Colors.black, diff --git a/lib/router.dart b/lib/router.dart index 25aea9e54..f48281fe3 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -15,6 +15,7 @@ import 'package:myecl/others/ui/no_internet_page.dart' deferred as no_internet_page; import 'package:myecl/others/ui/no_module.dart' deferred as no_module_page; import 'package:myecl/others/ui/update_page.dart' deferred as update_page; +import 'package:myecl/phonebook/router.dart'; import 'package:myecl/recommendation/router.dart'; import 'package:myecl/settings/router.dart'; import 'package:myecl/raffle/router.dart'; @@ -84,6 +85,7 @@ class AppRouter { RecommendationRouter(ref).route(), SettingsRouter(ref).route(), VoteRouter(ref).route(), + PhonebookRouter(ref).route(), ]; } } diff --git a/lib/settings/providers/module_list_provider.dart b/lib/settings/providers/module_list_provider.dart index 1b0d289e4..ad9d5a580 100644 --- a/lib/settings/providers/module_list_provider.dart +++ b/lib/settings/providers/module_list_provider.dart @@ -11,6 +11,7 @@ import 'package:collection/collection.dart'; import 'package:myecl/event/router.dart'; import 'package:myecl/home/router.dart'; import 'package:myecl/loan/router.dart'; +import 'package:myecl/phonebook/router.dart'; import 'package:myecl/raffle/router.dart'; import 'package:myecl/recommendation/router.dart'; import 'package:myecl/vote/router.dart'; @@ -42,6 +43,7 @@ class ModulesNotifier extends StateNotifier> { EventRouter.module, RaffleRouter.module, RecommendationRouter.module, + PhonebookRouter.module ]; ModulesNotifier() : super([]); From f82aba3e5d031d97d95a7a0defa9841133ebec24 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:02 +0100 Subject: [PATCH 034/123] Fix routing --- lib/phonebook/router.dart | 3 ++- .../association_editor_page/association_editor_page.dart | 7 ++++++- .../association_editor_page/member_editable_card.dart | 8 +++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/phonebook/router.dart b/lib/phonebook/router.dart index e241ab6ae..7d5e293aa 100644 --- a/lib/phonebook/router.dart +++ b/lib/phonebook/router.dart @@ -5,6 +5,7 @@ import 'package:myecl/phonebook/providers/phonebook_admin_provider.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/admin_page.dart'; import 'package:myecl/phonebook/ui/pages/association_creation_page/association_creation_page.dart'; import 'package:myecl/phonebook/ui/pages/association_editor_page/association_editor_page.dart'; +import 'package:myecl/phonebook/ui/pages/association_page/association_page.dart'; import 'package:myecl/phonebook/ui/pages/main_page/main_page.dart'; import 'package:myecl/phonebook/ui/pages/member_detail_page/member_detail_page.dart'; import 'package:myecl/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart'; @@ -43,7 +44,7 @@ class PhonebookRouter { ), QRoute(path: createAssociaiton, builder: () => const AssociationCreationPage()), ]), - QRoute(path: associationDetail, builder: () => const AssociationEditorPage(), + QRoute(path: associationDetail, builder: () => const AssociationPage(), children: [ QRoute(path: editAssociation, builder: () => const AssociationEditorPage(), middleware: [ diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index c23553b0d..d693d448c 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -294,7 +294,12 @@ class AssociationEditorPage extends HookConsumerWidget { completeMemberNotifier .setCompleteMember(CompleteMember.empty()); editionNotifier.setStatus(false); - QR.to(PhonebookRouter.root + PhonebookRouter.editAssociation + PhonebookRouter.addEditMember); + if (QR.currentPath.contains(PhonebookRouter.admin)) { + QR.to(PhonebookRouter.root + PhonebookRouter.admin + PhonebookRouter.editAssociation + PhonebookRouter.addEditMember); + } else { + QR.to(PhonebookRouter.root + PhonebookRouter.editAssociation + PhonebookRouter.addEditMember); + } + }, child: Container( width: 40, diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index 61c49b3e4..534aaf9c0 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -115,10 +115,16 @@ class MemberEditableCard extends HookConsumerWidget { roleTagsNotifier.loadRoleTagsFromMember(member, association); completeMemberNotifier.setCompleteMember(member); editionNotifier.setStatus(true); - QR.to(PhonebookRouter.root + + if (QR.currentPath.contains(PhonebookRouter.admin)) { + QR.to(PhonebookRouter.root + PhonebookRouter.admin + PhonebookRouter.editAssociation + PhonebookRouter.addEditMember); + } else { + QR.to(PhonebookRouter.root + + PhonebookRouter.editAssociation + + PhonebookRouter.addEditMember); + } }), const SizedBox(width: 10), DeleteButton( From d6251d086e03eed9ad00ecb5c249893f193c344f Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:02 +0100 Subject: [PATCH 035/123] Fix member list + cleanup --- lib/phonebook/class/association.dart | 1 - lib/phonebook/class/complete_member.dart | 9 +++++---- lib/phonebook/class/membership.dart | 11 ++++++----- .../providers/association_kinds_provider.dart | 2 -- .../providers/association_list_provider.dart | 1 - .../providers/association_member_list_provider.dart | 1 - .../providers/member_role_tags_provider.dart | 3 --- lib/phonebook/providers/roles_tags_provider.dart | 1 - .../repositories/association_repository.dart | 6 +++--- 9 files changed, 14 insertions(+), 21 deletions(-) diff --git a/lib/phonebook/class/association.dart b/lib/phonebook/class/association.dart index 1ff1168f6..8746e4d27 100644 --- a/lib/phonebook/class/association.dart +++ b/lib/phonebook/class/association.dart @@ -16,7 +16,6 @@ class Association{ late final int mandateYear; Association.fromJSON(Map json){ - debugPrint("Association.fromJSON: $json"); id = json['id']; name = json['name']; description = json['description']; diff --git a/lib/phonebook/class/complete_member.dart b/lib/phonebook/class/complete_member.dart index a71c1beba..08ad576f9 100644 --- a/lib/phonebook/class/complete_member.dart +++ b/lib/phonebook/class/complete_member.dart @@ -1,3 +1,4 @@ +import 'package:flutter/material.dart'; import 'package:myecl/phonebook/class/membership.dart'; import 'member.dart'; @@ -17,10 +18,10 @@ class CompleteMember { nickname: json['nickname'], id: json['id'], email: json['email'], - promotion: json['promotion']); - memberships = json['memberships'] - .map((membership) => Membership.fromJSON(membership)) - .toList(); + promotion: json['promotion']??""); + memberships = List.from(json['memberships'] + .map((membership) => Membership.fromJSON(membership))); + } Map toJSON() { diff --git a/lib/phonebook/class/membership.dart b/lib/phonebook/class/membership.dart index 8555fdb8f..1024585ce 100644 --- a/lib/phonebook/class/membership.dart +++ b/lib/phonebook/class/membership.dart @@ -1,3 +1,4 @@ +import 'package:flutter/material.dart'; import 'package:myecl/phonebook/class/association.dart'; class Membership { @@ -14,11 +15,11 @@ class Membership { late final String apparentName; Membership.fromJSON(Map json){ - id = json['id']; - association = json['association']; - rolesTags = json['role_tags']; - apparentName = json['role_name']; - } + id = json['id']; + association = Association.fromJSON(json['association']); + rolesTags = json['role_tags'].split(";"); + apparentName = json['role_name']; + } Map toJSON(){ final data = { diff --git a/lib/phonebook/providers/association_kinds_provider.dart b/lib/phonebook/providers/association_kinds_provider.dart index 07fa98429..bbea6326d 100644 --- a/lib/phonebook/providers/association_kinds_provider.dart +++ b/lib/phonebook/providers/association_kinds_provider.dart @@ -18,10 +18,8 @@ class AssociationKindsNotifier extends SingleNotifier { } Future> loadAssociationKinds() async { - debugPrint("loadAssociationKinds"); AsyncValue result = await load(() async => associationRepository.getAssociationKinds()); - debugPrint("loadAssociationKinds result: $result"); return result; } } diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index e18e5a230..6690a125f 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -17,7 +17,6 @@ class AssociationListNotifier extends ListNotifier { Future>> loadAssociations() async { associationList = await loadList(() async => associationRepository.getAssociationList()); - debugPrint("associationList: $associationList"); return associationList; } diff --git a/lib/phonebook/providers/association_member_list_provider.dart b/lib/phonebook/providers/association_member_list_provider.dart index 9c235a99f..a6bc60860 100644 --- a/lib/phonebook/providers/association_member_list_provider.dart +++ b/lib/phonebook/providers/association_member_list_provider.dart @@ -17,7 +17,6 @@ class AssociationMemberListNotifier extends ListNotifier { Future>> loadMembers(String associationId) async { dynamic members = await loadList(() async => associationMemberRepository.getAssociationMemberList(associationId)); - debugPrint("Membres : $members"); return members; } } diff --git a/lib/phonebook/providers/member_role_tags_provider.dart b/lib/phonebook/providers/member_role_tags_provider.dart index 363f63fef..e02fc8ddf 100644 --- a/lib/phonebook/providers/member_role_tags_provider.dart +++ b/lib/phonebook/providers/member_role_tags_provider.dart @@ -12,8 +12,6 @@ class MemberRoleTagsProvider extends StateNotifier> { MemberRoleTagsProvider() : super([]); void setRoleTagsWithFilter(Tuple2> data) { - debugPrint(data.item1.tags.toString()); - debugPrint(data.item2.toString()); List newRoleTags = []; for (int i = 0; i < data.item2.length; i++) { if (data.item2[i]) { @@ -21,6 +19,5 @@ class MemberRoleTagsProvider extends StateNotifier> { } } state = newRoleTags; - debugPrint(state.toString()); } } diff --git a/lib/phonebook/providers/roles_tags_provider.dart b/lib/phonebook/providers/roles_tags_provider.dart index bce3a9852..ac297f10d 100644 --- a/lib/phonebook/providers/roles_tags_provider.dart +++ b/lib/phonebook/providers/roles_tags_provider.dart @@ -21,7 +21,6 @@ class RolesTagsNotifier extends SingleNotifier>> { } Future>>> loadRolesTags() async { - debugPrint('loadRolesTags'); return await load(() async => rolesTagsRepository.getRolesTags()); } diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index 276ec6f48..aef1aeae2 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -33,10 +33,10 @@ class AssociationRepository extends Repository { Future addMember(Association association, Member member, List rolesTags, String apparentName) async { return await create({ - "member_id": member.id, + "user_id": member.id, "association_id": association.id, - "rolesTags": rolesTags, - "apparentName": apparentName + "role_tags": rolesTags.join(";"), + "role_name": apparentName }, suffix: "memberships"); } From 169fbeaf6bc06a082b0f0d12cad00df7cde11db2 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:02 +0100 Subject: [PATCH 036/123] Use text constants and fix member detail --- lib/phonebook/class/complete_member.dart | 1 + .../providers/phonebook_admin_provider.dart | 3 ++- lib/phonebook/tools/constants.dart | 2 ++ .../member_detail_page.dart | 25 ++++++++++--------- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/lib/phonebook/class/complete_member.dart b/lib/phonebook/class/complete_member.dart index 08ad576f9..a15c5d0cf 100644 --- a/lib/phonebook/class/complete_member.dart +++ b/lib/phonebook/class/complete_member.dart @@ -12,6 +12,7 @@ class CompleteMember { late final List memberships; CompleteMember.fromJSON(Map json) { + debugPrint(json.toString()); member = Member( name: json['name'], firstname: json['firstname'], diff --git a/lib/phonebook/providers/phonebook_admin_provider.dart b/lib/phonebook/providers/phonebook_admin_provider.dart index ca36c2f87..d596602e8 100644 --- a/lib/phonebook/providers/phonebook_admin_provider.dart +++ b/lib/phonebook/providers/phonebook_admin_provider.dart @@ -1,6 +1,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/user/providers/user_provider.dart'; final isPhonebookAdminProvider = StateProvider((ref) { @@ -19,7 +20,7 @@ final isAssociationPresidentProvider = StateProvider((ref) { if (members.map((e) => e.member.id).contains(me.id)) { if (members.firstWhere((member) => member.member.id == me.id) .memberships.firstWhere((membership) => membership.association.id == association.id) - .rolesTags.contains("Prez'")) { + .rolesTags.contains(PhonebookTextConstants.presidentRoleTag)) { return true; } } diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index 97e40d9e5..3432615a4 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -85,6 +85,8 @@ class PhonebookTextConstants { static const String all = "Toutes"; static const String research = "Rechercher"; + + static const String presidentRoleTag = "Prez'"; } class PhonebookColorConstants { diff --git a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart index 30fd8c1cd..125664bea 100644 --- a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart +++ b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart @@ -1,8 +1,12 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; +import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/phonebook/ui/pages/main_page/association_card.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; +import 'package:qlevar_router/qlevar_router.dart'; class MemberDetailPage extends HookConsumerWidget { const MemberDetailPage({Key? key}) : super(key: key); @@ -10,7 +14,7 @@ class MemberDetailPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final memberProvider = ref.watch(completeMemberProvider); - + final associationNotifier = ref.watch(asyncAssociationProvider.notifier); return PhonebookTemplate( child: Container( @@ -31,17 +35,14 @@ class MemberDetailPage extends HookConsumerWidget { "${PhonebookTextConstants.email} ${memberProvider.member.email}"), const Text(PhonebookTextConstants .association), //TODO: à changer pour dépendre du nombre d'associatione - Column(children: [ - for (var membership in memberProvider.memberships) - Container( - margin: const EdgeInsets.all(10), - child: Row(children: [ - const Spacer(flex: 1), - Text( - "${membership.association.name} : ${membership.apparentName}"), - const Spacer(flex: 1), - ])) - ]), + ...memberProvider.memberships.map( + (e) => AssociationCard( + association: e.association, + onClicked: (() { + associationNotifier.setAssociation(e.association); + QR.to(PhonebookRouter.root + + PhonebookRouter.associationDetail); + }))).toList(), ]))); } } From b8af8be19c6c335cff70bfbe7e936c09ccd17ca6 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:02 +0100 Subject: [PATCH 037/123] Change phonebook's admin and allow prez modifications --- .../providers/phonebook_admin_provider.dart | 7 +- .../association_page/association_page.dart | 208 +++++++++++------- .../ui/pages/main_page/main_page.dart | 4 +- 3 files changed, 134 insertions(+), 85 deletions(-) diff --git a/lib/phonebook/providers/phonebook_admin_provider.dart b/lib/phonebook/providers/phonebook_admin_provider.dart index d596602e8..47aee7540 100644 --- a/lib/phonebook/providers/phonebook_admin_provider.dart +++ b/lib/phonebook/providers/phonebook_admin_provider.dart @@ -1,3 +1,4 @@ +import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; @@ -16,15 +17,17 @@ final isAssociationPresidentProvider = StateProvider((ref) { final association = ref.watch(associationProvider); final membersList = ref.watch(associationMemberListProvider); final me = ref.watch(userProvider); + bool isPresident = false; membersList.whenData((members) { if (members.map((e) => e.member.id).contains(me.id)) { if (members.firstWhere((member) => member.member.id == me.id) .memberships.firstWhere((membership) => membership.association.id == association.id) .rolesTags.contains(PhonebookTextConstants.presidentRoleTag)) { - return true; + isPresident = true; } } }); - return false; + debugPrint("isPresident: $isPresident"); + return isPresident; }); diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index 7a381ba95..d823e8f8b 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -1,12 +1,16 @@ import 'package:flutter/material.dart'; +import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; +import 'package:myecl/phonebook/providers/phonebook_admin_provider.dart'; +import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/pages/association_page/member_card.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/tools/ui/refresher.dart'; +import 'package:qlevar_router/qlevar_router.dart'; class AssociationPage extends HookConsumerWidget { const AssociationPage({Key? key}) : super(key: key); @@ -20,6 +24,7 @@ class AssociationPage extends HookConsumerWidget { ref.watch(associationMemberListProvider.notifier); final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); + final isPresident = ref.watch(isAssociationPresidentProvider); return PhonebookTemplate( child: @@ -29,90 +34,131 @@ class AssociationPage extends HookConsumerWidget { await associationPictureNotifier .getAssociationPicture(association.id); }, - child: Column(children: [ - const Text(PhonebookTextConstants.associationDetail, - style: TextStyle(fontSize: 30)), - const SizedBox( - height: 20, - ), - Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - spreadRadius: 5, - blurRadius: 10, - offset: const Offset(2, 3), + child: Stack( + children: [ + Column(children: [ + const Text(PhonebookTextConstants.associationDetail, + style: TextStyle(fontSize: 30)), + const SizedBox( + height: 20, + ), + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + spreadRadius: 5, + blurRadius: 10, + offset: const Offset(2, 3), + ), + ], ), - ], - ), - child: associationPicture.when( - data: (picture) { - return Container( - width: 40, - height: 40, - decoration: BoxDecoration( - shape: BoxShape.circle, - image: DecorationImage( - image: picture.image, - fit: BoxFit.cover, + child: associationPicture.when( + data: (picture) { + return Container( + width: 40, + height: 40, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: picture.image, + fit: BoxFit.cover, + ), + ), + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return const Center( + child: + Text(PhonebookTextConstants.errorLoadAssociationPicture), + ); + }, + ), + ), + const SizedBox(height: 20), + Text( + association.name, + style: const TextStyle(fontSize: 40, color: Colors.black), + ), + const SizedBox(height: 10), + Text(association.kind, + style: const TextStyle(fontSize: 20, color: Colors.black)), + const SizedBox(height: 10), + Text( + association.description, + style: const TextStyle(fontSize: 15, color: Colors.black), + ), + const SizedBox(height: 10), + Text( + "${PhonebookTextConstants.activeMandate} ${association.mandateYear}", + style: const TextStyle(fontSize: 15, color: Colors.black), + ), + const SizedBox( + height: 20, + ), + associationMemberList.when( + data: (members) { + return Column( + children: members + .map((member) => MemberCard(member: member)) + .toList()); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return const Center( + child: Text(PhonebookTextConstants.errorLoadAssociationMember), + ); + }, + ) + ] + ), + if (isPresident) + Positioned( + top: 20, + right: 20, + child: GestureDetector( + onTap: () { + QR.to(PhonebookRouter.root + PhonebookRouter.admin + PhonebookRouter.editAssociation); + }, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + blurRadius: 10, + offset: const Offset(0, 5)) + ]), + child: const Row( + children: [ + HeroIcon(HeroIcons.userGroup, color: Colors.white), + SizedBox(width: 10), + Text(PhonebookTextConstants.admin, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.white)), + ], + ), ), ), - ); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: - Text(PhonebookTextConstants.errorLoadAssociationPicture), - ); - }, ), - ), - const SizedBox(height: 20), - Text( - association.name, - style: const TextStyle(fontSize: 40, color: Colors.black), - ), - const SizedBox(height: 10), - Text(association.kind, - style: const TextStyle(fontSize: 20, color: Colors.black)), - const SizedBox(height: 10), - Text( - association.description, - style: const TextStyle(fontSize: 15, color: Colors.black), - ), - const SizedBox(height: 10), - Text( - "${PhonebookTextConstants.activeMandate} ${association.mandateYear}", - style: const TextStyle(fontSize: 15, color: Colors.black), - ), - const SizedBox( - height: 20, - ), - associationMemberList.when( - data: (members) { - return Column( - children: members - .map((member) => MemberCard(member: member)) - .toList()); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: Text(PhonebookTextConstants.errorLoadAssociationMember), - ); - }, - ) - ]))); + ] + ) + ) + ); } } diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 86d1298ad..e8094af91 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -6,10 +6,10 @@ import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/providers/phonebook_admin_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/admin/providers/is_admin.dart'; import 'package:myecl/phonebook/ui/pages/main_page/association_card.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/phonebook/ui/radio_chip.dart'; @@ -22,7 +22,7 @@ class PhonebookMainPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final isAdmin = ref.watch(isAdminProvider); + final isAdmin = ref.watch(isPhonebookAdminProvider); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationListNotifier = ref.watch(associationListProvider.notifier); final associationList = ref.watch(associationListProvider); From 02a19beb600373705b8d4fb1d17ff6e94ce7b799 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:02 +0100 Subject: [PATCH 038/123] Change to preshot phonebook history --- .../providers/association_member_list_provider.dart | 6 +++--- lib/phonebook/providers/phonebook_admin_provider.dart | 2 +- .../repositories/association_member_repository.dart | 4 ++-- .../association_editor_page/association_editor_page.dart | 2 +- .../pages/association_editor_page/member_editable_card.dart | 2 +- .../ui/pages/association_page/association_page.dart | 2 +- .../membership_editor_page/membership_editor_page.dart | 4 ++-- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/phonebook/providers/association_member_list_provider.dart b/lib/phonebook/providers/association_member_list_provider.dart index a6bc60860..9e5c3d91e 100644 --- a/lib/phonebook/providers/association_member_list_provider.dart +++ b/lib/phonebook/providers/association_member_list_provider.dart @@ -15,8 +15,8 @@ class AssociationMemberListNotifier extends ListNotifier { associationMemberRepository.setToken(token); } - Future>> loadMembers(String associationId) async { - dynamic members = await loadList(() async => associationMemberRepository.getAssociationMemberList(associationId)); + Future>> loadMembers(String associationId, String year) async { + dynamic members = await loadList(() async => associationMemberRepository.getAssociationMemberList(associationId, year)); return members; } } @@ -28,7 +28,7 @@ final associationMemberListProvider = StateNotifierProvider< AssociationMemberListNotifier(token: token); tokenExpireWrapperAuth(ref, () async { final association = ref.watch(associationProvider); - await provider.loadMembers(association.id); + await provider.loadMembers(association.id, association.mandateYear.toString()); }); return provider; }); diff --git a/lib/phonebook/providers/phonebook_admin_provider.dart b/lib/phonebook/providers/phonebook_admin_provider.dart index 47aee7540..0654de552 100644 --- a/lib/phonebook/providers/phonebook_admin_provider.dart +++ b/lib/phonebook/providers/phonebook_admin_provider.dart @@ -20,7 +20,7 @@ final isAssociationPresidentProvider = StateProvider((ref) { bool isPresident = false; membersList.whenData((members) { if (members.map((e) => e.member.id).contains(me.id)) { - if (members.firstWhere((member) => member.member.id == me.id) + if (members.firstWhere((completeMember) => completeMember.member.id == me.id) .memberships.firstWhere((membership) => membership.association.id == association.id) .rolesTags.contains(PhonebookTextConstants.presidentRoleTag)) { isPresident = true; diff --git a/lib/phonebook/repositories/association_member_repository.dart b/lib/phonebook/repositories/association_member_repository.dart index 4c25415e8..161a13b9e 100644 --- a/lib/phonebook/repositories/association_member_repository.dart +++ b/lib/phonebook/repositories/association_member_repository.dart @@ -7,9 +7,9 @@ class AssociationMemberRepository extends Repository { final ext = "phonebook/associations/"; Future> getAssociationMemberList( - String associationId) async { + String associationId, String year) async { return List.from( - (await getList(suffix: "$associationId/members")) + (await getList(suffix: "$associationId/members/$year")) .map((x) => CompleteMember.fromJSON(x))); } } diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index d693d448c..a199af9ba 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -52,7 +52,7 @@ class AssociationEditorPage extends HookConsumerWidget { child: Refresher( onRefresh: () async { - await associationMemberListNotifier.loadMembers(association.id); + await associationMemberListNotifier.loadMembers(association.id, association.mandateYear.toString()); await associationPictureNotifier.getAssociationPicture(association.id); }, child: Column(children: [ diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index 534aaf9c0..e5fe1b6a2 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -132,7 +132,7 @@ class MemberEditableCard extends HookConsumerWidget { final result = await associationNotifier.deleteMember( member.memberships.firstWhere( (element) => element.association.id == association.id)); - await associationMembersNotifier.loadMembers(association.id); + await associationMembersNotifier.loadMembers(association.id, association.mandateYear.toString()); if (result) { displayToastWithContext( TypeMsg.msg, PhonebookTextConstants.deletedMember); diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index d823e8f8b..f03cce0a8 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -30,7 +30,7 @@ class AssociationPage extends HookConsumerWidget { child: Refresher( onRefresh: () async { - await associationMemberListNotifier.loadMembers(association.id); + await associationMemberListNotifier.loadMembers(association.id, association.mandateYear.toString()); await associationPictureNotifier .getAssociationPicture(association.id); }, diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index c04be5d31..4e1b54f5d 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -188,7 +188,7 @@ class MembershipEditorPage extends HookConsumerWidget { memberRoleTags, apparentNameController.text); if (value) { - associationMemberListNotifier.loadMembers(association.id); + associationMemberListNotifier.loadMembers(association.id, association.mandateYear.toString()); displayToastWithContext( TypeMsg.msg, PhonebookTextConstants.updatedMember); QR.back(); @@ -203,7 +203,7 @@ class MembershipEditorPage extends HookConsumerWidget { memberRoleTags, apparentNameController.text); if (value) { - associationMemberListNotifier.loadMembers(association.id); + associationMemberListNotifier.loadMembers(association.id, association.mandateYear.toString()); displayToastWithContext( TypeMsg.msg, PhonebookTextConstants.addedMember); QR.back(); From fa3265184dc02fe7e953cacfa1cfc04c923c39cc Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:03 +0100 Subject: [PATCH 039/123] clean up --- lib/phonebook/class/association.dart | 4 +- lib/phonebook/class/association_kinds.dart | 4 +- lib/phonebook/class/complete_member.dart | 8 +- lib/phonebook/class/member.dart | 4 +- lib/phonebook/class/membership.dart | 6 +- lib/phonebook/class/roles_tags.dart | 4 +- .../providers/association_kinds_provider.dart | 4 +- .../providers/association_list_provider.dart | 13 +- .../association_member_list_provider.dart | 3 +- .../associations_pictures_provider.dart | 7 +- lib/phonebook/providers/reload_provider.dart | 13 -- .../providers/roles_tags_provider.dart | 2 +- .../association_member_repository.dart | 2 +- .../repositories/association_repository.dart | 10 +- .../repositories/member_repository.dart | 8 +- .../repositories/role_tags_repository.dart | 2 +- lib/phonebook/router.dart | 3 +- lib/phonebook/tools/function.dart | 15 ++ .../admin_page/editable_association_card.dart | 8 +- .../ui/pages/admin_page/edition_button.dart | 2 +- .../association_creation_page/text_entry.dart | 2 - .../association_editor_page.dart | 4 - .../membership_dialog.dart | 159 ------------------ .../membership_editor_page.dart | 25 +-- 24 files changed, 53 insertions(+), 259 deletions(-) delete mode 100644 lib/phonebook/providers/reload_provider.dart create mode 100644 lib/phonebook/tools/function.dart delete mode 100644 lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart diff --git a/lib/phonebook/class/association.dart b/lib/phonebook/class/association.dart index 8746e4d27..7a9f17f0c 100644 --- a/lib/phonebook/class/association.dart +++ b/lib/phonebook/class/association.dart @@ -15,7 +15,7 @@ class Association{ late final String kind; late final int mandateYear; - Association.fromJSON(Map json){ + Association.fromJson(Map json){ id = json['id']; name = json['name']; description = json['description']; @@ -23,7 +23,7 @@ class Association{ mandateYear = json['mandate_year']; } - Map toJSON() { + Map toJson() { final data = { 'id': id, 'name': name, diff --git a/lib/phonebook/class/association_kinds.dart b/lib/phonebook/class/association_kinds.dart index b2ff65b5b..e74ea1355 100644 --- a/lib/phonebook/class/association_kinds.dart +++ b/lib/phonebook/class/association_kinds.dart @@ -5,11 +5,11 @@ class AssociationKinds { late final List kinds; - AssociationKinds.fromJSON(Map json) { + AssociationKinds.fromJson(Map json) { kinds = json['kinds'].map((dynamic tag) => tag.toString()).toList(); } - Map toJSON() { + Map toJson() { final data = { 'kinds': kinds, }; diff --git a/lib/phonebook/class/complete_member.dart b/lib/phonebook/class/complete_member.dart index a15c5d0cf..34ceb9ba0 100644 --- a/lib/phonebook/class/complete_member.dart +++ b/lib/phonebook/class/complete_member.dart @@ -11,7 +11,7 @@ class CompleteMember { late final Member member; late final List memberships; - CompleteMember.fromJSON(Map json) { + CompleteMember.fromJson(Map json) { debugPrint(json.toString()); member = Member( name: json['name'], @@ -21,14 +21,14 @@ class CompleteMember { email: json['email'], promotion: json['promotion']??""); memberships = List.from(json['memberships'] - .map((membership) => Membership.fromJSON(membership))); + .map((membership) => Membership.fromJson(membership))); } - Map toJSON() { + Map toJson() { final data = { 'member': member.id, - 'memberships': memberships.map((e) => e.toJSON()).toList(), + 'memberships': memberships.map((e) => e.toJson()).toList(), }; return data; } diff --git a/lib/phonebook/class/member.dart b/lib/phonebook/class/member.dart index 3eb4f9a46..2998a9c88 100644 --- a/lib/phonebook/class/member.dart +++ b/lib/phonebook/class/member.dart @@ -17,7 +17,7 @@ class Member { late final String email; late final String promotion; - Member.fromJSON(Map json) { + Member.fromJson(Map json) { name = json['name']; firstname = json['firstname']; nickname = json['nickname']; @@ -26,7 +26,7 @@ class Member { promotion = json['promotion']; } - Map toJSON() { + Map toJson() { final data = { 'name': name, 'firstname': firstname, diff --git a/lib/phonebook/class/membership.dart b/lib/phonebook/class/membership.dart index 1024585ce..cdf1c6295 100644 --- a/lib/phonebook/class/membership.dart +++ b/lib/phonebook/class/membership.dart @@ -14,14 +14,14 @@ class Membership { late final List rolesTags; late final String apparentName; - Membership.fromJSON(Map json){ + Membership.fromJson(Map json){ id = json['id']; - association = Association.fromJSON(json['association']); + association = Association.fromJson(json['association']); rolesTags = json['role_tags'].split(";"); apparentName = json['role_name']; } - Map toJSON(){ + Map toJson(){ final data = { 'id': id, 'association': association.id, diff --git a/lib/phonebook/class/roles_tags.dart b/lib/phonebook/class/roles_tags.dart index d6f66aa37..bc3642c01 100644 --- a/lib/phonebook/class/roles_tags.dart +++ b/lib/phonebook/class/roles_tags.dart @@ -5,11 +5,11 @@ class RolesTags { late final List tags; - RolesTags.fromJSON(Map json) { + RolesTags.fromJson(Map json) { tags = json['tags'].map((dynamic tag) => tag.toString()).toList(); } - Map toJSON() { + Map toJson() { final data = { 'tags': tags, }; diff --git a/lib/phonebook/providers/association_kinds_provider.dart b/lib/phonebook/providers/association_kinds_provider.dart index bbea6326d..ff19c170c 100644 --- a/lib/phonebook/providers/association_kinds_provider.dart +++ b/lib/phonebook/providers/association_kinds_provider.dart @@ -18,9 +18,7 @@ class AssociationKindsNotifier extends SingleNotifier { } Future> loadAssociationKinds() async { - AsyncValue result = - await load(() async => associationRepository.getAssociationKinds()); - return result; + return await load(associationRepository.getAssociationKinds); } } diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index 6690a125f..eb665191e 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -16,8 +16,7 @@ class AssociationListNotifier extends ListNotifier { } Future>> loadAssociations() async { - associationList = await loadList(() async => associationRepository.getAssociationList()); - return associationList; + return await loadList(associationRepository.getAssociationList); } Future createAssociation(Association association) async { @@ -95,13 +94,3 @@ final associationListProvider = StateNotifierProvider>>( -// (ref) { -// final token = ref.watch(tokenProvider); -// AssociationListNotifier provider = AssociationListNotifier(token: token); -// tokenExpireWrapperAuth(ref, () async { -// await provider.loadAssociationsFromUser(ref.watch(userProvider)); -// }); -// return provider; -//}); diff --git a/lib/phonebook/providers/association_member_list_provider.dart b/lib/phonebook/providers/association_member_list_provider.dart index 9e5c3d91e..bd7c06a8a 100644 --- a/lib/phonebook/providers/association_member_list_provider.dart +++ b/lib/phonebook/providers/association_member_list_provider.dart @@ -16,8 +16,7 @@ class AssociationMemberListNotifier extends ListNotifier { } Future>> loadMembers(String associationId, String year) async { - dynamic members = await loadList(() async => associationMemberRepository.getAssociationMemberList(associationId, year)); - return members; + return await loadList(() async => associationMemberRepository.getAssociationMemberList(associationId, year)); } } diff --git a/lib/phonebook/providers/associations_pictures_provider.dart b/lib/phonebook/providers/associations_pictures_provider.dart index 5207db8d2..d697a815c 100644 --- a/lib/phonebook/providers/associations_pictures_provider.dart +++ b/lib/phonebook/providers/associations_pictures_provider.dart @@ -15,16 +15,13 @@ final associationPicturesProvider = StateNotifierProvider< AssociationPictureNotifier associationPictureNotifier = AssociationPictureNotifier(); tokenExpireWrapperAuth(ref, () async { - ref.watch(associationListProvider).when(data: (association) { + ref.watch(associationListProvider).maybeWhen(data: (association) { associationPictureNotifier.loadTList(association); for (final l in association) { associationPictureNotifier.setTData(l, const AsyncValue.data([])); } return associationPictureNotifier; - }, error: (error, stackTrace) { - associationPictureNotifier.loadTList([]); - return associationPictureNotifier; - }, loading: () { + }, orElse: (){ associationPictureNotifier.loadTList([]); return associationPictureNotifier; }); diff --git a/lib/phonebook/providers/reload_provider.dart b/lib/phonebook/providers/reload_provider.dart deleted file mode 100644 index 6594cb959..000000000 --- a/lib/phonebook/providers/reload_provider.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; - -final reloadProvider = StateNotifierProvider((ref) { - return ReloadProvider(); -}); - -class ReloadProvider extends StateNotifier { - ReloadProvider() : super(false); - - void setStatus(bool i) { - state = i; - } -} diff --git a/lib/phonebook/providers/roles_tags_provider.dart b/lib/phonebook/providers/roles_tags_provider.dart index ac297f10d..a95589a97 100644 --- a/lib/phonebook/providers/roles_tags_provider.dart +++ b/lib/phonebook/providers/roles_tags_provider.dart @@ -21,7 +21,7 @@ class RolesTagsNotifier extends SingleNotifier>> { } Future>>> loadRolesTags() async { - return await load(() async => rolesTagsRepository.getRolesTags()); + return await load(rolesTagsRepository.getRolesTags); } void resetChecked() { diff --git a/lib/phonebook/repositories/association_member_repository.dart b/lib/phonebook/repositories/association_member_repository.dart index 161a13b9e..9330f86c6 100644 --- a/lib/phonebook/repositories/association_member_repository.dart +++ b/lib/phonebook/repositories/association_member_repository.dart @@ -10,6 +10,6 @@ class AssociationMemberRepository extends Repository { String associationId, String year) async { return List.from( (await getList(suffix: "$associationId/members/$year")) - .map((x) => CompleteMember.fromJSON(x))); + .map((x) => CompleteMember.fromJson(x))); } } diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index aef1aeae2..67f175450 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -11,11 +11,11 @@ class AssociationRepository extends Repository { Future> getAssociationList() async { return List.from( - (await getList()).map((x) => Association.fromJSON(x))); + (await getList()).map((x) => Association.fromJson(x))); } Future getAssociation(String associationId) async { - return Association.fromJSON(await getOne(associationId)); + return Association.fromJson(await getOne(associationId)); } Future deleteAssociation(String associationId) async { @@ -23,11 +23,11 @@ class AssociationRepository extends Repository { } Future updateAssociation(Association association) async { - return await update(association.toJSON(), association.id); + return await update(association.toJson(), association.id); } Future createAssociation(Association association) async { - return Association.fromJSON(await create(association.toJSON())); + return Association.fromJson(await create(association.toJson())); } Future addMember(Association association, Member member, @@ -55,6 +55,6 @@ class AssociationRepository extends Repository { } Future getAssociationKinds() async { - return AssociationKinds.fromJSON(await getOne("kinds")); + return AssociationKinds.fromJson(await getOne("kinds")); } } diff --git a/lib/phonebook/repositories/member_repository.dart b/lib/phonebook/repositories/member_repository.dart index 97ceb30e5..0231a1412 100644 --- a/lib/phonebook/repositories/member_repository.dart +++ b/lib/phonebook/repositories/member_repository.dart @@ -10,18 +10,18 @@ class MemberRepository extends Repository { Future> getMemberMembershipList(int memberId) async { return List.from((await getList(suffix: "/$memberId/posts")) - .map((x) => Membership.fromJSON(x))); + .map((x) => Membership.fromJson(x))); } Future getMember(String memberId) async { - return Member.fromJSON(await getOne(memberId)); + return Member.fromJson(await getOne(memberId)); } Future getCompleteMember(String memberId) async { - return CompleteMember.fromJSON(await getOne(memberId, suffix: "complete")); + return CompleteMember.fromJson(await getOne(memberId, suffix: "complete")); } Future getMe() async { - return CompleteMember.fromJSON(await getOne("me", suffix: "complete")); + return CompleteMember.fromJson(await getOne("me", suffix: "complete")); } } diff --git a/lib/phonebook/repositories/role_tags_repository.dart b/lib/phonebook/repositories/role_tags_repository.dart index 7c2a8a5b9..c583c9d5c 100644 --- a/lib/phonebook/repositories/role_tags_repository.dart +++ b/lib/phonebook/repositories/role_tags_repository.dart @@ -9,7 +9,7 @@ class RolesTagsRepository extends Repository { final ext = "phonebook/"; Future>> getRolesTags() async { - RolesTags rolesTags = RolesTags.fromJSON(await getOne("roletags")); + RolesTags rolesTags = RolesTags.fromJson(await getOne("roletags")); debugPrint(rolesTags.toString()); return Tuple2(rolesTags, List.filled(rolesTags.tags.length, false)); } diff --git a/lib/phonebook/router.dart b/lib/phonebook/router.dart index 7d5e293aa..598c46f02 100644 --- a/lib/phonebook/router.dart +++ b/lib/phonebook/router.dart @@ -1,3 +1,4 @@ +import 'package:either_dart/either.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/drawer/class/module.dart'; @@ -24,7 +25,7 @@ class PhonebookRouter { static const String addEditMember = '/add_edit_member'; static final Module module = Module( name: "Annuaire", - icon: HeroIcons.phone, + icon: const Left(HeroIcons.phone), root: PhonebookRouter.root, selected: false); PhonebookRouter(this.ref); diff --git a/lib/phonebook/tools/function.dart b/lib/phonebook/tools/function.dart new file mode 100644 index 000000000..8b66d96a1 --- /dev/null +++ b/lib/phonebook/tools/function.dart @@ -0,0 +1,15 @@ +import 'package:myecl/phonebook/class/roles_tags.dart'; +import 'package:tuple/tuple.dart'; + +String nameConstructor(Tuple2> data) { + String name = ''; + for (int i = 0; i < data.item2.length; i++) { + if (data.item2[i]) { + name = "$name, ${data.item1.tags[i]}"; + } + } + if (name == "") { + return ""; + } + return name.substring(1, name.length); +} diff --git a/lib/phonebook/ui/pages/admin_page/editable_association_card.dart b/lib/phonebook/ui/pages/admin_page/editable_association_card.dart index 7fd57802c..31f1b1cde 100644 --- a/lib/phonebook/ui/pages/admin_page/editable_association_card.dart +++ b/lib/phonebook/ui/pages/admin_page/editable_association_card.dart @@ -121,13 +121,9 @@ class EditableAssociationCard extends HookConsumerWidget { fontSize: 20, fontWeight: FontWeight.bold)), const Spacer(), - EditionButton(onEdition: () async { - onEdit(); - }), + EditionButton(onEdition: onEdit), const SizedBox(width: 10), - DeleteButton(onDelete: () async { - await onDelete(); - }), + DeleteButton(onDelete: onDelete), ], ), ); diff --git a/lib/phonebook/ui/pages/admin_page/edition_button.dart b/lib/phonebook/ui/pages/admin_page/edition_button.dart index 176e91c11..287072146 100644 --- a/lib/phonebook/ui/pages/admin_page/edition_button.dart +++ b/lib/phonebook/ui/pages/admin_page/edition_button.dart @@ -4,7 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; class EditionButton extends HookConsumerWidget { const EditionButton({Key? key, required this.onEdition}) : super(key: key); - final Future Function() onEdition; + final void Function() onEdition; @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/lib/phonebook/ui/pages/association_creation_page/text_entry.dart b/lib/phonebook/ui/pages/association_creation_page/text_entry.dart index 55084fb6a..618bf9440 100644 --- a/lib/phonebook/ui/pages/association_creation_page/text_entry.dart +++ b/lib/phonebook/ui/pages/association_creation_page/text_entry.dart @@ -41,8 +41,6 @@ class AddAssociationTextEntry extends StatelessWidget { return AdminTextConstants.emptyFieldError; } else if (value.isEmpty) { return AdminTextConstants.emptyFieldError; - } else { - return null; } }, ), diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index a199af9ba..74509094b 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -138,8 +138,6 @@ class AssociationEditorPage extends HookConsumerWidget { } else if (value.isEmpty) { return PhonebookTextConstants .emptyFieldError; - } else { - return null; } }, ), @@ -183,8 +181,6 @@ class AssociationEditorPage extends HookConsumerWidget { } else if (value.isEmpty) { return PhonebookTextConstants .emptyFieldError; - } else { - return null; } }, ), diff --git a/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart b/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart deleted file mode 100644 index 81dcc47ee..000000000 --- a/lib/phonebook/ui/pages/association_editor_page/membership_dialog.dart +++ /dev/null @@ -1,159 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/class/complete_member.dart'; -import 'package:myecl/phonebook/class/roles_tags.dart'; -import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; -import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; -import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/tools/token_expire_wrapper.dart'; -import 'package:myecl/user/providers/user_list_provider.dart'; -import 'package:tuple/tuple.dart'; -import 'package:myecl/phonebook/ui/pages/membership_editor_page/search_result.dart'; - -class MembershipDialog extends HookConsumerWidget { - const MembershipDialog( - {Key? key, - required this.apparentNameController, - required this.title, - required this.defaultText, - required this.onConfirm, - required this.member, - required this.association}) - : super(key: key); - - final String title; - final String defaultText; - final VoidCallback onConfirm; - final TextEditingController apparentNameController; - final CompleteMember member; - final Association association; - - String nameConstructor(Tuple2> data) { - String name = ''; - for (int i = 0; i < data.item2.length; i++) { - if (data.item2[i]) { - name = "$name, ${data.item1.tags[i]}"; - } - } - if (name == "") { - return ""; - } - return name.substring(1, name.length); - } - - @override - Widget build(BuildContext context, WidgetRef ref) { - final rolesTags = ref.watch(rolesTagsProvider); - final apparentName = useState(defaultText); - final queryController = useTextEditingController(text: ''); - final usersNotifier = ref.watch(userList.notifier); - final memberRoleTagsNotifier = ref.watch(memberRoleTagsProvider.notifier); - final rolesTagsNotifier = ref.watch(rolesTagsProvider.notifier); - - apparentNameController.text = apparentName.value; - return AlertDialog( - title: Center( - child: Container( - decoration: const BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.black)), - color: Colors.white, - ), - child: Text(title, style: const TextStyle(fontSize: 20)))), - content: SizedBox( - height: 390, - child: SingleChildScrollView( - child: Column( - children: [ - if (member.member.id == "") - TextFormField( - enabled: member.member.id == "", - onChanged: (value) { - tokenExpireWrapper(ref, () async { - if (queryController.text.isNotEmpty) { - await usersNotifier.filterUsers(queryController.text); - } else { - usersNotifier.clear(); - } - }); - }, - cursorColor: Colors.black, - controller: queryController, - decoration: const InputDecoration( - labelText: PhonebookTextConstants.member, - floatingLabelStyle: TextStyle( - color: Colors.black, - fontWeight: FontWeight.bold, - ), - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide(color: Colors.black, width: 2.0), - ), - ), - ), - const SizedBox( - height: 10, - ), - SearchResult(queryController: queryController), - ...rolesTags.when( - data: (data) { - if (member.member.id != "") { - for (int i = 0; i < data.item2.length; i++) { - if (member.memberships - .where((e) => e.association.id == association.id) - .toList()[0] - .rolesTags - .contains(data.item1.tags[i])) { - data.item2[i] = true; - } - } - } - return data.item1.tags - .map((e) => Row(children: [ - Text(e), - const Spacer(), - Checkbox( - value: data.item2[data.item1.tags.indexOf(e)], - fillColor: MaterialStateProperty.all(Colors.black), - onChanged: (value) { - data.item2[data.item1.tags.indexOf(e)] = value!; - debugPrint(data.item2.toString()); - apparentName.value = nameConstructor(data); - apparentNameController.text = apparentName.value; - memberRoleTagsNotifier - .setRoleTagsWithFilter(data); - }, - ) - ])) - .toList(); - }, - error: (e, s) => [const Text('Error')], - loading: () => [const Text('Loading')], - ), - const SizedBox(height: 5), - const Text(PhonebookTextConstants.apparentName), - TextField( - controller: apparentNameController, - ) - ], - )), - ), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: const Text(PhonebookTextConstants.cancel), - ), - TextButton( - onPressed: () { - Navigator.of(context).pop(); - onConfirm(); - rolesTagsNotifier.resetChecked(); - }, - child: const Text(PhonebookTextConstants.validation), - ), - ], - ); - } -} diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index 4e1b54f5d..28ed02802 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -3,20 +3,19 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/class/roles_tags.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/edition_provider.dart'; import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/phonebook/tools/function.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:myecl/tools/ui/shrink_button.dart'; import 'package:myecl/user/providers/user_list_provider.dart'; import 'package:qlevar_router/qlevar_router.dart'; -import 'package:tuple/tuple.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/ui/pages/membership_editor_page/search_result.dart'; @@ -25,28 +24,6 @@ class MembershipEditorPage extends HookConsumerWidget { Key? key, }) : super(key: key); - String nameConstructor(Tuple2> data) { - String name = ''; - for (int i = 0; i < data.item2.length; i++) { - if (data.item2[i]) { - name = "$name, ${data.item1.tags[i]}"; - } - } - if (name == "") { - return ""; - } - return name.substring(1, name.length); - } - - List setRoleTagsWithFilter(Tuple2> data) { - List roleTags = []; - for (int i = 0; i < data.item2.length; i++) { - if (data.item2[i]) { - roleTags.add(data.item1.tags[i]); - } - } - return roleTags; - } @override Widget build(BuildContext context, WidgetRef ref) { From 59c3d4b0c1891f9a4516ec087f7320450a6e6f25 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:03 +0100 Subject: [PATCH 040/123] fix clean up issue and extends Member from SimpleUser --- lib/phonebook/class/member.dart | 44 ++++----------- .../providers/association_list_provider.dart | 3 +- .../providers/member_role_tags_provider.dart | 15 +++--- .../providers/roles_tags_provider.dart | 54 +++++++++++-------- .../repositories/role_tags_repository.dart | 4 +- lib/phonebook/tools/function.dart | 15 +++--- .../membership_editor_page.dart | 13 +++-- 7 files changed, 71 insertions(+), 77 deletions(-) diff --git a/lib/phonebook/class/member.dart b/lib/phonebook/class/member.dart index 2998a9c88..debd91349 100644 --- a/lib/phonebook/class/member.dart +++ b/lib/phonebook/class/member.dart @@ -1,40 +1,26 @@ import 'package:myecl/user/class/list_users.dart'; -class Member { +class Member extends SimpleUser { Member({ - required this.name, - required this.firstname, - required this.nickname, - required this.id, + required super.name, + required super.firstname, + required super.nickname, + required super.id, required this.email, required this.promotion, }); - - late final String name; - late final String firstname; - late final String? nickname; - late final String id; late final String email; late final String promotion; - Member.fromJson(Map json) { - name = json['name']; - firstname = json['firstname']; - nickname = json['nickname']; - id = json['id']; + Member.fromJson(Map json) : super.fromJson(json) { email = json['email']; promotion = json['promotion']; } Map toJson() { - final data = { - 'name': name, - 'firstname': firstname, - 'nickname': nickname, - 'id': id, - 'email': email, - 'promotion': promotion, - }; + final Map data = super.toJson(); + data['email'] = email; + data['promotion'] = promotion; return data; } @@ -56,16 +42,12 @@ class Member { ); } - Member.empty() { - name = "nom"; - firstname = "prénom"; - nickname = null; - id = ""; + Member.empty() : super.empty() { email = "email.test@empty.useless"; promotion = "Exx"; } - Member.fromUser(SimpleUser user) { + Member.fromUser(SimpleUser user) : super.empty() { name = user.name; firstname = user.firstname; nickname = user.nickname; @@ -78,8 +60,4 @@ class Member { String toString() { return 'Member(name: $name, firstname: $firstname, nickname: $nickname, id: $id, email: $email, promotion: $promotion)'; } - - String getName() { - return "$firstname $name ($nickname)"; - } } diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index eb665191e..5238a8fe8 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -16,7 +16,8 @@ class AssociationListNotifier extends ListNotifier { } Future>> loadAssociations() async { - return await loadList(associationRepository.getAssociationList); + associationList = await loadList(associationRepository.getAssociationList); + return associationList; } Future createAssociation(Association association) async { diff --git a/lib/phonebook/providers/member_role_tags_provider.dart b/lib/phonebook/providers/member_role_tags_provider.dart index e02fc8ddf..a9eeca965 100644 --- a/lib/phonebook/providers/member_role_tags_provider.dart +++ b/lib/phonebook/providers/member_role_tags_provider.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/phonebook/class/roles_tags.dart'; +import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:tuple/tuple.dart'; final memberRoleTagsProvider = @@ -11,13 +12,15 @@ final memberRoleTagsProvider = class MemberRoleTagsProvider extends StateNotifier> { MemberRoleTagsProvider() : super([]); - void setRoleTagsWithFilter(Tuple2> data) { + void setRoleTagsWithFilter(Map>> data) { List newRoleTags = []; - for (int i = 0; i < data.item2.length; i++) { - if (data.item2[i]) { - newRoleTags.add(data.item1.tags[i]); - } - } + data.forEach((key, value) { + value.maybeWhen(data: (d) { + if (d[0]) { + newRoleTags.add(key); + } + }, orElse: () {}); + }); state = newRoleTags; } } diff --git a/lib/phonebook/providers/roles_tags_provider.dart b/lib/phonebook/providers/roles_tags_provider.dart index a95589a97..2a1f7ebaf 100644 --- a/lib/phonebook/providers/roles_tags_provider.dart +++ b/lib/phonebook/providers/roles_tags_provider.dart @@ -5,49 +5,59 @@ import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/roles_tags.dart'; import 'package:myecl/phonebook/repositories/role_tags_repository.dart'; +import 'package:myecl/tools/providers/map_provider.dart'; import 'package:myecl/tools/providers/single_notifier.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:tuple/tuple.dart'; -class RolesTagsNotifier extends SingleNotifier>> { +class RolesTagsNotifier extends MapNotifier { final RolesTagsRepository rolesTagsRepository = RolesTagsRepository(); - RolesTagsNotifier({required String token}) - : super(const AsyncValue.loading()) { + RolesTagsNotifier({required String token}) { rolesTagsRepository.setToken(token); } - void setRole(RolesTags i) { - state = AsyncValue.data(Tuple2(i, state.value!.item2)); - } - Future>>> loadRolesTags() async { - return await load(rolesTagsRepository.getRolesTags); + + // void setRole(RolesTags i) { + // state = AsyncValue.data(Tuple2(i, state.value!.item2)); + // } + + Future loadRolesTags() async { + loadTList([]); + final result = await rolesTagsRepository.getRolesTags(); + for (int i = 0; i < result.tags.length; i++) { + setTData(result.tags[i], const AsyncData([false])); + } } void resetChecked() { - final checked = state.value!.item2; - state = AsyncValue.data( - Tuple2(state.value!.item1, List.filled(checked.length, false))); + state.maybeWhen(data: (d) { + for (int i = 0; i < d.length; i++) { + d[d.keys.toList()[i]] = const AsyncData([false]); + } + state = AsyncValue.data(d); + }, orElse: () {}); } - void setChecked(int index, bool value) { - List checked = state.value!.item2; - checked[index] = value; - state = AsyncValue.data(Tuple2(state.value!.item1, checked)); - } + // void setChecked(int index, bool value) { + // List checked = state.value!.item2; + // checked[index] = value; + // state = AsyncValue.data(Tuple2(state.value!.item1, checked)); + // } void loadRoleTagsFromMember(CompleteMember member, Association association) { - final checked = state.value!.item2; List roleTags = member.getRolesTags(association.id); - for (int i = 0; i < checked.length; i++) { - checked[i] = roleTags.contains(state.value!.item1.tags[i]); - } - state = AsyncValue.data(Tuple2(state.value!.item1, checked)); + state.maybeWhen(data: (d) { + for (int i = 0; i < roleTags.length; i++) { + d[roleTags[i]] = const AsyncData([true]); + } + state = AsyncValue.data(d); + }, orElse: () {}); } } final rolesTagsProvider = StateNotifierProvider>>>((ref) { + AsyncValue>>>>((ref) { final token = ref.watch(tokenProvider); RolesTagsNotifier notifier = RolesTagsNotifier(token: token); tokenExpireWrapperAuth(ref, () async { diff --git a/lib/phonebook/repositories/role_tags_repository.dart b/lib/phonebook/repositories/role_tags_repository.dart index c583c9d5c..c6f3b8c1b 100644 --- a/lib/phonebook/repositories/role_tags_repository.dart +++ b/lib/phonebook/repositories/role_tags_repository.dart @@ -8,9 +8,9 @@ class RolesTagsRepository extends Repository { // ignore: overridden_fields final ext = "phonebook/"; - Future>> getRolesTags() async { + Future getRolesTags() async { RolesTags rolesTags = RolesTags.fromJson(await getOne("roletags")); debugPrint(rolesTags.toString()); - return Tuple2(rolesTags, List.filled(rolesTags.tags.length, false)); + return rolesTags; } } diff --git a/lib/phonebook/tools/function.dart b/lib/phonebook/tools/function.dart index 8b66d96a1..23e584dcf 100644 --- a/lib/phonebook/tools/function.dart +++ b/lib/phonebook/tools/function.dart @@ -1,13 +1,16 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/roles_tags.dart'; import 'package:tuple/tuple.dart'; -String nameConstructor(Tuple2> data) { +String nameConstructor(Map>> data) { String name = ''; - for (int i = 0; i < data.item2.length; i++) { - if (data.item2[i]) { - name = "$name, ${data.item1.tags[i]}"; - } - } + data.forEach((key, value) { + value.maybeWhen(data: (d) { + if (d[0]) { + name += "$key,"; + } + }, orElse: () {}); + }); if (name == "") { return ""; } diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index 28ed02802..c8a203e37 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -103,24 +103,23 @@ class MembershipEditorPage extends HookConsumerWidget { child: Column(children: [ ...rolesTags.when( data: (data) { - return data.item1.tags + return data.keys .map((e) => Row(children: [ Text(e), const Spacer(), Checkbox( - value: data.item2[data.item1.tags.indexOf(e)], + value: data[e]!.maybeWhen( + data: (d) => d[0], + orElse:() => false,), fillColor: MaterialStateProperty.all(Colors.black), onChanged: (value) { - data.item2[data.item1.tags.indexOf(e)] = - value!; - debugPrint(data.item2.toString()); + data[e] = AsyncData([value!]); apparentNameController.text = nameConstructor(data); memberRoleTagsNotifier .setRoleTagsWithFilter(data); - rolesTagsNotifier.setChecked( - data.item1.tags.indexOf(e), value); + rolesTagsNotifier.setTData(e, AsyncData([value])); }, ), ])) From e62d79912b6f98c00dc4892957aa3422f122346a Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:03 +0100 Subject: [PATCH 041/123] clean up --- .../providers/member_role_tags_provider.dart | 3 --- lib/phonebook/providers/roles_tags_provider.dart | 3 --- .../repositories/role_tags_repository.dart | 1 - lib/phonebook/tools/function.dart | 4 +--- .../association_creation_page/text_entry.dart | 5 ++--- .../association_editor_page.dart | 14 +++++--------- 6 files changed, 8 insertions(+), 22 deletions(-) diff --git a/lib/phonebook/providers/member_role_tags_provider.dart b/lib/phonebook/providers/member_role_tags_provider.dart index a9eeca965..27e41dad4 100644 --- a/lib/phonebook/providers/member_role_tags_provider.dart +++ b/lib/phonebook/providers/member_role_tags_provider.dart @@ -1,8 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:myecl/phonebook/class/roles_tags.dart'; -import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; -import 'package:tuple/tuple.dart'; final memberRoleTagsProvider = StateNotifierProvider>((ref) { diff --git a/lib/phonebook/providers/roles_tags_provider.dart b/lib/phonebook/providers/roles_tags_provider.dart index 2a1f7ebaf..a9d533bec 100644 --- a/lib/phonebook/providers/roles_tags_provider.dart +++ b/lib/phonebook/providers/roles_tags_provider.dart @@ -3,12 +3,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; -import 'package:myecl/phonebook/class/roles_tags.dart'; import 'package:myecl/phonebook/repositories/role_tags_repository.dart'; import 'package:myecl/tools/providers/map_provider.dart'; -import 'package:myecl/tools/providers/single_notifier.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; -import 'package:tuple/tuple.dart'; class RolesTagsNotifier extends MapNotifier { final RolesTagsRepository rolesTagsRepository = RolesTagsRepository(); diff --git a/lib/phonebook/repositories/role_tags_repository.dart b/lib/phonebook/repositories/role_tags_repository.dart index c6f3b8c1b..dd2710830 100644 --- a/lib/phonebook/repositories/role_tags_repository.dart +++ b/lib/phonebook/repositories/role_tags_repository.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:myecl/phonebook/class/roles_tags.dart'; import 'package:myecl/tools/repository/repository.dart'; -import 'package:tuple/tuple.dart'; class RolesTagsRepository extends Repository { @override diff --git a/lib/phonebook/tools/function.dart b/lib/phonebook/tools/function.dart index 23e584dcf..e1bc9b6c1 100644 --- a/lib/phonebook/tools/function.dart +++ b/lib/phonebook/tools/function.dart @@ -1,6 +1,4 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/class/roles_tags.dart'; -import 'package:tuple/tuple.dart'; String nameConstructor(Map>> data) { String name = ''; @@ -11,7 +9,7 @@ String nameConstructor(Map>> data) { } }, orElse: () {}); }); - if (name == "") { + if (name.isEmpty) { return ""; } return name.substring(1, name.length); diff --git a/lib/phonebook/ui/pages/association_creation_page/text_entry.dart b/lib/phonebook/ui/pages/association_creation_page/text_entry.dart index 618bf9440..0f37ac0fa 100644 --- a/lib/phonebook/ui/pages/association_creation_page/text_entry.dart +++ b/lib/phonebook/ui/pages/association_creation_page/text_entry.dart @@ -37,11 +37,10 @@ class AddAssociationTextEntry extends StatelessWidget { borderSide: BorderSide(color: ColorConstants.gradient1))), validator: (value) { - if (value == null) { - return AdminTextConstants.emptyFieldError; - } else if (value.isEmpty) { + if (value == null || value.isEmpty) { return AdminTextConstants.emptyFieldError; } + return null; }, ), ), diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 74509094b..72d7be369 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -132,13 +132,11 @@ class AssociationEditorPage extends HookConsumerWidget { borderSide: BorderSide( color: ColorConstants.gradient1))), validator: (value) { - if (value == null) { + if (value == null || value.isEmpty) { return PhonebookTextConstants .emptyFieldError; - } else if (value.isEmpty) { - return PhonebookTextConstants - .emptyFieldError; - } + } + return null; }, ), ), @@ -175,13 +173,11 @@ class AssociationEditorPage extends HookConsumerWidget { borderSide: BorderSide( color: ColorConstants.gradient1))), validator: (value) { - if (value == null) { - return PhonebookTextConstants - .emptyFieldError; - } else if (value.isEmpty) { + if (value == null || value.isEmpty) { return PhonebookTextConstants .emptyFieldError; } + return null; }, ), ), From 3a4162189d91e302921af6fca8375507eb008c58 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:03 +0100 Subject: [PATCH 042/123] change admin condition to include CAA's members --- lib/phonebook/providers/phonebook_admin_provider.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/phonebook/providers/phonebook_admin_provider.dart b/lib/phonebook/providers/phonebook_admin_provider.dart index 0654de552..2001a9d99 100644 --- a/lib/phonebook/providers/phonebook_admin_provider.dart +++ b/lib/phonebook/providers/phonebook_admin_provider.dart @@ -7,7 +7,7 @@ import 'package:myecl/user/providers/user_provider.dart'; final isPhonebookAdminProvider = StateProvider((ref) { final user = ref.watch(userProvider); - if (user.groups.map((e) => e.id).contains("53a669d6-84b1-4352-8d7c-421c1fbd9c6a")) { + if (user.groups.map((e) => e.id).contains("53a669d6-84b1-4352-8d7c-421c1fbd9c6a") || user.groups.map((e) => e.id).contains("6c6d7e88-fdb8-4e42-b2b5-3d3cfd12e7d6")) { return true; } return false; From 20d862aadb20ee44effaeb8ba0a614dffdf263ae Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:03 +0100 Subject: [PATCH 043/123] Fix member name, update member detail, sort text constant --- lib/phonebook/class/association.dart | 22 +- lib/phonebook/class/complete_member.dart | 12 +- lib/phonebook/class/member.dart | 9 +- lib/phonebook/class/membership.dart | 8 +- .../providers/association_list_provider.dart | 6 +- .../association_member_list_provider.dart | 9 +- .../association_picture_provider.dart | 6 +- .../associations_pictures_provider.dart | 2 +- .../providers/member_role_tags_provider.dart | 12 +- .../providers/phonebook_admin_provider.dart | 22 +- .../providers/roles_tags_provider.dart | 34 +- lib/phonebook/router.dart | 40 +- lib/phonebook/tools/constants.dart | 136 ++-- lib/phonebook/tools/function.dart | 12 +- .../association_editor_page.dart | 710 +++++++++--------- .../member_editable_card.dart | 15 +- .../association_page/association_page.dart | 98 ++- .../pages/association_page/member_card.dart | 2 +- .../ui/pages/main_page/association_card.dart | 11 +- .../ui/pages/main_page/main_page.dart | 209 +++--- .../ui/pages/main_page/research_bar.dart | 46 +- .../member_detail_page.dart | 60 +- .../membership_editor_page.dart | 273 +++---- lib/phonebook/ui/phonebook.dart | 28 +- 24 files changed, 911 insertions(+), 871 deletions(-) diff --git a/lib/phonebook/class/association.dart b/lib/phonebook/class/association.dart index 7a9f17f0c..f81beb3e4 100644 --- a/lib/phonebook/class/association.dart +++ b/lib/phonebook/class/association.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -class Association{ +class Association { Association({ required this.id, required this.name, @@ -15,13 +15,13 @@ class Association{ late final String kind; late final int mandateYear; - Association.fromJson(Map json){ - id = json['id']; - name = json['name']; - description = json['description']; - kind = json['kind']; - mandateYear = json['mandate_year']; - } + Association.fromJson(Map json) { + id = json['id']; + name = json['name']; + description = json['description']; + kind = json['kind']; + mandateYear = json['mandate_year']; + } Map toJson() { final data = { @@ -58,12 +58,12 @@ class Association{ mandateYear = 0; } - void newMandate(){ - mandateYear = mandateYear + 1; + void newMandate() { + mandateYear = mandateYear + 1; } @override String toString() { - return "Nom : $name, id : $id, description : $description, kind : $kind, mandate_year : $mandateYear"; + return "Association(Nom : $name, id : $id, description : $description, kind : $kind, mandate_year : $mandateYear)"; } } diff --git a/lib/phonebook/class/complete_member.dart b/lib/phonebook/class/complete_member.dart index 34ceb9ba0..27cfff802 100644 --- a/lib/phonebook/class/complete_member.dart +++ b/lib/phonebook/class/complete_member.dart @@ -19,10 +19,9 @@ class CompleteMember { nickname: json['nickname'], id: json['id'], email: json['email'], - promotion: json['promotion']??""); + promotion: json['promotion'] ?? ""); memberships = List.from(json['memberships'] .map((membership) => Membership.fromJson(membership))); - } Map toJson() { @@ -49,14 +48,7 @@ class CompleteMember { } Member toMember() { - return Member( - name: member.name, - firstname: member.firstname, - nickname: member.nickname, - id: member.id, - email: member.email, - promotion: member.promotion, - ); + return member; } @override diff --git a/lib/phonebook/class/member.dart b/lib/phonebook/class/member.dart index debd91349..637085513 100644 --- a/lib/phonebook/class/member.dart +++ b/lib/phonebook/class/member.dart @@ -10,13 +10,14 @@ class Member extends SimpleUser { required this.promotion, }); late final String email; - late final String promotion; + late final int promotion; Member.fromJson(Map json) : super.fromJson(json) { email = json['email']; promotion = json['promotion']; } + @override Map toJson() { final Map data = super.toJson(); data['email'] = email; @@ -30,7 +31,7 @@ class Member extends SimpleUser { String? nickname, String? id, String? email, - String? promotion, + int? promotion, }) { return Member( name: name ?? this.name, @@ -44,7 +45,7 @@ class Member extends SimpleUser { Member.empty() : super.empty() { email = "email.test@empty.useless"; - promotion = "Exx"; + promotion = 0; } Member.fromUser(SimpleUser user) : super.empty() { @@ -53,7 +54,7 @@ class Member extends SimpleUser { nickname = user.nickname; id = user.id; email = ""; - promotion = "Exx"; + promotion = 0; } @override diff --git a/lib/phonebook/class/membership.dart b/lib/phonebook/class/membership.dart index cdf1c6295..d082fad2f 100644 --- a/lib/phonebook/class/membership.dart +++ b/lib/phonebook/class/membership.dart @@ -14,14 +14,14 @@ class Membership { late final List rolesTags; late final String apparentName; - Membership.fromJson(Map json){ + Membership.fromJson(Map json) { id = json['id']; association = Association.fromJson(json['association']); rolesTags = json['role_tags'].split(";"); apparentName = json['role_name']; - } - - Map toJson(){ + } + + Map toJson() { final data = { 'id': id, 'association': association.id, diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index 5238a8fe8..5743d4a1b 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -9,9 +9,8 @@ import 'package:myecl/tools/token_expire_wrapper.dart'; class AssociationListNotifier extends ListNotifier { final AssociationRepository associationRepository = AssociationRepository(); AsyncValue> associationList = const AsyncValue.loading(); - AssociationListNotifier({ - required String token, - }) : super(const AsyncValue.loading()) { + AssociationListNotifier({required String token}) + : super(const AsyncValue.loading()) { associationRepository.setToken(token); } @@ -94,4 +93,3 @@ final associationListProvider = StateNotifierProvider { associationMemberRepository.setToken(token); } - Future>> loadMembers(String associationId, String year) async { - return await loadList(() async => associationMemberRepository.getAssociationMemberList(associationId, year)); + Future>> loadMembers( + String associationId, String year) async { + return await loadList(() async => associationMemberRepository + .getAssociationMemberList(associationId, year)); } } @@ -27,7 +29,8 @@ final associationMemberListProvider = StateNotifierProvider< AssociationMemberListNotifier(token: token); tokenExpireWrapperAuth(ref, () async { final association = ref.watch(associationProvider); - await provider.loadMembers(association.id, association.mandateYear.toString()); + await provider.loadMembers( + association.id, association.mandateYear.toString()); }); return provider; }); diff --git a/lib/phonebook/providers/association_picture_provider.dart b/lib/phonebook/providers/association_picture_provider.dart index d551b25a2..020a8d918 100644 --- a/lib/phonebook/providers/association_picture_provider.dart +++ b/lib/phonebook/providers/association_picture_provider.dart @@ -9,14 +9,16 @@ import 'package:myecl/tools/providers/single_notifier.dart'; final associationPictureProvider = StateNotifierProvider>((ref) { final token = ref.watch(tokenProvider); - AssociationPictureNotifier notifier = AssociationPictureNotifier(token); + AssociationPictureNotifier notifier = + AssociationPictureNotifier(token: token); return notifier; }); class AssociationPictureNotifier extends SingleNotifier { final AssociationPictureRepository associationPictureRepository = AssociationPictureRepository(); - AssociationPictureNotifier(String token) : super(const AsyncLoading()) { + AssociationPictureNotifier({required String token}) + : super(const AsyncLoading()) { associationPictureRepository.setToken(token); } diff --git a/lib/phonebook/providers/associations_pictures_provider.dart b/lib/phonebook/providers/associations_pictures_provider.dart index d697a815c..0203af4a5 100644 --- a/lib/phonebook/providers/associations_pictures_provider.dart +++ b/lib/phonebook/providers/associations_pictures_provider.dart @@ -21,7 +21,7 @@ final associationPicturesProvider = StateNotifierProvider< associationPictureNotifier.setTData(l, const AsyncValue.data([])); } return associationPictureNotifier; - }, orElse: (){ + }, orElse: () { associationPictureNotifier.loadTList([]); return associationPictureNotifier; }); diff --git a/lib/phonebook/providers/member_role_tags_provider.dart b/lib/phonebook/providers/member_role_tags_provider.dart index 27e41dad4..10b97a90e 100644 --- a/lib/phonebook/providers/member_role_tags_provider.dart +++ b/lib/phonebook/providers/member_role_tags_provider.dart @@ -12,11 +12,13 @@ class MemberRoleTagsProvider extends StateNotifier> { void setRoleTagsWithFilter(Map>> data) { List newRoleTags = []; data.forEach((key, value) { - value.maybeWhen(data: (d) { - if (d[0]) { - newRoleTags.add(key); - } - }, orElse: () {}); + value.whenData( + (d) { + if (d[0]) { + newRoleTags.add(key); + } + }, + ); }); state = newRoleTags; } diff --git a/lib/phonebook/providers/phonebook_admin_provider.dart b/lib/phonebook/providers/phonebook_admin_provider.dart index 2001a9d99..868249c23 100644 --- a/lib/phonebook/providers/phonebook_admin_provider.dart +++ b/lib/phonebook/providers/phonebook_admin_provider.dart @@ -7,7 +7,12 @@ import 'package:myecl/user/providers/user_provider.dart'; final isPhonebookAdminProvider = StateProvider((ref) { final user = ref.watch(userProvider); - if (user.groups.map((e) => e.id).contains("53a669d6-84b1-4352-8d7c-421c1fbd9c6a") || user.groups.map((e) => e.id).contains("6c6d7e88-fdb8-4e42-b2b5-3d3cfd12e7d6")) { + if (user.groups + .map((e) => e.id) + .contains("53a669d6-84b1-4352-8d7c-421c1fbd9c6a") || + user.groups + .map((e) => e.id) + .contains("6c6d7e88-fdb8-4e42-b2b5-3d3cfd12e7d6")) { return true; } return false; @@ -20,14 +25,17 @@ final isAssociationPresidentProvider = StateProvider((ref) { bool isPresident = false; membersList.whenData((members) { if (members.map((e) => e.member.id).contains(me.id)) { - if (members.firstWhere((completeMember) => completeMember.member.id == me.id) - .memberships.firstWhere((membership) => membership.association.id == association.id) - .rolesTags.contains(PhonebookTextConstants.presidentRoleTag)) { - isPresident = true; - } + if (members + .firstWhere((completeMember) => completeMember.member.id == me.id) + .memberships + .firstWhere( + (membership) => membership.association.id == association.id) + .rolesTags + .contains(PhonebookTextConstants.presidentRoleTag)) { + isPresident = true; + } } }); debugPrint("isPresident: $isPresident"); return isPresident; }); - diff --git a/lib/phonebook/providers/roles_tags_provider.dart b/lib/phonebook/providers/roles_tags_provider.dart index a9d533bec..c7a2ec22f 100644 --- a/lib/phonebook/providers/roles_tags_provider.dart +++ b/lib/phonebook/providers/roles_tags_provider.dart @@ -13,48 +13,38 @@ class RolesTagsNotifier extends MapNotifier { rolesTagsRepository.setToken(token); } - - - // void setRole(RolesTags i) { - // state = AsyncValue.data(Tuple2(i, state.value!.item2)); - // } - Future loadRolesTags() async { loadTList([]); final result = await rolesTagsRepository.getRolesTags(); for (int i = 0; i < result.tags.length; i++) { - setTData(result.tags[i], const AsyncData([false])); + setTData(result.tags[i], const AsyncData([false])); } } void resetChecked() { - state.maybeWhen(data: (d) { + state.whenData((d) { for (int i = 0; i < d.length; i++) { d[d.keys.toList()[i]] = const AsyncData([false]); } state = AsyncValue.data(d); - }, orElse: () {}); + }); } - // void setChecked(int index, bool value) { - // List checked = state.value!.item2; - // checked[index] = value; - // state = AsyncValue.data(Tuple2(state.value!.item1, checked)); - // } - void loadRoleTagsFromMember(CompleteMember member, Association association) { List roleTags = member.getRolesTags(association.id); - state.maybeWhen(data: (d) { - for (int i = 0; i < roleTags.length; i++) { - d[roleTags[i]] = const AsyncData([true]); - } - state = AsyncValue.data(d); - }, orElse: () {}); + state.maybeWhen( + data: (d) { + for (int i = 0; i < roleTags.length; i++) { + d[roleTags[i]] = const AsyncData([true]); + } + state = AsyncValue.data(d); + }, + orElse: () {}); } } final rolesTagsProvider = StateNotifierProvider>>>>((ref) { + AsyncValue>>>>((ref) { final token = ref.watch(tokenProvider); RolesTagsNotifier notifier = RolesTagsNotifier(token: token); tokenExpireWrapperAuth(ref, () async { diff --git a/lib/phonebook/router.dart b/lib/phonebook/router.dart index 598c46f02..7b14fec1c 100644 --- a/lib/phonebook/router.dart +++ b/lib/phonebook/router.dart @@ -38,24 +38,36 @@ class PhonebookRouter { QRoute(path: admin, builder: () => const AdminPage(), middleware: [ AdminMiddleware(ref, isPhonebookAdminProvider), ], children: [ - QRoute(path: editAssociation, builder: () => const AssociationEditorPage(), + QRoute( + path: editAssociation, + builder: () => const AssociationEditorPage(), children: [ - QRoute(path: addEditMember, builder: () => const MembershipEditorPage()), + QRoute( + path: addEditMember, + builder: () => const MembershipEditorPage()), ], ), - QRoute(path: createAssociaiton, builder: () => const AssociationCreationPage()), + QRoute( + path: createAssociaiton, + builder: () => const AssociationCreationPage()), ]), - QRoute(path: associationDetail, builder: () => const AssociationPage(), - children: [ - QRoute(path: editAssociation, builder: () => const AssociationEditorPage(), - middleware: [ - AdminMiddleware(ref, isAssociationPresidentProvider), - ], - children: [ - QRoute(path: addEditMember, builder: () => const MembershipEditorPage()), - ]) - ]), + QRoute( + path: associationDetail, + builder: () => const AssociationPage(), + children: [ + QRoute( + path: editAssociation, + builder: () => const AssociationEditorPage(), + middleware: [ + AdminMiddleware(ref, isAssociationPresidentProvider), + ], + children: [ + QRoute( + path: addEditMember, + builder: () => const MembershipEditorPage()), + ]) + ]), QRoute(path: memberDetail, builder: () => const MemberDetailPage()), ], ); -} \ No newline at end of file +} diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index 3432615a4..b87b29903 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -1,92 +1,100 @@ import 'package:flutter/material.dart'; class PhonebookTextConstants { - static const String errorAssociationPicture = - "Erreur lors de la modification de la photo d'association"; - static const String phonebook = "Annuaire"; - static const String phonebookSearch = "Rechercher"; - static const String phonebookSearchName = "Nom/Prénom/Surnom"; - static const String phonebookSearchRole = "Poste"; - static const String phonebookSearchAssociation = "Association"; - static const String phonebookSearchField = "Rechercher :"; - static const String updatedAssociationPicture = - "La photo d'association a été changée"; - static const String tooHeavyAssociationPicture = - "L'image est trop lourde (max 4Mo)"; - static const String membershipRole = "Rôle :"; - static const String membershipAssociationError = - "Veuillez choisir une association"; - static const String membershipRoleError = "Veuillez choisir un rôle"; - static const String validation = "Valider"; - static const String cancel = "Annuler"; + static const String activeMandate = "Mandat actif :"; + static const String add = "Ajouter"; + static const String addAssociation = "Ajouter une association"; + static const String addedAssociation = "Association ajoutée"; + static const String addedMember = "Membre ajouté"; + static const String addingError = "Erreur lors de l'ajout"; + static const String addMember = "Ajouter un membre"; + static const String addRole = "Ajouter un rôle"; + static const String admin = "Admin"; + static const String adminPage = "Page Administrateur"; + static const String all = "Toutes"; + static const String apparentName = "Nom public du rôle:"; static const String association = "Association :"; + static const String associationDetail = "Détail de l'association :"; + static const String associationKind = "Type d'association :"; static const String associationPure = "Association"; - static const String rolePure = "Rôle"; static const String associationPureSearch = " Association"; - static const String name = "Nom :"; - static const String firstname = "Prénom :"; - static const String nickname = "Surnom :"; - static const String email = "Email :"; + static const String associations = "Associations :"; + + static const String cancel = "Annuler"; + static const String changeMandate = "Passer au mandat "; + static const String changeMandateConfirm = + "Êtes-vous sûr de vouloir changer tout le mandat ?\nCette action est irréversible !"; + static const String detail = "Détail :"; - static const String addRole = "Ajouter un rôle"; - static const String adminPage = "Page Administrateur"; - static const String admin = "Admin"; - static const String addAssociation = "Ajouter une association"; - static const String errorLoadAssociationPicture = - "Erreur lors du chargement de la photo d'association"; - static const String deleting = "Suppression"; static const String deleteAssociation = "Supprimer l'association ?"; static const String deletedAssociation = "Association supprimée"; + static const String deletedMember = "Membre supprimé"; + static const String deleting = "Suppression"; static const String deletingError = "Erreur lors de la suppression"; - static const String errorLoadAssociationList = - "Erreur lors du chargement de la liste des associations"; - static const String associationDetail = "Détail de l'association :"; - static const String errorLoadAssociationMember = - "Erreur lors du chargement des membres de l'association"; - static const String updatingError = "Erreur lors de la modification"; - static const String errorLoadProfilePicture = "Erreur"; - static const String updatedAssociation = "Association modifiée"; + + static const String edit = "Modifier"; + static const String editMembership = "Modifier le rôle"; + static const String email = "Email :"; + static const String emptyApparentName = "Veuillez entrer un nom de role"; + static const String emptyFieldError = "Un champ n'est pas rempli"; + static const String emptyKindError = "Veuillez choisir un type d'association"; + static const String emptyMember = "Aucun membre sélectionné"; static const String errorAssociationLoading = "Erreur lors du chargement de l'association"; static const String errorAssociationNameEmpty = "Veuillez entrer un nom d'association"; - static const String addedAssociation = "Association ajoutée"; - static const String deletedMember = "Membre supprimé"; - static const String associationKind = "Type d'association :"; + static const String errorAssociationPicture = + "Erreur lors de la modification de la photo d'association"; static const String errorKindsLoading = "Erreur lors du chargement des types d'association"; - static const String emptyFieldError = "Un champ n'est pas rempli"; - static const String emptyKindError = "Veuillez choisir un type d'association"; - static const String edit = "Modifier"; - static const String members = "Membres"; - static const String member = "Membre"; - static const String apparentName = "Nom public du rôle:"; - static const String editMembership = "Modifier le rôle"; - static const String addedMember = "Membre ajouté"; - static const String addingError = "Erreur lors de l'ajout"; - static const String addMember = "Ajouter un membre"; - static const String updatedMember = "Membre modifié"; - static const String add = "Ajouter"; - static const String emptyMember = "Aucun membre sélectionné"; - static const String emptyApparentName = "Veuillez entrer un nom de role"; + static const String errorLoadAssociationList = + "Erreur lors du chargement de la liste des associations"; + static const String errorLoadAssociationMember = + "Erreur lors du chargement des membres de l'association"; + static const String errorLoadAssociationPicture = + "Erreur lors du chargement de la photo d'association"; + static const String errorLoadProfilePicture = "Erreur"; static const String errorRoleTagsLoading = "Erreur lors du chargement des tags de rôle"; - static const String promotion = "Promotion :"; - static const String newMandateConfirmed = "Mandat changé"; + + static const String firstname = "Prénom :"; + static const String mandateChangingError = "Erreur lors du changement de mandat"; - static const String changeMandateConfirm = - "Êtes-vous sûr de vouloir changer tout le mandat ?\nCette action est irréversible !"; - static const String newMandate = "Nouveau mandat"; - static const String changeMandate = "Passer au mandat "; + static const String member = "Membre"; + static const String members = "Membres"; + static const String membershipAssociationError = + "Veuillez choisir une association"; + static const String membershipRole = "Rôle :"; + static const String membershipRoleError = "Veuillez choisir un rôle"; - static const String activeMandate = "Mandat actif :"; + static const String name = "Nom :"; + static const String newMandate = "Nouveau mandat"; + static const String newMandateConfirmed = "Mandat changé"; + static const String nickname = "Surnom :"; - static const String all = "Toutes"; + static const String phonebook = "Annuaire"; + static const String phonebookSearch = "Rechercher"; + static const String phonebookSearchAssociation = "Association"; + static const String phonebookSearchField = "Rechercher :"; + static const String phonebookSearchName = "Nom/Prénom/Surnom"; + static const String phonebookSearchRole = "Poste"; + static const String presidentRoleTag = "Prez'"; + static const String promotion = "Promotion :"; static const String research = "Rechercher"; + static const String rolePure = "Rôle"; - static const String presidentRoleTag = "Prez'"; + static const String tooHeavyAssociationPicture = + "L'image est trop lourde (max 4Mo)"; + + static const String updatedAssociation = "Association modifiée"; + static const String updatedAssociationPicture = + "La photo d'association a été changée"; + static const String updatingError = "Erreur lors de la modification"; + static const String updatedMember = "Membre modifié"; + + static const String validation = "Valider"; } class PhonebookColorConstants { diff --git a/lib/phonebook/tools/function.dart b/lib/phonebook/tools/function.dart index e1bc9b6c1..ca2fb7f7f 100644 --- a/lib/phonebook/tools/function.dart +++ b/lib/phonebook/tools/function.dart @@ -3,11 +3,13 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; String nameConstructor(Map>> data) { String name = ''; data.forEach((key, value) { - value.maybeWhen(data: (d) { - if (d[0]) { - name += "$key,"; - } - }, orElse: () {}); + value.maybeWhen( + data: (d) { + if (d[0]) { + name += "$key,"; + } + }, + orElse: () {}); }); if (name.isEmpty) { return ""; diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 72d7be369..69c9c7f07 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -49,386 +49,390 @@ class AssociationEditorPage extends HookConsumerWidget { } return PhonebookTemplate( - child: - Refresher( - onRefresh: () async { - await associationMemberListNotifier.loadMembers(association.id, association.mandateYear.toString()); - await associationPictureNotifier.getAssociationPicture(association.id); - }, + child: Refresher( + onRefresh: () async { + await associationMemberListNotifier.loadMembers( + association.id, association.mandateYear.toString()); + await associationPictureNotifier.getAssociationPicture(association.id); + }, + child: Column(children: [ + const SizedBox( + height: 20, + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 30), + alignment: Alignment.centerLeft, + child: const Text(PhonebookTextConstants.edit, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w700, + color: ColorConstants.gradient1)), + ), + const SizedBox( + height: 20, + ), + Form( + key: key, child: Column(children: [ - const SizedBox( - height: 20, + associationKinds.when( + data: (value) { + return SingleChildScrollView( + physics: const BouncingScrollPhysics(), + scrollDirection: Axis.horizontal, + child: Row( + children: value.kinds + .map((e) => RadioChip( + label: e, + selected: e == kind.value, + onTap: () async { + kind.value = e; + }, + )) + .toList())); + }, + error: (error, stack) { + return const Text(PhonebookTextConstants.errorKindsLoading); + }, + loading: () { + return const CircularProgressIndicator(); + }, ), - Container( + Padding( padding: const EdgeInsets.symmetric(horizontal: 30), - alignment: Alignment.centerLeft, - child: const Text(PhonebookTextConstants.edit, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.w700, - color: ColorConstants.gradient1)), - ), - const SizedBox( - height: 20, - ), - Form( - key: key, - child: Column(children: [ - associationKinds.when( - data: (value) { - return SingleChildScrollView( - physics: const BouncingScrollPhysics(), - scrollDirection: Axis.horizontal, - child: Row( - children: value.kinds - .map((e) => RadioChip( - label: e, - selected: e == kind.value, - onTap: () async { - kind.value = e; - }, - )) - .toList())); - }, - error: (error, stack) { - return const Text(PhonebookTextConstants.errorKindsLoading); - }, - loading: () { - return const CircularProgressIndicator(); - }, - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), - child: Column( - children: [ - Container( - margin: const EdgeInsets.symmetric(vertical: 10), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - child: TextFormField( - controller: name, - cursorColor: ColorConstants.gradient1, - decoration: InputDecoration( - labelText: "Name", - labelStyle: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - suffixIcon: Container( - padding: const EdgeInsets.all(10), - child: const HeroIcon( - HeroIcons.pencil, - ), - ), - enabledBorder: const UnderlineInputBorder( - borderSide: BorderSide( - color: Colors.transparent, - ), - ), - focusedBorder: const UnderlineInputBorder( - borderSide: BorderSide( - color: ColorConstants.gradient1))), - validator: (value) { - if (value == null || value.isEmpty) { - return PhonebookTextConstants - .emptyFieldError; - } - return null; - }, + child: Column( + children: [ + Container( + margin: const EdgeInsets.symmetric(vertical: 10), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + child: TextFormField( + controller: name, + cursorColor: ColorConstants.gradient1, + decoration: InputDecoration( + labelText: "Name", + labelStyle: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, ), - ), - ], - )), - Container( - margin: const EdgeInsets.symmetric(vertical: 10), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - child: TextFormField( - controller: description, - cursorColor: ColorConstants.gradient1, - decoration: InputDecoration( - labelText: "Description", - labelStyle: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - suffixIcon: Container( - padding: const EdgeInsets.all(10), - child: const HeroIcon( - HeroIcons.pencil, - ), - ), - enabledBorder: const UnderlineInputBorder( - borderSide: BorderSide( - color: Colors.transparent, - ), - ), - focusedBorder: const UnderlineInputBorder( - borderSide: BorderSide( - color: ColorConstants.gradient1))), - validator: (value) { - if (value == null || value.isEmpty) { - return PhonebookTextConstants - .emptyFieldError; - } - return null; - }, + suffixIcon: Container( + padding: const EdgeInsets.all(10), + child: const HeroIcon( + HeroIcons.pencil, + ), ), - ), - ], - )), - ShrinkButton( - waitChild: Container( - width: double.infinity, - margin: const EdgeInsets.symmetric(vertical: 20), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, - ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: const SizedBox( - height: 20, - width: 20, - child: CircularProgressIndicator( - color: Colors.white, - ), + enabledBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: Colors.transparent, + ), + ), + focusedBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: ColorConstants.gradient1))), + validator: (value) { + if (value == null || value.isEmpty) { + return PhonebookTextConstants + .emptyFieldError; + } + return null; + }, ), ), - onTap: () async { - if (!key.currentState!.validate()) { - return; - } - if (kind.value == '') { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.emptyKindError); - return; - } - await tokenExpireWrapper(ref, () async { - final value = await associationListNotifier - .updateAssociation(association.copyWith( - name: name.text, - description: description.text, - kind: kind.value)); - if (value) { - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.updatedAssociation); - } else { - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.updatingError); - } - }); - }, - child: Container( - width: double.infinity, - margin: const EdgeInsets.symmetric(vertical: 20), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, - ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: const Text( - PhonebookTextConstants.edit, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color.fromARGB(255, 255, 255, 255), - ), + ], + )), + Container( + margin: const EdgeInsets.symmetric(vertical: 10), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + child: TextFormField( + controller: description, + cursorColor: ColorConstants.gradient1, + decoration: InputDecoration( + labelText: "Description", + labelStyle: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + suffixIcon: Container( + padding: const EdgeInsets.all(10), + child: const HeroIcon( + HeroIcons.pencil, + ), + ), + enabledBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: Colors.transparent, + ), + ), + focusedBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: ColorConstants.gradient1))), + validator: (value) { + if (value == null || value.isEmpty) { + return PhonebookTextConstants + .emptyFieldError; + } + return null; + }, ), ), - ) - ], - ), - ) - ])), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), - child: Row( - children: [ - const Text(PhonebookTextConstants.members), - const Spacer(), + ], + )), ShrinkButton( + waitChild: Container( + width: double.infinity, + margin: const EdgeInsets.symmetric(vertical: 20), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), + ], + borderRadius: BorderRadius.circular(15), + ), + child: const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + color: Colors.white, + ), + ), + ), onTap: () async { - rolesTagsNotifier.resetChecked(); - completeMemberNotifier - .setCompleteMember(CompleteMember.empty()); - editionNotifier.setStatus(false); - if (QR.currentPath.contains(PhonebookRouter.admin)) { - QR.to(PhonebookRouter.root + PhonebookRouter.admin + PhonebookRouter.editAssociation + PhonebookRouter.addEditMember); - } else { - QR.to(PhonebookRouter.root + PhonebookRouter.editAssociation + PhonebookRouter.addEditMember); + if (!key.currentState!.validate()) { + return; + } + if (kind.value == '') { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.emptyKindError); + return; } - + await tokenExpireWrapper(ref, () async { + final value = await associationListNotifier + .updateAssociation(association.copyWith( + name: name.text, + description: description.text, + kind: kind.value)); + if (value) { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.updatedAssociation); + } else { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.updatingError); + } + }); }, child: Container( - width: 40, - height: 40, + width: double.infinity, + margin: const EdgeInsets.symmetric(vertical: 20), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, decoration: BoxDecoration( - color: ColorConstants.gradient1, - borderRadius: BorderRadius.circular(10), + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), + ], + borderRadius: BorderRadius.circular(15), ), - child: const Icon( - Icons.add, - color: Colors.white, + child: const Text( + PhonebookTextConstants.edit, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), + ), ), ), - ), + ) ], ), - ), - ...associationMemberList.when( - data: (data) { - return data - .map((member) => MemberEditableCard(member: member)) - .toList(); - }, - error: (error, stackTrace) { - return const [ - Text(PhonebookTextConstants.errorLoadAssociationMember), - ]; - }, - loading: () => [ - const Center( - child: CircularProgressIndicator(), - ), - ], - ), - const SizedBox( - height: 10, - ), + ) + ])), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: Row( + children: [ + const Text(PhonebookTextConstants.members), + const Spacer(), ShrinkButton( - waitChild: Container( - width: double.infinity, - margin: const EdgeInsets.all(30), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, - ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: const SizedBox( - height: 20, - width: 20, - child: CircularProgressIndicator( - color: Colors.white, - ), - ), - ), onTap: () async { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text(PhonebookTextConstants.newMandate), - content: - const Text(PhonebookTextConstants.changeMandateConfirm), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - }, - child: const Text(PhonebookTextConstants.cancel), - ), - TextButton( - onPressed: () async { - Navigator.pop(context); - await tokenExpireWrapper(ref, () async { - final value = await associationListNotifier - .updateAssociation(association.copyWith( - mandateYear: association.mandateYear + 1)); - if (value) { - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.newMandateConfirmed); - } else { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.mandateChangingError); - } - }); - }, - child: const Text(PhonebookTextConstants.validation), - ), - ], - ), - ); + rolesTagsNotifier.resetChecked(); + completeMemberNotifier + .setCompleteMember(CompleteMember.empty()); + editionNotifier.setStatus(false); + if (QR.currentPath.contains(PhonebookRouter.admin)) { + QR.to(PhonebookRouter.root + + PhonebookRouter.admin + + PhonebookRouter.editAssociation + + PhonebookRouter.addEditMember); + } else { + QR.to(PhonebookRouter.root + + PhonebookRouter.editAssociation + + PhonebookRouter.addEditMember); + } }, child: Container( - width: double.infinity, - margin: const EdgeInsets.all(30), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, + width: 40, + height: 40, decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, - ), - ], - borderRadius: BorderRadius.circular(15), + color: ColorConstants.gradient1, + borderRadius: BorderRadius.circular(10), ), - child: Text( - "${PhonebookTextConstants.changeMandate} ${association.mandateYear + 1}", - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color.fromARGB(255, 255, 255, 255), - ), + child: const Icon( + Icons.add, + color: Colors.white, ), ), - ) - ]), - )); + ), + ], + ), + ), + ...associationMemberList.when( + data: (data) { + return data + .map((member) => MemberEditableCard(member: member)) + .toList(); + }, + error: (error, stackTrace) { + return const [ + Text(PhonebookTextConstants.errorLoadAssociationMember), + ]; + }, + loading: () => [ + const Center( + child: CircularProgressIndicator(), + ), + ], + ), + const SizedBox( + height: 10, + ), + ShrinkButton( + waitChild: Container( + width: double.infinity, + margin: const EdgeInsets.all(30), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), + ], + borderRadius: BorderRadius.circular(15), + ), + child: const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + color: Colors.white, + ), + ), + ), + onTap: () async { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text(PhonebookTextConstants.newMandate), + content: + const Text(PhonebookTextConstants.changeMandateConfirm), + actions: [ + TextButton( + onPressed: () { + Navigator.pop(context); + }, + child: const Text(PhonebookTextConstants.cancel), + ), + TextButton( + onPressed: () async { + Navigator.pop(context); + await tokenExpireWrapper(ref, () async { + final value = await associationListNotifier + .updateAssociation(association.copyWith( + mandateYear: association.mandateYear + 1)); + if (value) { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.newMandateConfirmed); + } else { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.mandateChangingError); + } + }); + }, + child: const Text(PhonebookTextConstants.validation), + ), + ], + ), + ); + }, + child: Container( + width: double.infinity, + margin: const EdgeInsets.all(30), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], + ), + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), + ], + borderRadius: BorderRadius.circular(15), + ), + child: Text( + "${PhonebookTextConstants.changeMandate} ${association.mandateYear + 1}", + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), + ), + ), + ), + ) + ]), + )); } } diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index e5fe1b6a2..874e5bef8 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -82,7 +82,7 @@ class MemberEditableCard extends HookConsumerWidget { child: Column( children: [ Text( - "${member.member.name} ${member.member.firstname} (${member.member.nickname})", + member.member.getName(), style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, @@ -117,13 +117,13 @@ class MemberEditableCard extends HookConsumerWidget { editionNotifier.setStatus(true); if (QR.currentPath.contains(PhonebookRouter.admin)) { QR.to(PhonebookRouter.root + - PhonebookRouter.admin + - PhonebookRouter.editAssociation + - PhonebookRouter.addEditMember); + PhonebookRouter.admin + + PhonebookRouter.editAssociation + + PhonebookRouter.addEditMember); } else { QR.to(PhonebookRouter.root + - PhonebookRouter.editAssociation + - PhonebookRouter.addEditMember); + PhonebookRouter.editAssociation + + PhonebookRouter.addEditMember); } }), const SizedBox(width: 10), @@ -132,7 +132,8 @@ class MemberEditableCard extends HookConsumerWidget { final result = await associationNotifier.deleteMember( member.memberships.firstWhere( (element) => element.association.id == association.id)); - await associationMembersNotifier.loadMembers(association.id, association.mandateYear.toString()); + await associationMembersNotifier.loadMembers( + association.id, association.mandateYear.toString()); if (result) { displayToastWithContext( TypeMsg.msg, PhonebookTextConstants.deletedMember); diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index f03cce0a8..19eb4ac46 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -27,15 +27,14 @@ class AssociationPage extends HookConsumerWidget { final isPresident = ref.watch(isAssociationPresidentProvider); return PhonebookTemplate( - child: - Refresher( - onRefresh: () async { - await associationMemberListNotifier.loadMembers(association.id, association.mandateYear.toString()); - await associationPictureNotifier - .getAssociationPicture(association.id); - }, - child: Stack( - children: [ + child: Refresher( + onRefresh: () async { + await associationMemberListNotifier.loadMembers( + association.id, association.mandateYear.toString()); + await associationPictureNotifier + .getAssociationPicture(association.id); + }, + child: Stack(children: [ Column(children: [ const Text(PhonebookTextConstants.associationDetail, style: TextStyle(fontSize: 30)), @@ -75,8 +74,8 @@ class AssociationPage extends HookConsumerWidget { }, error: (e, s) { return const Center( - child: - Text(PhonebookTextConstants.errorLoadAssociationPicture), + child: Text( + PhonebookTextConstants.errorLoadAssociationPicture), ); }, ), @@ -116,49 +115,48 @@ class AssociationPage extends HookConsumerWidget { }, error: (e, s) { return const Center( - child: Text(PhonebookTextConstants.errorLoadAssociationMember), + child: Text( + PhonebookTextConstants.errorLoadAssociationMember), ); }, ) - ] - ), - if (isPresident) - Positioned( - top: 20, - right: 20, - child: GestureDetector( - onTap: () { - QR.to(PhonebookRouter.root + PhonebookRouter.admin + PhonebookRouter.editAssociation); - }, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 10, - offset: const Offset(0, 5)) - ]), - child: const Row( - children: [ - HeroIcon(HeroIcons.userGroup, color: Colors.white), - SizedBox(width: 10), - Text(PhonebookTextConstants.admin, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.white)), - ], - ), + ]), + if (isPresident) + Positioned( + top: 20, + right: 20, + child: GestureDetector( + onTap: () { + QR.to(PhonebookRouter.root + + PhonebookRouter.admin + + PhonebookRouter.editAssociation); + }, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + blurRadius: 10, + offset: const Offset(0, 5)) + ]), + child: const Row( + children: [ + HeroIcon(HeroIcons.userGroup, color: Colors.white), + SizedBox(width: 10), + Text(PhonebookTextConstants.admin, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.white)), + ], ), ), - ), - ] - ) - ) - ); + ), + ), + ]))); } } diff --git a/lib/phonebook/ui/pages/association_page/member_card.dart b/lib/phonebook/ui/pages/association_page/member_card.dart index 6068890be..0e0b6e00f 100644 --- a/lib/phonebook/ui/pages/association_page/member_card.dart +++ b/lib/phonebook/ui/pages/association_page/member_card.dart @@ -75,7 +75,7 @@ class MemberCard extends HookConsumerWidget { child: Column( children: [ Text( - "${member.member.name} ${member.member.firstname} (${member.member.nickname})", + member.member.getName(), style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, diff --git a/lib/phonebook/ui/pages/main_page/association_card.dart b/lib/phonebook/ui/pages/main_page/association_card.dart index 312ff1de1..af1d85b0e 100644 --- a/lib/phonebook/ui/pages/main_page/association_card.dart +++ b/lib/phonebook/ui/pages/main_page/association_card.dart @@ -4,6 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/associations_pictures_provider.dart'; +import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; @@ -12,10 +13,12 @@ class AssociationCard extends HookConsumerWidget { super.key, required this.association, required this.onClicked, + required this.giveMemberRole, }); final Association association; final VoidCallback onClicked; + final bool giveMemberRole; @override Widget build(BuildContext context, WidgetRef ref) { @@ -24,6 +27,7 @@ class AssociationCard extends HookConsumerWidget { ref.watch(associationPicturesProvider.notifier); final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); + final member = ref.watch(completeMemberProvider); return Padding( padding: const EdgeInsets.symmetric(horizontal: 30), @@ -117,7 +121,12 @@ class AssociationCard extends HookConsumerWidget { ), const Spacer(flex: 1), Text( - association.kind, + giveMemberRole + ? member.memberships + .firstWhere((element) => + element.association.id == association.id) + .apparentName + : association.kind, style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index e8094af91..18792ff13 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -34,111 +34,114 @@ class PhonebookMainPage extends HookConsumerWidget { final nameFilter = ref.watch(filterProvider); return PhonebookTemplate( - child: - Refresher( - onRefresh: () async { - await associationKindsNotifier.loadAssociationKinds(); - await associationListNotifier.loadAssociations(); - }, - child: Column(children: [ - Padding( - padding: const EdgeInsets.all(30.0), - child: Row( - children: [ - const ResearchBar(), - if (isAdmin) const SizedBox(width: 20), - if (isAdmin) - GestureDetector( - onTap: () { - QR.to(PhonebookRouter.root + PhonebookRouter.admin); - }, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 10, - offset: const Offset(0, 5)) - ]), - child: const Row( - children: [ - HeroIcon(HeroIcons.userGroup, color: Colors.white), - SizedBox(width: 10), - Text(PhonebookTextConstants.admin, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.white)), - ], + child: Refresher( + onRefresh: () async { + await associationKindsNotifier.loadAssociationKinds(); + await associationListNotifier.loadAssociations(); + }, + child: Column(children: [ + Padding( + padding: const EdgeInsets.all(30.0), + child: Row( + children: [ + const ResearchBar(), + if (isAdmin) const SizedBox(width: 20), + if (isAdmin) + GestureDetector( + onTap: () { + QR.to(PhonebookRouter.root + PhonebookRouter.admin); + }, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + blurRadius: 10, + offset: const Offset(0, 5)) + ]), + child: const Row( + children: [ + HeroIcon(HeroIcons.userGroup, + color: Colors.white), + SizedBox(width: 10), + Text(PhonebookTextConstants.admin, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.white)), + ], + ), ), ), - ), - ], + ], + ), ), - ), - const SizedBox(height: 10), - associationKinds.when( - data: (data) { - debugPrint("associationKinds.when data: ${data.kinds}"); - return SingleChildScrollView( - scrollDirection: Axis.horizontal, - physics: const BouncingScrollPhysics(), - child: Row(children: [ - const SizedBox( - width: 20, - ), - RadioChip( - label: PhonebookTextConstants.all, - selected: kind.value == "", - onTap: () { - kind.value = ""; - kindNotifier.setKind(""); - associationListNotifier.filterAssociationList( - nameFilter, kind.value); - }), - ...data.kinds - .map((e) => RadioChip( - label: e, - selected: kind.value == e, - onTap: () { - kind.value = e; - kindNotifier.setKind(e); - associationListNotifier.filterAssociationList( - nameFilter, kind.value); - })) - .toList(), - const SizedBox( - width: 20, - ), - ])); - }, - error: (error, stackTrace) => - const Text(PhonebookTextConstants.errorKindsLoading), - loading: () => const CircularProgressIndicator()), - const SizedBox(height: 30), - ...associationList.when( - data: (associations) { - return associations - .map((association) => AssociationCard( - association: association, - onClicked: () { - associationNotifier.setAssociation(association); - QR.to(PhonebookRouter.root + - PhonebookRouter.associationDetail); - }, - )) - .toList(); - }, - loading: () => const [Center(child: CircularProgressIndicator())], - error: (error, stack) => [ - const Center( - child: Text( - PhonebookTextConstants.errorLoadAssociationList)) - ]) - ]))); + const SizedBox(height: 10), + associationKinds.when( + data: (data) { + debugPrint("associationKinds.when data: ${data.kinds}"); + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + physics: const BouncingScrollPhysics(), + child: Row(children: [ + const SizedBox( + width: 20, + ), + RadioChip( + label: PhonebookTextConstants.all, + selected: kind.value == "", + onTap: () { + kind.value = ""; + kindNotifier.setKind(""); + associationListNotifier.filterAssociationList( + nameFilter, kind.value); + }), + ...data.kinds + .map((e) => RadioChip( + label: e, + selected: kind.value == e, + onTap: () { + kind.value = e; + kindNotifier.setKind(e); + associationListNotifier + .filterAssociationList( + nameFilter, kind.value); + })) + .toList(), + const SizedBox( + width: 20, + ), + ])); + }, + error: (error, stackTrace) => + const Text(PhonebookTextConstants.errorKindsLoading), + loading: () => const CircularProgressIndicator()), + const SizedBox(height: 30), + ...associationList.when( + data: (associations) { + return associations + .map((association) => AssociationCard( + association: association, + onClicked: () { + associationNotifier.setAssociation(association); + QR.to(PhonebookRouter.root + + PhonebookRouter.associationDetail); + }, + giveMemberRole: false, + )) + .toList(); + }, + loading: () => + const [Center(child: CircularProgressIndicator())], + error: (error, stack) => [ + const Center( + child: Text(PhonebookTextConstants + .errorLoadAssociationList)) + ]) + ]))); } } diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart index c32ea544a..132565226 100644 --- a/lib/phonebook/ui/pages/main_page/research_bar.dart +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -20,28 +20,28 @@ class ResearchBar extends HookConsumerWidget { return Expanded( child: TextField( - onChanged: (value) { - associationsNotifier.filterAssociationList(value, associationKind); - filterNotifier.setFilter(value); - }, - focusNode: focusNode, - controller: editingController, - cursorColor: PhonebookColorConstants.textDark, - decoration: const InputDecoration( - isDense: true, - suffixIcon: Icon( - Icons.search, - color: PhonebookColorConstants.textDark, - size: 30, - ), - label: Text( - PhonebookTextConstants.research, - style: TextStyle( - color: PhonebookColorConstants.textDark,), - ), - focusedBorder: UnderlineInputBorder( - borderSide: - BorderSide(color: ColorConstants.gradient1))), - )); + onChanged: (value) { + associationsNotifier.filterAssociationList(value, associationKind); + filterNotifier.setFilter(value); + }, + focusNode: focusNode, + controller: editingController, + cursorColor: PhonebookColorConstants.textDark, + decoration: const InputDecoration( + isDense: true, + suffixIcon: Icon( + Icons.search, + color: PhonebookColorConstants.textDark, + size: 30, + ), + label: Text( + PhonebookTextConstants.research, + style: TextStyle( + color: PhonebookColorConstants.textDark, + ), + ), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(color: ColorConstants.gradient1))), + )); } } diff --git a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart index 125664bea..a0d3e285a 100644 --- a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart +++ b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart @@ -16,33 +16,37 @@ class MemberDetailPage extends HookConsumerWidget { final memberProvider = ref.watch(completeMemberProvider); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); return PhonebookTemplate( - child: - Container( - margin: const EdgeInsets.all(10), - width: MediaQuery.of(context).size.width, - decoration: BoxDecoration(borderRadius: BorderRadius.circular(50)), - child: Column(children: [ - const Text(PhonebookTextConstants.detail), - Text("${PhonebookTextConstants.name} ${memberProvider.member.name}"), - Text( - "${PhonebookTextConstants.firstname} ${memberProvider.member.firstname}"), - if (memberProvider.member.nickname != null) - Text( - "${PhonebookTextConstants.nickname} ${memberProvider.member.nickname!}"), - Text( - "${PhonebookTextConstants.promotion} ${memberProvider.member.promotion}"), - Text( - "${PhonebookTextConstants.email} ${memberProvider.member.email}"), - const Text(PhonebookTextConstants - .association), //TODO: à changer pour dépendre du nombre d'associatione - ...memberProvider.memberships.map( - (e) => AssociationCard( - association: e.association, - onClicked: (() { - associationNotifier.setAssociation(e.association); - QR.to(PhonebookRouter.root + - PhonebookRouter.associationDetail); - }))).toList(), - ]))); + child: Container( + margin: const EdgeInsets.all(10), + width: MediaQuery.of(context).size.width, + decoration: BoxDecoration(borderRadius: BorderRadius.circular(50)), + child: Column(children: [ + const Text(PhonebookTextConstants.detail), + Text( + "${PhonebookTextConstants.name} ${memberProvider.member.name}"), + Text( + "${PhonebookTextConstants.firstname} ${memberProvider.member.firstname}"), + if (memberProvider.member.nickname != null) + Text( + "${PhonebookTextConstants.nickname} ${memberProvider.member.nickname!}"), + Text( + "${PhonebookTextConstants.promotion} ${memberProvider.member.promotion}"), + Text( + "${PhonebookTextConstants.email} ${memberProvider.member.email}"), + if (memberProvider.memberships.isNotEmpty) + Text(memberProvider.memberships.length == 1 + ? PhonebookTextConstants.association + : PhonebookTextConstants.associations), + ...memberProvider.memberships + .map((e) => AssociationCard( + association: e.association, + onClicked: () { + associationNotifier.setAssociation(e.association); + QR.to(PhonebookRouter.root + + PhonebookRouter.associationDetail); + }, + giveMemberRole: true)) + .toList(), + ]))); } } diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index c8a203e37..e487886b9 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -24,7 +24,6 @@ class MembershipEditorPage extends HookConsumerWidget { Key? key, }) : super(key: key); - @override Widget build(BuildContext context, WidgetRef ref) { final rolesTags = ref.watch(rolesTagsProvider); @@ -53,145 +52,151 @@ class MembershipEditorPage extends HookConsumerWidget { } return PhonebookTemplate( - child: - Padding( - padding: const EdgeInsets.all(20.0), - child: SingleChildScrollView( - child: Column( - children: [ - Center( - child: Container( - decoration: const BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.black)), - color: Colors.white, + child: Padding( + padding: const EdgeInsets.all(20.0), + child: SingleChildScrollView( + child: Column( + children: [ + Center( + child: Container( + decoration: const BoxDecoration( + border: + Border(bottom: BorderSide(color: Colors.black)), + color: Colors.white, + ), + child: Text( + edition + ? PhonebookTextConstants.editMembership + : PhonebookTextConstants.addMember, + style: const TextStyle(fontSize: 20)))), + if (!edition) + TextFormField( + onChanged: (value) { + tokenExpireWrapper(ref, () async { + if (queryController.text.isNotEmpty) { + await usersNotifier.filterUsers(queryController.text); + } else { + usersNotifier.clear(); + } + }); + }, + cursorColor: Colors.black, + controller: queryController, + decoration: const InputDecoration( + labelText: PhonebookTextConstants.member, + floatingLabelStyle: TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + ), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.black, width: 2.0), ), - child: Text( - edition - ? PhonebookTextConstants.editMembership - : PhonebookTextConstants.addMember, - style: const TextStyle(fontSize: 20)))), - if (!edition) - TextFormField( - onChanged: (value) { - tokenExpireWrapper(ref, () async { - if (queryController.text.isNotEmpty) { - await usersNotifier.filterUsers(queryController.text); - } else { - usersNotifier.clear(); - } - }); - }, - cursorColor: Colors.black, - controller: queryController, - decoration: const InputDecoration( - labelText: PhonebookTextConstants.member, - floatingLabelStyle: TextStyle( - color: Colors.black, - fontWeight: FontWeight.bold, - ), - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide(color: Colors.black, width: 2.0), ), ), + const SizedBox( + height: 10, ), - const SizedBox( - height: 10, - ), - SearchResult(queryController: queryController), - SizedBox( - width: min(MediaQuery.of(context).size.width, 300), - child: Column(children: [ - ...rolesTags.when( - data: (data) { - return data.keys - .map((e) => Row(children: [ - Text(e), - const Spacer(), - Checkbox( - value: data[e]!.maybeWhen( + SearchResult(queryController: queryController), + SizedBox( + width: min(MediaQuery.of(context).size.width, 300), + child: Column(children: [ + ...rolesTags.when( + data: (data) { + return data.keys + .map((e) => Row(children: [ + Text(e), + const Spacer(), + Checkbox( + value: data[e]!.maybeWhen( data: (d) => d[0], - orElse:() => false,), - fillColor: - MaterialStateProperty.all(Colors.black), - onChanged: (value) { - data[e] = AsyncData([value!]); - apparentNameController.text = - nameConstructor(data); - memberRoleTagsNotifier - .setRoleTagsWithFilter(data); - rolesTagsNotifier.setTData(e, AsyncData([value])); - }, - ), - ])) - .toList(); - }, - error: (e, s) => [const Text('Error')], - loading: () => [const Text('Loading')], - ), - ]), - ), - const SizedBox(height: 5), - const Text(PhonebookTextConstants.apparentName), - TextField( - controller: apparentNameController, - ), - const SizedBox(height: 5), - ShrinkButton( - child: Text(!edition - ? PhonebookTextConstants.add - : PhonebookTextConstants.edit), - onTap: () async { - if (member.member.id == "") { - displayToastWithContext( - TypeMsg.msg, PhonebookTextConstants.emptyMember); - return; - } - if (apparentNameController.text == "") { - displayToastWithContext( - TypeMsg.msg, PhonebookTextConstants.emptyApparentName); - return; - } - debugPrint("Appui sur le bouton avec les paramètres:\n" - "association: $association\n" - "member: ${member.member}\n" - "rolesTags: $memberRoleTags\n" - "apparentName: ${apparentNameController.text}"); - tokenExpireWrapper(ref, () async { - if (edition) { - final value = await associationNotifier.updateMember( - association, - member.member, - memberRoleTags, - apparentNameController.text); - if (value) { - associationMemberListNotifier.loadMembers(association.id, association.mandateYear.toString()); - displayToastWithContext( - TypeMsg.msg, PhonebookTextConstants.updatedMember); - QR.back(); - } else { - displayToastWithContext( - TypeMsg.msg, PhonebookTextConstants.updatingError); - } - } else { - final value = await associationNotifier.addMember( - association, - member.member, - memberRoleTags, - apparentNameController.text); - if (value) { - associationMemberListNotifier.loadMembers(association.id, association.mandateYear.toString()); - displayToastWithContext( - TypeMsg.msg, PhonebookTextConstants.addedMember); - QR.back(); + orElse: () => false, + ), + fillColor: + MaterialStateProperty.all(Colors.black), + onChanged: (value) { + data[e] = AsyncData([value!]); + apparentNameController.text = + nameConstructor(data); + memberRoleTagsNotifier + .setRoleTagsWithFilter(data); + rolesTagsNotifier.setTData( + e, AsyncData([value])); + }, + ), + ])) + .toList(); + }, + error: (e, s) => [const Text('Error')], + loading: () => [const Text('Loading')], + ), + ]), + ), + const SizedBox(height: 5), + const Text(PhonebookTextConstants.apparentName), + TextField( + controller: apparentNameController, + ), + const SizedBox(height: 5), + ShrinkButton( + child: Text(!edition + ? PhonebookTextConstants.add + : PhonebookTextConstants.edit), + onTap: () async { + if (member.member.id == "") { + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.emptyMember); + return; + } + if (apparentNameController.text == "") { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.emptyApparentName); + return; + } + debugPrint("Appui sur le bouton avec les paramètres:\n" + "association: $association\n" + "member: ${member.member}\n" + "rolesTags: $memberRoleTags\n" + "apparentName: ${apparentNameController.text}"); + tokenExpireWrapper(ref, () async { + if (edition) { + final value = await associationNotifier.updateMember( + association, + member.member, + memberRoleTags, + apparentNameController.text); + if (value) { + associationMemberListNotifier.loadMembers( + association.id, + association.mandateYear.toString()); + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.updatedMember); + QR.back(); + } else { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.updatingError); + } } else { - displayToastWithContext( - TypeMsg.msg, PhonebookTextConstants.addingError); + final value = await associationNotifier.addMember( + association, + member.member, + memberRoleTags, + apparentNameController.text); + if (value) { + associationMemberListNotifier.loadMembers( + association.id, + association.mandateYear.toString()); + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.addedMember); + QR.back(); + } else { + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.addingError); + } } - } - }); - }, - ), - ], - )))); + }); + }, + ), + ], + )))); } } diff --git a/lib/phonebook/ui/phonebook.dart b/lib/phonebook/ui/phonebook.dart index ccf339c13..5dade646d 100644 --- a/lib/phonebook/ui/phonebook.dart +++ b/lib/phonebook/ui/phonebook.dart @@ -6,34 +6,32 @@ import 'package:myecl/phonebook/ui/top_bar.dart'; class PhonebookTemplate extends HookConsumerWidget { final Widget child; - const PhonebookTemplate( - {Key? key, required this.child}) - : super(key: key); + const PhonebookTemplate({Key? key, required this.child}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { final animationNotifier = ref.watch(animationProvider.notifier); final controller = - ref.watch(swipeControllerProvider(animationNotifier.animation!)); + ref.watch(swipeControllerProvider(animationNotifier.animation!)); final controllerNotifier = ref .watch(swipeControllerProvider(animationNotifier.animation!).notifier); return Scaffold( body: Container( color: Colors.white, child: SafeArea( - child: IgnorePointer( - ignoring: controller.isCompleted, - child: Column( - children: [ - TopBar( - controllerNotifier: controllerNotifier, - ), - Expanded(child: child), - ], - ), + child: IgnorePointer( + ignoring: controller.isCompleted, + child: Column( + children: [ + TopBar( + controllerNotifier: controllerNotifier, + ), + Expanded(child: child), + ], ), ), + ), ), ); } -} \ No newline at end of file +} From 0fcc38ab1d04bff6e2cebaeb54bddd470e039dee Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:03 +0100 Subject: [PATCH 044/123] UI improvement and member list fix --- lib/phonebook/class/complete_member.dart | 7 +- lib/phonebook/class/member.dart | 13 ++-- lib/phonebook/class/membership.dart | 20 ++--- .../providers/association_list_provider.dart | 12 ++- .../association_member_list_provider.dart | 4 +- .../providers/association_provider.dart | 5 +- .../associations_pictures_provider.dart | 2 +- .../providers/phonebook_admin_provider.dart | 2 +- .../repositories/association_repository.dart | 2 +- lib/phonebook/tools/constants.dart | 2 + lib/phonebook/tools/function.dart | 2 +- .../ui/pages/admin_page/admin_page.dart | 73 ++++++++++++------- .../admin_page/association_research_bar.dart | 3 +- .../admin_page/editable_association_card.dart | 16 ++-- .../association_creation_page.dart | 12 ++- .../association_creation_page/text_entry.dart | 20 +++-- .../association_editor_page.dart | 19 +++-- .../member_editable_card.dart | 5 +- .../association_page/association_page.dart | 1 - .../pages/association_page/member_card.dart | 2 +- .../ui/pages/main_page/association_card.dart | 9 ++- .../ui/pages/main_page/main_page.dart | 6 +- .../ui/pages/main_page/research_bar.dart | 3 +- .../member_detail_page.dart | 11 ++- .../membership_editor_page.dart | 2 +- 25 files changed, 150 insertions(+), 103 deletions(-) diff --git a/lib/phonebook/class/complete_member.dart b/lib/phonebook/class/complete_member.dart index 27cfff802..4c8656f23 100644 --- a/lib/phonebook/class/complete_member.dart +++ b/lib/phonebook/class/complete_member.dart @@ -12,14 +12,13 @@ class CompleteMember { late final List memberships; CompleteMember.fromJson(Map json) { - debugPrint(json.toString()); member = Member( name: json['name'], firstname: json['firstname'], - nickname: json['nickname'], + nickname: json['nickname'] ?? "", id: json['id'], email: json['email'], - promotion: json['promotion'] ?? ""); + promotion: json['promo'] ?? 0); memberships = List.from(json['memberships'] .map((membership) => Membership.fromJson(membership))); } @@ -58,7 +57,7 @@ class CompleteMember { List getRolesTags(String associationId) { return memberships - .firstWhere((element) => element.association.id == associationId) + .firstWhere((element) => element.associationId == associationId) .rolesTags; } } diff --git a/lib/phonebook/class/member.dart b/lib/phonebook/class/member.dart index 637085513..c20c21cdc 100644 --- a/lib/phonebook/class/member.dart +++ b/lib/phonebook/class/member.dart @@ -14,7 +14,7 @@ class Member extends SimpleUser { Member.fromJson(Map json) : super.fromJson(json) { email = json['email']; - promotion = json['promotion']; + promotion = json['promo'] ?? 0; } @override @@ -48,11 +48,12 @@ class Member extends SimpleUser { promotion = 0; } - Member.fromUser(SimpleUser user) : super.empty() { - name = user.name; - firstname = user.firstname; - nickname = user.nickname; - id = user.id; + Member.fromUser(SimpleUser user) + : super( + name: user.name, + firstname: user.firstname, + nickname: user.nickname, + id: user.id) { email = ""; promotion = 0; } diff --git a/lib/phonebook/class/membership.dart b/lib/phonebook/class/membership.dart index d082fad2f..7b4a9a80b 100644 --- a/lib/phonebook/class/membership.dart +++ b/lib/phonebook/class/membership.dart @@ -4,19 +4,19 @@ import 'package:myecl/phonebook/class/association.dart'; class Membership { Membership({ required this.id, - required this.association, + required this.associationId, required this.rolesTags, required this.apparentName, }); late final String id; - late final Association association; + late final String associationId; late final List rolesTags; late final String apparentName; Membership.fromJson(Map json) { id = json['id']; - association = Association.fromJson(json['association']); + associationId = json['association_id']; rolesTags = json['role_tags'].split(";"); apparentName = json['role_name']; } @@ -24,7 +24,7 @@ class Membership { Map toJson() { final data = { 'id': id, - 'association': association.id, + 'association': associationId, 'role_tags': rolesTags.join(";"), 'role_name': apparentName, }; @@ -33,13 +33,13 @@ class Membership { Membership copyWith({ String? id, - Association? association, + String? associationId, List? rolesTags, String? apparentName, }) { return Membership( id: id ?? this.id, - association: association ?? this.association, + associationId: associationId ?? this.associationId, rolesTags: rolesTags ?? this.rolesTags, apparentName: apparentName ?? this.apparentName, ); @@ -47,13 +47,13 @@ class Membership { Membership.empty() { id = ""; - association = Association.empty(); + associationId = ""; rolesTags = []; apparentName = ""; } - Membership setAssociation(String name, String id) { - return copyWith(association: association.copyWith(name: name, id: id)); + Membership setAssociation(String id) { + return copyWith(associationId: id); } Membership setRolesTags(List rolesTags) { @@ -66,6 +66,6 @@ class Membership { @override String toString() { - return 'Membership(id: $id, association: $association, rolesTags: ${rolesTags.join(";")}, apparentName: $apparentName)'; + return 'Membership(id: $id, association: $associationId, rolesTags: ${rolesTags.join(";")}, apparentName: $apparentName)'; } } diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index 5743d4a1b..5aae76dae 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -55,6 +55,8 @@ class AssociationListNotifier extends ListNotifier { } void filterAssociationList(String nameFilter, String kindFilter) async { + debugPrint("nameFilter: $nameFilter"); + debugPrint("kindFilter: $kindFilter"); if (kindFilter == "") { associationList.maybeWhen( data: (data) => state = AsyncValue.data(data @@ -84,8 +86,8 @@ class AssociationListNotifier extends ListNotifier { } } -final associationListProvider = StateNotifierProvider>>((ref) { +final asyncAssociationListProvider = StateNotifierProvider< + AssociationListNotifier, AsyncValue>>((ref) { final token = ref.watch(tokenProvider); AssociationListNotifier notifier = AssociationListNotifier(token: token); tokenExpireWrapperAuth(ref, () async { @@ -93,3 +95,9 @@ final associationListProvider = StateNotifierProvider>((ref) { + final association = ref.watch(asyncAssociationListProvider); + return association.maybeWhen( + data: (association) => association, orElse: () => [Association.empty()]); +}); diff --git a/lib/phonebook/providers/association_member_list_provider.dart b/lib/phonebook/providers/association_member_list_provider.dart index 1c494329b..58b68e593 100644 --- a/lib/phonebook/providers/association_member_list_provider.dart +++ b/lib/phonebook/providers/association_member_list_provider.dart @@ -17,8 +17,10 @@ class AssociationMemberListNotifier extends ListNotifier { Future>> loadMembers( String associationId, String year) async { - return await loadList(() async => associationMemberRepository + final result = await loadList(() async => associationMemberRepository .getAssociationMemberList(associationId, year)); + debugPrint("loadMembers: $result"); + return result; } } diff --git a/lib/phonebook/providers/association_provider.dart b/lib/phonebook/providers/association_provider.dart index 526cf1eac..1b4c46a20 100644 --- a/lib/phonebook/providers/association_provider.dart +++ b/lib/phonebook/providers/association_provider.dart @@ -26,10 +26,11 @@ class AssociationNotifier extends SingleNotifier { association); } - Future deleteMember(Membership membership) async { + Future deleteMember( + Membership membership, Association association) async { return await update( (association) async => associationRepository.deleteMember(membership), - membership.association); + association); } Future updateMember(Association association, Member user, diff --git a/lib/phonebook/providers/associations_pictures_provider.dart b/lib/phonebook/providers/associations_pictures_provider.dart index 0203af4a5..82b5ab135 100644 --- a/lib/phonebook/providers/associations_pictures_provider.dart +++ b/lib/phonebook/providers/associations_pictures_provider.dart @@ -15,7 +15,7 @@ final associationPicturesProvider = StateNotifierProvider< AssociationPictureNotifier associationPictureNotifier = AssociationPictureNotifier(); tokenExpireWrapperAuth(ref, () async { - ref.watch(associationListProvider).maybeWhen(data: (association) { + ref.watch(asyncAssociationListProvider).maybeWhen(data: (association) { associationPictureNotifier.loadTList(association); for (final l in association) { associationPictureNotifier.setTData(l, const AsyncValue.data([])); diff --git a/lib/phonebook/providers/phonebook_admin_provider.dart b/lib/phonebook/providers/phonebook_admin_provider.dart index 868249c23..a2d3f010a 100644 --- a/lib/phonebook/providers/phonebook_admin_provider.dart +++ b/lib/phonebook/providers/phonebook_admin_provider.dart @@ -29,7 +29,7 @@ final isAssociationPresidentProvider = StateProvider((ref) { .firstWhere((completeMember) => completeMember.member.id == me.id) .memberships .firstWhere( - (membership) => membership.association.id == association.id) + (membership) => membership.associationId == association.id) .rolesTags .contains(PhonebookTextConstants.presidentRoleTag)) { isPresident = true; diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index 67f175450..1841ab622 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -41,7 +41,7 @@ class AssociationRepository extends Repository { } Future deleteMember(Membership membership) async { - return await delete("/memberships/${membership.id}"); + return await delete("memberships/${membership.id}"); } Future updateMember(Association association, Member member, diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index b87b29903..038eaee8e 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -31,6 +31,7 @@ class PhonebookTextConstants { static const String deletedMember = "Membre supprimé"; static const String deleting = "Suppression"; static const String deletingError = "Erreur lors de la suppression"; + static const String description = "Description"; static const String edit = "Modifier"; static const String editMembership = "Modifier le rôle"; @@ -69,6 +70,7 @@ class PhonebookTextConstants { static const String membershipRoleError = "Veuillez choisir un rôle"; static const String name = "Nom :"; + static const String namePure = "Nom"; static const String newMandate = "Nouveau mandat"; static const String newMandateConfirmed = "Mandat changé"; static const String nickname = "Surnom :"; diff --git a/lib/phonebook/tools/function.dart b/lib/phonebook/tools/function.dart index ca2fb7f7f..0b761e8ce 100644 --- a/lib/phonebook/tools/function.dart +++ b/lib/phonebook/tools/function.dart @@ -14,5 +14,5 @@ String nameConstructor(Map>> data) { if (name.isEmpty) { return ""; } - return name.substring(1, name.length); + return name.substring(0, name.length - 1); } diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 55e22119b..9696ac890 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -14,6 +14,7 @@ import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/association_research_bar.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/editable_association_card.dart'; import 'package:myecl/tools/functions.dart'; +import 'package:myecl/tools/ui/dialog.dart'; import 'package:myecl/tools/ui/refresher.dart'; import 'package:qlevar_router/qlevar_router.dart'; @@ -23,8 +24,9 @@ class AdminPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final associationNotifier = ref.watch(asyncAssociationProvider.notifier); - final associationsNotifier = ref.watch(associationListProvider.notifier); - final associations = ref.watch(associationListProvider); + final associationsNotifier = + ref.watch(asyncAssociationListProvider.notifier); + final associations = ref.watch(asyncAssociationListProvider); final roleNotifier = ref.watch(rolesTagsProvider.notifier); final associationKinds = ref.watch(associationKindsProvider); final kind = useState(''); @@ -85,7 +87,7 @@ class AdminPage extends HookConsumerWidget { const Text(PhonebookTextConstants.errorRoleTagsLoading), loading: () => const CircularProgressIndicator()), Padding( - padding: const EdgeInsets.all(30.0), + padding: const EdgeInsets.all(10), child: Column( children: [ GestureDetector( @@ -114,31 +116,46 @@ class AdminPage extends HookConsumerWidget { data: (associations) { return associations .map((association) => EditableAssociationCard( - association: association, - onEdit: () { - associationNotifier - .setAssociation(association); - QR.to(PhonebookRouter.root + - PhonebookRouter.admin + - PhonebookRouter.editAssociation); - }, - onDelete: () async { - final result = await associationsNotifier - .deleteAssociation(association); - if (result) { - displayToastWithContext( - TypeMsg.msg, - PhonebookTextConstants - .deletedAssociation); - } else { - displayToastWithContext( - TypeMsg.error, - PhonebookTextConstants - .deletingError); - } - associationsNotifier.loadAssociations(); - }, - )) + association: association, + onEdit: () { + associationNotifier + .setAssociation(association); + QR.to(PhonebookRouter.root + + PhonebookRouter.admin + + PhonebookRouter.editAssociation); + }, + onDelete: () async { + await showDialog( + context: context, + builder: (context) { + return CustomDialogBox( + title: + PhonebookTextConstants.deleting, + descriptions: PhonebookTextConstants + .deleteAssociation, + onYes: () async { + final result = + await associationsNotifier + .deleteAssociation( + association); + if (result) { + displayToastWithContext( + TypeMsg.msg, + PhonebookTextConstants + .deletedAssociation); + } else { + displayToastWithContext( + TypeMsg.error, + PhonebookTextConstants + .deletingError); + } + associationsNotifier + .loadAssociations(); + }, + ); + }, + ); + })) .toList(); }, loading: () => diff --git a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart index b2bac602c..28c3c2242 100644 --- a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart +++ b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart @@ -15,7 +15,8 @@ class AssociationResearchBar extends HookConsumerWidget { final focusNode = useFocusNode(); final editingController = useTextEditingController(); final filterNotifier = ref.watch(filterProvider.notifier); - final associationsNotifier = ref.watch(associationListProvider.notifier); + final associationsNotifier = + ref.watch(asyncAssociationListProvider.notifier); final associationKind = ref.watch(associationKindProvider); return TextField( diff --git a/lib/phonebook/ui/pages/admin_page/editable_association_card.dart b/lib/phonebook/ui/pages/admin_page/editable_association_card.dart index 31f1b1cde..24b4aff54 100644 --- a/lib/phonebook/ui/pages/admin_page/editable_association_card.dart +++ b/lib/phonebook/ui/pages/admin_page/editable_association_card.dart @@ -27,7 +27,7 @@ class EditableAssociationCard extends HookConsumerWidget { final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); return Container( - margin: const EdgeInsets.symmetric(vertical: 10), + margin: const EdgeInsets.symmetric(vertical: 5), padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.white, @@ -40,9 +40,6 @@ class EditableAssociationCard extends HookConsumerWidget { ]), child: Row( children: [ - const SizedBox( - width: 10, - ), associationPictures.when( data: (pictures) { if (pictures[association] != null) { @@ -104,7 +101,10 @@ class EditableAssociationCard extends HookConsumerWidget { }, error: (e, s) { return const Center( - child: Text(PhonebookTextConstants.errorLoadAssociationPicture), + child: HeroIcon( + HeroIcons.exclamationCircle, + size: 40, + ), ); }, ), @@ -112,17 +112,17 @@ class EditableAssociationCard extends HookConsumerWidget { Text( association.name, style: const TextStyle( - color: Colors.black, fontSize: 20, fontWeight: FontWeight.bold), + color: Colors.black, fontSize: 16, fontWeight: FontWeight.bold), ), const Spacer(), Text(association.kind, style: const TextStyle( color: Colors.black, - fontSize: 20, + fontSize: 16, fontWeight: FontWeight.bold)), const Spacer(), EditionButton(onEdition: onEdit), - const SizedBox(width: 10), + const SizedBox(width: 5), DeleteButton(onDelete: onDelete), ], ), diff --git a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart index fe73d797b..00ef1ef00 100644 --- a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart +++ b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart @@ -25,8 +25,9 @@ class AssociationCreationPage extends HookConsumerWidget { final key = GlobalKey(); final name = useTextEditingController(); final description = useTextEditingController(); - final associationListNotifier = ref.watch(associationListProvider.notifier); - final associations = ref.watch(associationListProvider); + final associationListNotifier = + ref.watch(asyncAssociationListProvider.notifier); + final associations = ref.watch(asyncAssociationListProvider); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationKinds = ref.watch(associationKindsProvider); final kind = useState(''); @@ -96,10 +97,13 @@ class AssociationCreationPage extends HookConsumerWidget { ), ), AddAssociationTextEntry( - controller: name, title: AdminTextConstants.name), + controller: name, + title: AdminTextConstants.name, + canBeEmpty: false), AddAssociationTextEntry( controller: description, - title: AdminTextConstants.description), + title: AdminTextConstants.description, + canBeEmpty: true), ShrinkButton( waitChild: Container( width: double.infinity, diff --git a/lib/phonebook/ui/pages/association_creation_page/text_entry.dart b/lib/phonebook/ui/pages/association_creation_page/text_entry.dart index 0f37ac0fa..d6024c2e4 100644 --- a/lib/phonebook/ui/pages/association_creation_page/text_entry.dart +++ b/lib/phonebook/ui/pages/association_creation_page/text_entry.dart @@ -5,8 +5,12 @@ import 'package:myecl/tools/constants.dart'; class AddAssociationTextEntry extends StatelessWidget { final TextEditingController controller; final String title; + final bool canBeEmpty; const AddAssociationTextEntry( - {Key? key, required this.controller, required this.title}) + {Key? key, + required this.controller, + required this.title, + required this.canBeEmpty}) : super(key: key); @override @@ -36,12 +40,14 @@ class AddAssociationTextEntry extends StatelessWidget { focusedBorder: UnderlineInputBorder( borderSide: BorderSide(color: ColorConstants.gradient1))), - validator: (value) { - if (value == null || value.isEmpty) { - return AdminTextConstants.emptyFieldError; - } - return null; - }, + validator: canBeEmpty + ? null + : (value) { + if (value == null || value.isEmpty) { + return AdminTextConstants.emptyFieldError; + } + return null; + }, ), ), ], diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 69c9c7f07..2adc43ab2 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -30,12 +30,14 @@ class AssociationEditorPage extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final key = GlobalKey(); final association = ref.watch(associationProvider); + final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); final associationMemberList = ref.watch(associationMemberListProvider); final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); - final associationListNotifier = ref.watch(associationListProvider.notifier); + final associationListNotifier = + ref.watch(asyncAssociationListProvider.notifier); final associationKinds = ref.watch(associationKindsProvider); final kind = useState(association.kind); final name = useTextEditingController(text: association.name); @@ -112,7 +114,7 @@ class AssociationEditorPage extends HookConsumerWidget { controller: name, cursorColor: ColorConstants.gradient1, decoration: InputDecoration( - labelText: "Name", + labelText: PhonebookTextConstants.namePure, labelStyle: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, @@ -153,7 +155,8 @@ class AssociationEditorPage extends HookConsumerWidget { controller: description, cursorColor: ColorConstants.gradient1, decoration: InputDecoration( - labelText: "Description", + labelText: + PhonebookTextConstants.description, labelStyle: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, @@ -172,13 +175,6 @@ class AssociationEditorPage extends HookConsumerWidget { focusedBorder: const UnderlineInputBorder( borderSide: BorderSide( color: ColorConstants.gradient1))), - validator: (value) { - if (value == null || value.isEmpty) { - return PhonebookTextConstants - .emptyFieldError; - } - return null; - }, ), ), ], @@ -388,6 +384,9 @@ class AssociationEditorPage extends HookConsumerWidget { if (value) { displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.newMandateConfirmed); + associationNotifier.setAssociation( + association.copyWith( + mandateYear: association.mandateYear + 1)); } else { displayToastWithContext(TypeMsg.error, PhonebookTextConstants.mandateChangingError); diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index 874e5bef8..78d3cff9c 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -103,7 +103,7 @@ class MemberEditableCard extends HookConsumerWidget { Text( member.memberships .firstWhere( - (element) => element.association.id == association.id) + (element) => element.associationId == association.id) .apparentName, style: const TextStyle( fontSize: 20, @@ -131,7 +131,8 @@ class MemberEditableCard extends HookConsumerWidget { onDelete: () async { final result = await associationNotifier.deleteMember( member.memberships.firstWhere( - (element) => element.association.id == association.id)); + (element) => element.associationId == association.id), + association); await associationMembersNotifier.loadMembers( association.id, association.mandateYear.toString()); if (result) { diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index 19eb4ac46..376a7cc0a 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -128,7 +128,6 @@ class AssociationPage extends HookConsumerWidget { child: GestureDetector( onTap: () { QR.to(PhonebookRouter.root + - PhonebookRouter.admin + PhonebookRouter.editAssociation); }, child: Container( diff --git a/lib/phonebook/ui/pages/association_page/member_card.dart b/lib/phonebook/ui/pages/association_page/member_card.dart index 0e0b6e00f..1c9e0738a 100644 --- a/lib/phonebook/ui/pages/association_page/member_card.dart +++ b/lib/phonebook/ui/pages/association_page/member_card.dart @@ -96,7 +96,7 @@ class MemberCard extends HookConsumerWidget { Text( member.memberships .firstWhere((element) => - element.association.id == association.id) + element.associationId == association.id) .apparentName, style: const TextStyle( fontSize: 20, diff --git a/lib/phonebook/ui/pages/main_page/association_card.dart b/lib/phonebook/ui/pages/main_page/association_card.dart index af1d85b0e..f63bcf62c 100644 --- a/lib/phonebook/ui/pages/main_page/association_card.dart +++ b/lib/phonebook/ui/pages/main_page/association_card.dart @@ -30,10 +30,11 @@ class AssociationCard extends HookConsumerWidget { final member = ref.watch(completeMemberProvider); return Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), + padding: const EdgeInsets.symmetric(horizontal: 10), child: GestureDetector( onTap: onClicked, child: Container( + margin: const EdgeInsets.symmetric(vertical: 5), padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.white, @@ -115,7 +116,7 @@ class AssociationCard extends HookConsumerWidget { Text( association.name, style: const TextStyle( - fontSize: 20, + fontSize: 16, fontWeight: FontWeight.bold, ), ), @@ -124,11 +125,11 @@ class AssociationCard extends HookConsumerWidget { giveMemberRole ? member.memberships .firstWhere((element) => - element.association.id == association.id) + element.associationId == association.id) .apparentName : association.kind, style: const TextStyle( - fontSize: 20, + fontSize: 16, fontWeight: FontWeight.bold, ), ), diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 18792ff13..3a7943a54 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -24,8 +24,9 @@ class PhonebookMainPage extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final isAdmin = ref.watch(isPhonebookAdminProvider); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); - final associationListNotifier = ref.watch(associationListProvider.notifier); - final associationList = ref.watch(associationListProvider); + final associationListNotifier = + ref.watch(asyncAssociationListProvider.notifier); + final associationList = ref.watch(asyncAssociationListProvider); final associationKindsNotifier = ref.watch(associationKindsProvider.notifier); final associationKinds = ref.watch(associationKindsProvider); @@ -83,7 +84,6 @@ class PhonebookMainPage extends HookConsumerWidget { const SizedBox(height: 10), associationKinds.when( data: (data) { - debugPrint("associationKinds.when data: ${data.kinds}"); return SingleChildScrollView( scrollDirection: Axis.horizontal, physics: const BouncingScrollPhysics(), diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart index 132565226..22e0d0c3a 100644 --- a/lib/phonebook/ui/pages/main_page/research_bar.dart +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -15,7 +15,8 @@ class ResearchBar extends HookConsumerWidget { final focusNode = useFocusNode(); final editingController = useTextEditingController(); final filterNotifier = ref.watch(filterProvider.notifier); - final associationsNotifier = ref.watch(associationListProvider.notifier); + final associationsNotifier = + ref.watch(asyncAssociationListProvider.notifier); final associationKind = ref.watch(associationKindProvider); return Expanded( diff --git a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart index a0d3e285a..514a927f9 100644 --- a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart +++ b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/router.dart'; @@ -15,6 +16,7 @@ class MemberDetailPage extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final memberProvider = ref.watch(completeMemberProvider); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); + final associationList = ref.watch(associationListProvider); return PhonebookTemplate( child: Container( margin: const EdgeInsets.all(10), @@ -30,7 +32,7 @@ class MemberDetailPage extends HookConsumerWidget { Text( "${PhonebookTextConstants.nickname} ${memberProvider.member.nickname!}"), Text( - "${PhonebookTextConstants.promotion} ${memberProvider.member.promotion}"), + "${PhonebookTextConstants.promotion} ${memberProvider.member.promotion + 2000}"), Text( "${PhonebookTextConstants.email} ${memberProvider.member.email}"), if (memberProvider.memberships.isNotEmpty) @@ -39,9 +41,12 @@ class MemberDetailPage extends HookConsumerWidget { : PhonebookTextConstants.associations), ...memberProvider.memberships .map((e) => AssociationCard( - association: e.association, + association: associationList.firstWhere( + (association) => association.id == e.associationId), onClicked: () { - associationNotifier.setAssociation(e.association); + associationNotifier.setAssociation( + associationList.firstWhere((association) => + association.id == e.associationId)); QR.to(PhonebookRouter.root + PhonebookRouter.associationDetail); }, diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index e487886b9..c3231250f 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -46,7 +46,7 @@ class MembershipEditorPage extends HookConsumerWidget { if (edition) { apparentNameController.text = member.memberships - .where((e) => e.association.id == association.id) + .where((e) => e.associationId == association.id) .toList()[0] .apparentName; } From 1313318492a1949ac27fe15165ff61403f2e07ca Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:03 +0100 Subject: [PATCH 045/123] Fix redirections --- lib/phonebook/providers/phonebook_admin_provider.dart | 11 +++++++++++ lib/phonebook/router.dart | 1 + lib/phonebook/ui/pages/admin_page/admin_page.dart | 2 +- .../association_editor_page.dart | 2 +- .../ui/pages/association_page/association_page.dart | 1 + 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/phonebook/providers/phonebook_admin_provider.dart b/lib/phonebook/providers/phonebook_admin_provider.dart index a2d3f010a..88bebb4d9 100644 --- a/lib/phonebook/providers/phonebook_admin_provider.dart +++ b/lib/phonebook/providers/phonebook_admin_provider.dart @@ -1,9 +1,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:myecl/user/providers/user_provider.dart'; +import 'package:qlevar_router/qlevar_router.dart'; +import 'package:myecl/phonebook/router.dart'; final isPhonebookAdminProvider = StateProvider((ref) { final user = ref.watch(userProvider); @@ -39,3 +43,10 @@ final isAssociationPresidentProvider = StateProvider((ref) { debugPrint("isPresident: $isPresident"); return isPresident; }); + +final comeFromAdmin = StateProvider((ref) { + if (QR.currentPath == PhonebookRouter.root + PhonebookRouter.admin) { + return true; + } + return false; +}); diff --git a/lib/phonebook/router.dart b/lib/phonebook/router.dart index 7b14fec1c..c87b15117 100644 --- a/lib/phonebook/router.dart +++ b/lib/phonebook/router.dart @@ -60,6 +60,7 @@ class PhonebookRouter { builder: () => const AssociationEditorPage(), middleware: [ AdminMiddleware(ref, isAssociationPresidentProvider), + AdminMiddleware(ref, comeFromAdmin) ], children: [ QRoute( diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 9696ac890..f4e7d45aa 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -5,6 +5,7 @@ import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/providers/phonebook_admin_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/router.dart'; @@ -32,7 +33,6 @@ class AdminPage extends HookConsumerWidget { final kind = useState(''); final kindNotifier = ref.watch(associationKindProvider.notifier); final nameFilter = ref.watch(filterProvider); - void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); } diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 2adc43ab2..5023b8d68 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -10,6 +10,7 @@ import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/providers/edition_provider.dart'; +import 'package:myecl/phonebook/providers/phonebook_admin_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; @@ -45,7 +46,6 @@ class AssociationEditorPage extends HookConsumerWidget { final rolesTagsNotifier = ref.watch(rolesTagsProvider.notifier); final editionNotifier = ref.watch(editionProvider.notifier); final completeMemberNotifier = ref.watch(completeMemberProvider.notifier); - void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); } diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index 376a7cc0a..db2b6d070 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -128,6 +128,7 @@ class AssociationPage extends HookConsumerWidget { child: GestureDetector( onTap: () { QR.to(PhonebookRouter.root + + PhonebookRouter.associationDetail + PhonebookRouter.editAssociation); }, child: Container( From b9c5e301c4aa2997a3ffc5a868cc1082a51188f1 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:03 +0100 Subject: [PATCH 046/123] Member detail UI upgrade --- lib/phonebook/tools/constants.dart | 2 ++ .../association_editor_page.dart | 3 +- .../member_detail_page/element_field.dart | 30 +++++++++++++++++++ .../member_detail_page.dart | 30 ++++++++++++------- 4 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 lib/phonebook/ui/pages/member_detail_page/element_field.dart diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index 038eaee8e..6680d4928 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -97,6 +97,8 @@ class PhonebookTextConstants { static const String updatedMember = "Membre modifié"; static const String validation = "Valider"; + + static const String promoNotGiven = "Promo non renseignée"; } class PhonebookColorConstants { diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 5023b8d68..bc2aef462 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -6,11 +6,10 @@ import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; -import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; +import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/providers/edition_provider.dart'; -import 'package:myecl/phonebook/providers/phonebook_admin_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; diff --git a/lib/phonebook/ui/pages/member_detail_page/element_field.dart b/lib/phonebook/ui/pages/member_detail_page/element_field.dart new file mode 100644 index 000000000..f3401eb40 --- /dev/null +++ b/lib/phonebook/ui/pages/member_detail_page/element_field.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; + +class ElementField extends StatelessWidget { + final String label; + final String value; + const ElementField({Key? key, required this.label, required this.value}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + margin: const EdgeInsets.symmetric(vertical: 2.0), + child: Row( + children: [ + Expanded( + flex: 1, + child: Text( + label, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + Expanded( + flex: 2, + child: Text(value), + ), + ], + ), + ); + } +} diff --git a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart index 514a927f9..84f4191d8 100644 --- a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart +++ b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart @@ -6,6 +6,7 @@ import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/pages/main_page/association_card.dart'; +import 'package:myecl/phonebook/ui/pages/member_detail_page/element_field.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:qlevar_router/qlevar_router.dart'; @@ -24,17 +25,26 @@ class MemberDetailPage extends HookConsumerWidget { decoration: BoxDecoration(borderRadius: BorderRadius.circular(50)), child: Column(children: [ const Text(PhonebookTextConstants.detail), - Text( - "${PhonebookTextConstants.name} ${memberProvider.member.name}"), - Text( - "${PhonebookTextConstants.firstname} ${memberProvider.member.firstname}"), + ElementField( + label: PhonebookTextConstants.name, + value: memberProvider.member.name), + ElementField( + label: PhonebookTextConstants.firstname, + value: memberProvider.member.firstname), if (memberProvider.member.nickname != null) - Text( - "${PhonebookTextConstants.nickname} ${memberProvider.member.nickname!}"), - Text( - "${PhonebookTextConstants.promotion} ${memberProvider.member.promotion + 2000}"), - Text( - "${PhonebookTextConstants.email} ${memberProvider.member.email}"), + ElementField( + label: PhonebookTextConstants.nickname, + value: memberProvider.member.nickname!), + ElementField( + label: PhonebookTextConstants.email, + value: memberProvider.member.email), + ElementField( + label: PhonebookTextConstants.promotion, + value: memberProvider.member.promotion == 0 + ? PhonebookTextConstants.promoNotGiven + : memberProvider.member.promotion < 100 + ? "20${memberProvider.member.promotion}" + : memberProvider.member.promotion.toString()), if (memberProvider.memberships.isNotEmpty) Text(memberProvider.memberships.length == 1 ? PhonebookTextConstants.association From b003fa65d5f81dfb72d92f537745873aaba72f50 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Mon, 26 Feb 2024 15:57:03 +0100 Subject: [PATCH 047/123] UI improvement --- lib/phonebook/class/complete_member.dart | 1 + lib/phonebook/class/member.dart | 10 +- .../providers/association_list_provider.dart | 13 ++ .../association_member_list_provider.dart | 26 ++- .../providers/association_provider.dart | 6 +- .../providers/phonebook_admin_provider.dart | 7 - .../providers/profile_picture_provider.dart | 26 +++ .../providers/profile_pictures_provider.dart | 28 +++ .../repositories/association_repository.dart | 15 +- lib/phonebook/router.dart | 3 +- lib/phonebook/tools/constants.dart | 5 + lib/phonebook/tools/function.dart | 45 ++++ lib/phonebook/ui/copiabled_text.dart | 39 ++++ .../ui/pages/admin_page/admin_page.dart | 93 ++++----- .../association_editor_page.dart | 30 +-- .../member_editable_card.dart | 42 ++-- .../association_page/association_page.dart | 37 +--- .../pages/association_page/member_card.dart | 194 ++++++++++++++---- .../ui/pages/main_page/main_page.dart | 39 ++-- .../member_detail_page/element_field.dart | 51 +++-- .../member_detail_page.dart | 71 ++++--- .../membership_editor_page.dart | 8 +- 22 files changed, 543 insertions(+), 246 deletions(-) create mode 100644 lib/phonebook/providers/profile_picture_provider.dart create mode 100644 lib/phonebook/providers/profile_pictures_provider.dart create mode 100644 lib/phonebook/ui/copiabled_text.dart diff --git a/lib/phonebook/class/complete_member.dart b/lib/phonebook/class/complete_member.dart index 4c8656f23..4b87ab147 100644 --- a/lib/phonebook/class/complete_member.dart +++ b/lib/phonebook/class/complete_member.dart @@ -18,6 +18,7 @@ class CompleteMember { nickname: json['nickname'] ?? "", id: json['id'], email: json['email'], + phone: json['phone'], promotion: json['promo'] ?? 0); memberships = List.from(json['memberships'] .map((membership) => Membership.fromJson(membership))); diff --git a/lib/phonebook/class/member.dart b/lib/phonebook/class/member.dart index c20c21cdc..83c461f10 100644 --- a/lib/phonebook/class/member.dart +++ b/lib/phonebook/class/member.dart @@ -7,13 +7,16 @@ class Member extends SimpleUser { required super.nickname, required super.id, required this.email, + required this.phone, required this.promotion, }); late final String email; + late final String? phone; late final int promotion; Member.fromJson(Map json) : super.fromJson(json) { email = json['email']; + phone = json['phone']; promotion = json['promo'] ?? 0; } @@ -21,6 +24,7 @@ class Member extends SimpleUser { Map toJson() { final Map data = super.toJson(); data['email'] = email; + data['phone'] = phone; data['promotion'] = promotion; return data; } @@ -31,6 +35,7 @@ class Member extends SimpleUser { String? nickname, String? id, String? email, + String? phone, int? promotion, }) { return Member( @@ -39,12 +44,14 @@ class Member extends SimpleUser { nickname: nickname, id: id ?? this.id, email: email ?? this.email, + phone: phone ?? this.phone, promotion: promotion ?? this.promotion, ); } Member.empty() : super.empty() { email = "email.test@empty.useless"; + phone = "00 00 00 00 00"; promotion = 0; } @@ -55,11 +62,12 @@ class Member extends SimpleUser { nickname: user.nickname, id: user.id) { email = ""; + phone = ""; promotion = 0; } @override String toString() { - return 'Member(name: $name, firstname: $firstname, nickname: $nickname, id: $id, email: $email, promotion: $promotion)'; + return 'Member(name: $name, firstname: $firstname, nickname: $nickname, id: $id, email: $email, phone: $phone, promotion: $promotion)'; } } diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index 5aae76dae..85db319f7 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -1,10 +1,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/providers/association_kind_provider.dart'; +import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/repositories/association_repository.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/tools/providers/list_notifier.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; +import 'package:myecl/phonebook/tools/function.dart'; class AssociationListNotifier extends ListNotifier { final AssociationRepository associationRepository = AssociationRepository(); @@ -101,3 +104,13 @@ final associationListProvider = Provider>((ref) { return association.maybeWhen( data: (association) => association, orElse: () => [Association.empty()]); }); + +final associationSortedListProvider = Provider>((ref) { + final associationList = ref.watch(associationListProvider); + final associationKinds = ref.watch(associationKindsProvider); + return associationKinds.maybeWhen( + data: (associationKinds) { + return sortAssociation(associationList, associationKinds); + }, + orElse: () => []); +}); diff --git a/lib/phonebook/providers/association_member_list_provider.dart b/lib/phonebook/providers/association_member_list_provider.dart index 58b68e593..0b3b8886e 100644 --- a/lib/phonebook/providers/association_member_list_provider.dart +++ b/lib/phonebook/providers/association_member_list_provider.dart @@ -3,7 +3,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/repositories/association_member_repository.dart'; +import 'package:myecl/phonebook/tools/function.dart'; import 'package:myecl/tools/providers/list_notifier.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; @@ -16,10 +18,13 @@ class AssociationMemberListNotifier extends ListNotifier { } Future>> loadMembers( - String associationId, String year) async { + String associationId, String year, ref) async { final result = await loadList(() async => associationMemberRepository .getAssociationMemberList(associationId, year)); debugPrint("loadMembers: $result"); + result.whenData((value) { + sortMembers(value, associationId, ref); + }); return result; } } @@ -32,7 +37,24 @@ final associationMemberListProvider = StateNotifierProvider< tokenExpireWrapperAuth(ref, () async { final association = ref.watch(associationProvider); await provider.loadMembers( - association.id, association.mandateYear.toString()); + association.id, association.mandateYear.toString(), ref); }); return provider; }); + +final associationMemberSortedListProvider = + Provider>((ref) { + final association = ref.watch(associationProvider); + final associationMemberList = ref.watch(associationMemberListProvider); + final rolesTags = ref.watch(rolesTagsProvider); + return rolesTags.maybeWhen( + orElse: () => [], + data: (rolesTags) { + return associationMemberList.maybeWhen( + orElse: () => [CompleteMember.empty()], + data: (members) { + return sortMembers( + members, association.id, rolesTags.keys.toList()); + }); + }); +}); diff --git a/lib/phonebook/providers/association_provider.dart b/lib/phonebook/providers/association_provider.dart index 1b4c46a20..4b8817e00 100644 --- a/lib/phonebook/providers/association_provider.dart +++ b/lib/phonebook/providers/association_provider.dart @@ -33,11 +33,11 @@ class AssociationNotifier extends SingleNotifier { association); } - Future updateMember(Association association, Member user, - List rolesTags, String apparentName) async { + Future updateMember(Membership membership, Association association, + Member user, List rolesTags, String apparentName) async { return await update( (association) async => associationRepository.updateMember( - association, user, rolesTags, apparentName), + membership, association, user, rolesTags, apparentName), association); } diff --git a/lib/phonebook/providers/phonebook_admin_provider.dart b/lib/phonebook/providers/phonebook_admin_provider.dart index 88bebb4d9..1a38e4215 100644 --- a/lib/phonebook/providers/phonebook_admin_provider.dart +++ b/lib/phonebook/providers/phonebook_admin_provider.dart @@ -43,10 +43,3 @@ final isAssociationPresidentProvider = StateProvider((ref) { debugPrint("isPresident: $isPresident"); return isPresident; }); - -final comeFromAdmin = StateProvider((ref) { - if (QR.currentPath == PhonebookRouter.root + PhonebookRouter.admin) { - return true; - } - return false; -}); diff --git a/lib/phonebook/providers/profile_picture_provider.dart b/lib/phonebook/providers/profile_picture_provider.dart new file mode 100644 index 000000000..b0c8f2168 --- /dev/null +++ b/lib/phonebook/providers/profile_picture_provider.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/auth/providers/openid_provider.dart'; +import 'package:myecl/tools/providers/single_notifier.dart'; +import 'package:myecl/user/repositories/profile_picture_repository.dart'; + +final profilePictureProvider = + StateNotifierProvider>((ref) { + final token = ref.watch(tokenProvider); + ProfilePictureNotifier notifier = ProfilePictureNotifier(token: token); + return notifier; +}); + +class ProfilePictureNotifier extends SingleNotifier { + final ProfilePictureRepository profilePictureRepository = + ProfilePictureRepository(); + ProfilePictureNotifier({required String token}) + : super(const AsyncLoading()) { + profilePictureRepository.setToken(token); + } + + Future getProfilePicture(String profileId) async { + return Image.memory( + await profilePictureRepository.getProfilePicture(profileId)); + } +} diff --git a/lib/phonebook/providers/profile_pictures_provider.dart b/lib/phonebook/providers/profile_pictures_provider.dart new file mode 100644 index 000000000..efde042a7 --- /dev/null +++ b/lib/phonebook/providers/profile_pictures_provider.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; +import 'package:myecl/tools/providers/map_provider.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; + +class ProfilePictureNotifier extends MapNotifier { + ProfilePictureNotifier() : super(); +} + +final profilePicturesProvider = StateNotifierProvider>>>>((ref) { + ProfilePictureNotifier profilePictureNotifier = ProfilePictureNotifier(); + tokenExpireWrapperAuth(ref, () async { + ref.watch(associationMemberListProvider).maybeWhen(data: (profile) { + profilePictureNotifier.loadTList(profile); + for (final l in profile) { + profilePictureNotifier.setTData(l, const AsyncValue.data([])); + } + return profilePictureNotifier; + }, orElse: () { + profilePictureNotifier.loadTList([]); + return profilePictureNotifier; + }); + }); + return profilePictureNotifier; +}); diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index 1841ab622..afad1c45d 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -1,3 +1,4 @@ +import 'package:flutter/material.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/association_kinds.dart'; import 'package:myecl/phonebook/class/member.dart'; @@ -44,14 +45,18 @@ class AssociationRepository extends Repository { return await delete("memberships/${membership.id}"); } - Future updateMember(Association association, Member member, - List rolesTags, String apparentName) async { + Future updateMember(Membership membership, Association association, + Member member, List rolesTags, String apparentName) async { + debugPrint( + "updateMembership :\n id : ${membership.id}\n member_id : ${member.id}\n association_id : ${association.id}\n role_tags : ${rolesTags.join(";")}\n role_name : $apparentName"); + return await update({ + "id": membership.id, "member_id": member.id, "association_id": association.id, - "rolesTags": rolesTags, - "apparentName": apparentName - }, association.id, suffix: "memberships"); + "role_tags": rolesTags.join(";"), + "role_name": apparentName + }, "memberships/", suffix: membership.id); } Future getAssociationKinds() async { diff --git a/lib/phonebook/router.dart b/lib/phonebook/router.dart index c87b15117..424e37ee7 100644 --- a/lib/phonebook/router.dart +++ b/lib/phonebook/router.dart @@ -59,8 +59,7 @@ class PhonebookRouter { path: editAssociation, builder: () => const AssociationEditorPage(), middleware: [ - AdminMiddleware(ref, isAssociationPresidentProvider), - AdminMiddleware(ref, comeFromAdmin) + AdminMiddleware(ref, isAssociationPresidentProvider) ], children: [ QRoute( diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index 6680d4928..339147f29 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -24,6 +24,7 @@ class PhonebookTextConstants { static const String changeMandate = "Passer au mandat "; static const String changeMandateConfirm = "Êtes-vous sûr de vouloir changer tout le mandat ?\nCette action est irréversible !"; + static const String copied = "Copié dans le presse-papier"; static const String detail = "Détail :"; static const String deleteAssociation = "Supprimer l'association ?"; @@ -36,6 +37,7 @@ class PhonebookTextConstants { static const String edit = "Modifier"; static const String editMembership = "Modifier le rôle"; static const String email = "Email :"; + static const String emailCopied = "Email copié dans le presse-papier"; static const String emptyApparentName = "Veuillez entrer un nom de role"; static const String emptyFieldError = "Un champ n'est pas rempli"; static const String emptyKindError = "Veuillez choisir un type d'association"; @@ -70,11 +72,14 @@ class PhonebookTextConstants { static const String membershipRoleError = "Veuillez choisir un rôle"; static const String name = "Nom :"; + static const String nameCopied = "Nom et prénom copié dans le presse-papier"; static const String namePure = "Nom"; static const String newMandate = "Nouveau mandat"; static const String newMandateConfirmed = "Mandat changé"; static const String nickname = "Surnom :"; + static const String nicknameCopied = "Surnom copié dans le presse-papier"; + static const String phone = "Téléphone :"; static const String phonebook = "Annuaire"; static const String phonebookSearch = "Rechercher"; static const String phonebookSearchAssociation = "Association"; diff --git a/lib/phonebook/tools/function.dart b/lib/phonebook/tools/function.dart index 0b761e8ce..a45a14baa 100644 --- a/lib/phonebook/tools/function.dart +++ b/lib/phonebook/tools/function.dart @@ -1,4 +1,10 @@ +import 'package:flutter/foundation.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/class/association_kinds.dart'; +import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/membership.dart'; +import 'package:myecl/phonebook/class/roles_tags.dart'; String nameConstructor(Map>> data) { String name = ''; @@ -16,3 +22,42 @@ String nameConstructor(Map>> data) { } return name.substring(0, name.length - 1); } + +List sortMembers(List members, + String associationId, List rolesTags) { + List sorted = []; + List> sortedByRole = + List.generate(rolesTags.length, (index) => []); + for (CompleteMember member in members) { + Membership membership = member.memberships + .firstWhere((element) => element.associationId == associationId); + List memberRoleTags = membership.rolesTags; + int highestPosition = 1000; + for (String roleTag in memberRoleTags) { + int position = rolesTags.indexOf(roleTag); + if (position < highestPosition) { + highestPosition = position; + } + } + sortedByRole[highestPosition].add(member); + } + for (List list in sortedByRole) { + sorted.addAll(list); + } + return sorted; +} + +List sortAssociation( + List associations, AssociationKinds kinds) { + List sorted = []; + List> sortedByKind = + List.generate(kinds.kinds.length, (index) => []); + for (Association association in associations) { + sortedByKind[kinds.kinds.indexOf(association.kind)].add(association); + } + for (List list in sortedByKind) { + list.sort((a, b) => a.name.compareTo(b.name)); + sorted.addAll(list); + } + return sorted; +} diff --git a/lib/phonebook/ui/copiabled_text.dart b/lib/phonebook/ui/copiabled_text.dart new file mode 100644 index 000000000..2ad9afa3c --- /dev/null +++ b/lib/phonebook/ui/copiabled_text.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/tools/functions.dart'; + +class CopiabledText extends StatelessWidget { + const CopiabledText( + {Key? key, + required this.data, + required this.style, + required this.flex, + this.maxLines = 1}) + : super(key: key); + + final String data; + final TextStyle style; + final int flex; + final int maxLines; + + @override + Widget build(BuildContext context) { + void displayToastWithContext(TypeMsg type, String msg) { + displayToast(context, type, msg); + } + + return Expanded( + flex: flex, + child: Center( + child: SelectableText( + data, + maxLines: maxLines, + style: style, + onTap: () { + Clipboard.setData(ClipboardData(text: data)); + displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.copied); + }, + ))); + } +} diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index f4e7d45aa..9dd49bdb8 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -27,7 +27,7 @@ class AdminPage extends HookConsumerWidget { final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationsNotifier = ref.watch(asyncAssociationListProvider.notifier); - final associations = ref.watch(asyncAssociationListProvider); + final associations = ref.watch(associationSortedListProvider); final roleNotifier = ref.watch(rolesTagsProvider.notifier); final associationKinds = ref.watch(associationKindsProvider); final kind = useState(''); @@ -112,59 +112,48 @@ class AdminPage extends HookConsumerWidget { child: Icon(Icons.add, color: Colors.black, size: 40))), ), - ...associations.when( - data: (associations) { - return associations - .map((association) => EditableAssociationCard( - association: association, - onEdit: () { - associationNotifier - .setAssociation(association); - QR.to(PhonebookRouter.root + - PhonebookRouter.admin + - PhonebookRouter.editAssociation); - }, - onDelete: () async { - await showDialog( - context: context, - builder: (context) { - return CustomDialogBox( - title: - PhonebookTextConstants.deleting, - descriptions: PhonebookTextConstants - .deleteAssociation, - onYes: () async { - final result = - await associationsNotifier - .deleteAssociation( - association); - if (result) { - displayToastWithContext( - TypeMsg.msg, - PhonebookTextConstants - .deletedAssociation); - } else { - displayToastWithContext( - TypeMsg.error, - PhonebookTextConstants - .deletingError); - } - associationsNotifier - .loadAssociations(); - }, - ); + if (associations.isEmpty) + const Center(child: CircularProgressIndicator()) + else + ...associations + .map((association) => EditableAssociationCard( + association: association, + onEdit: () { + associationNotifier.setAssociation(association); + QR.to(PhonebookRouter.root + + PhonebookRouter.admin + + PhonebookRouter.editAssociation); + }, + onDelete: () async { + await showDialog( + context: context, + builder: (context) { + return CustomDialogBox( + title: PhonebookTextConstants.deleting, + descriptions: PhonebookTextConstants + .deleteAssociation, + onYes: () async { + final result = + await associationsNotifier + .deleteAssociation(association); + if (result) { + displayToastWithContext( + TypeMsg.msg, + PhonebookTextConstants + .deletedAssociation); + } else { + displayToastWithContext( + TypeMsg.error, + PhonebookTextConstants + .deletingError); + } + associationsNotifier.loadAssociations(); }, ); - })) - .toList(); - }, - loading: () => - const [Center(child: CircularProgressIndicator())], - error: (error, stack) => [ - const Center( - child: Text(PhonebookTextConstants - .errorLoadAssociationList)) - ]) + }, + ); + })) + .toList() ], ), ), diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index bc2aef462..319e838b1 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -33,7 +33,8 @@ class AssociationEditorPage extends HookConsumerWidget { final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); - final associationMemberList = ref.watch(associationMemberListProvider); + final associationMemberList = + ref.watch(associationMemberSortedListProvider); final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); final associationListNotifier = @@ -53,7 +54,7 @@ class AssociationEditorPage extends HookConsumerWidget { child: Refresher( onRefresh: () async { await associationMemberListNotifier.loadMembers( - association.id, association.mandateYear.toString()); + association.id, association.mandateYear.toString(), ref); await associationPictureNotifier.getAssociationPicture(association.id); }, child: Column(children: [ @@ -308,23 +309,14 @@ class AssociationEditorPage extends HookConsumerWidget { ], ), ), - ...associationMemberList.when( - data: (data) { - return data - .map((member) => MemberEditableCard(member: member)) - .toList(); - }, - error: (error, stackTrace) { - return const [ - Text(PhonebookTextConstants.errorLoadAssociationMember), - ]; - }, - loading: () => [ - const Center( - child: CircularProgressIndicator(), - ), - ], - ), + if (associationMemberList.isEmpty) + const Center( + child: CircularProgressIndicator(), + ) + else if (associationMemberList.first.member.id != '') + ...associationMemberList + .map((member) => MemberEditableCard(member: member)) + .toList(), const SizedBox( height: 10, ), diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index 78d3cff9c..63b4bd774 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -1,3 +1,4 @@ +import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; @@ -34,7 +35,7 @@ class MemberEditableCard extends HookConsumerWidget { } return Container( - padding: const EdgeInsets.all(10), + padding: const EdgeInsets.all(5), margin: const EdgeInsets.symmetric(horizontal: 30, vertical: 10), decoration: BoxDecoration( border: Border.all(), @@ -77,38 +78,26 @@ class MemberEditableCard extends HookConsumerWidget { ), ), const SizedBox(width: 10), - SizedBox( - width: 400, - child: Column( - children: [ - Text( - member.member.getName(), - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 5), - Text( - member.member.email, - style: const TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - ), - ), - ], + AutoSizeText( + member.member.getName(), + style: const TextStyle( + fontWeight: FontWeight.bold, ), + maxLines: 2, + minFontSize: 10, + maxFontSize: 15, ), const Spacer(), - Text( + AutoSizeText( member.memberships .firstWhere( (element) => element.associationId == association.id) .apparentName, style: const TextStyle( - fontSize: 20, fontWeight: FontWeight.bold, - )), + ), + minFontSize: 10, + maxFontSize: 15), const Spacer(), EditionButton(onEdition: () async { roleTagsNotifier.resetChecked(); @@ -122,11 +111,12 @@ class MemberEditableCard extends HookConsumerWidget { PhonebookRouter.addEditMember); } else { QR.to(PhonebookRouter.root + + PhonebookRouter.associationDetail + PhonebookRouter.editAssociation + PhonebookRouter.addEditMember); } }), - const SizedBox(width: 10), + const SizedBox(width: 5), DeleteButton( onDelete: () async { final result = await associationNotifier.deleteMember( @@ -134,7 +124,7 @@ class MemberEditableCard extends HookConsumerWidget { (element) => element.associationId == association.id), association); await associationMembersNotifier.loadMembers( - association.id, association.mandateYear.toString()); + association.id, association.mandateYear.toString(), ref); if (result) { displayToastWithContext( TypeMsg.msg, PhonebookTextConstants.deletedMember); diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index db2b6d070..97e47ba36 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -19,7 +19,8 @@ class AssociationPage extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final association = ref.watch(associationProvider); final associationPicture = ref.watch(associationPictureProvider); - final associationMemberList = ref.watch(associationMemberListProvider); + final associationMemberList = + ref.watch(associationMemberSortedListProvider); final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); final associationPictureNotifier = @@ -30,17 +31,12 @@ class AssociationPage extends HookConsumerWidget { child: Refresher( onRefresh: () async { await associationMemberListNotifier.loadMembers( - association.id, association.mandateYear.toString()); + association.id, association.mandateYear.toString(), ref); await associationPictureNotifier .getAssociationPicture(association.id); }, child: Stack(children: [ Column(children: [ - const Text(PhonebookTextConstants.associationDetail, - style: TextStyle(fontSize: 30)), - const SizedBox( - height: 20, - ), Container( decoration: BoxDecoration( shape: BoxShape.circle, @@ -101,25 +97,14 @@ class AssociationPage extends HookConsumerWidget { const SizedBox( height: 20, ), - associationMemberList.when( - data: (members) { - return Column( - children: members - .map((member) => MemberCard(member: member)) - .toList()); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: Text( - PhonebookTextConstants.errorLoadAssociationMember), - ); - }, - ) + if (associationMemberList.isEmpty) + const Center( + child: CircularProgressIndicator(), + ) + else + ...associationMemberList + .map((member) => MemberCard(member: member)) + .toList() ]), if (isPresident) Positioned( diff --git a/lib/phonebook/ui/pages/association_page/member_card.dart b/lib/phonebook/ui/pages/association_page/member_card.dart index 1c9e0738a..6e35676a9 100644 --- a/lib/phonebook/ui/pages/association_page/member_card.dart +++ b/lib/phonebook/ui/pages/association_page/member_card.dart @@ -1,9 +1,17 @@ +import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/providers/profile_pictures_provider.dart'; import 'package:myecl/phonebook/router.dart'; -import 'package:myecl/user/providers/profile_picture_provider.dart'; +import 'package:myecl/phonebook/ui/copiabled_text.dart'; +import 'package:myecl/tools/functions.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; +import 'package:myecl/phonebook/providers/profile_picture_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:qlevar_router/qlevar_router.dart'; @@ -16,24 +24,29 @@ class MemberCard extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final memberNotifier = ref.watch(completeMemberProvider.notifier); - final profilePicture = ref.watch(profilePictureProvider); final association = ref.watch(associationProvider); + final profilePictures = ref.watch(profilePicturesProvider); + final profilePicturesNotifier = ref.watch(profilePicturesProvider.notifier); final profilePictureNotifier = ref.watch(profilePictureProvider.notifier); return GestureDetector( onTap: () { memberNotifier.setCompleteMember(member); QR.to(PhonebookRouter.root + PhonebookRouter.memberDetail); - profilePictureNotifier.getProfilePicture(member.member.id); }, child: Container( - margin: const EdgeInsets.all(10), + margin: const EdgeInsets.all(5), padding: const EdgeInsets.all(10), decoration: BoxDecoration( - border: Border.all(), - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(20)), - ), + color: Colors.white, + border: Border.all(color: Colors.grey.withOpacity(0.2)), + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 5, + spreadRadius: 2) + ]), child: Row( children: [ Container( @@ -48,18 +61,67 @@ class MemberCard extends HookConsumerWidget { ), ], ), - child: profilePicture.when( + child: profilePictures.when( data: (picture) { - return CircleAvatar( - radius: 20, - backgroundImage: picture.isEmpty - ? const AssetImage('assets/images/logo_alpha.png') - : Image.memory(picture).image, - ); + if (picture[member] != null) { + return picture[member]!.when(data: (data) { + if (data.isNotEmpty) { + return Container( + width: 40, + height: 40, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: data.first.image, + fit: BoxFit.cover, + ), + ), + ); + } else { + Future.delayed( + const Duration(milliseconds: 1), + () => profilePicturesNotifier.setTData( + member, const AsyncLoading())); + tokenExpireWrapper(ref, () async { + profilePictureNotifier + .getProfilePicture(member.member.id) + .then((value) { + profilePicturesNotifier.setTData( + member, AsyncData([value])); + }); + }); + return const HeroIcon( + HeroIcons.userCircle, + size: 40, + ); + } + }, loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, error: (e, s) { + return const Center( + child: Text( + PhonebookTextConstants.errorLoadProfilePicture), + ); + }); + } else { + profilePicturesNotifier.setTData( + member, const AsyncValue.data([])); + profilePictureNotifier + .getProfilePicture(member.member.id); + return const CircleAvatar( + radius: 20, + backgroundImage: + AssetImage('assets/images/logo_alpha.png'), + ); + } }, loading: () { - return const Center( - child: CircularProgressIndicator(), + return const CircleAvatar( + radius: 20, + backgroundImage: + AssetImage('assets/images/logo_alpha.png'), ); }, error: (e, s) { @@ -70,39 +132,95 @@ class MemberCard extends HookConsumerWidget { }, ), ), - const SizedBox(width: 10), - SizedBox( - child: Column( - children: [ - Text( - member.member.getName(), + const SizedBox(width: 20), + if (kIsWeb) ...[ + if (member.member.nickname != null) + CopiabledText( + data: member.member.nickname!, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + flex: 1, + ), + CopiabledText( + data: "${member.member.name} ${member.member.firstname}", + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + color: member.member.nickname != null + ? const Color.fromARGB(255, 115, 115, 115) + : Colors.black, + ), + flex: 1, + ), + CopiabledText( + data: member.member.email, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + flex: 1), + if (member.member.phone != null) + CopiabledText( + data: member.member.phone!, style: const TextStyle( - fontSize: 20, fontWeight: FontWeight.bold, + fontSize: 16, ), + flex: 1), + CopiabledText( + data: member.memberships + .firstWhere((element) => + element.associationId == association.id) + .apparentName, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, ), - const SizedBox(height: 5), - Text( - member.member.email, - style: const TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, + flex: 1) + ] else ...[ + if (member.member.nickname != null) + Column( + children: [ + Text( + member.member.nickname!, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), ), + const SizedBox(height: 5), + Text( + "${member.member.name} ${member.member.firstname}", + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + color: Color.fromARGB(255, 115, 115, 115), + ), + ), + ], + ) + else + Text( + "${member.member.name} ${member.member.firstname}", + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, ), - ], - ), - ), - const Spacer(), - Text( + ), + const Spacer(flex: 1), + Text( member.memberships .firstWhere((element) => element.associationId == association.id) .apparentName, style: const TextStyle( - fontSize: 20, fontWeight: FontWeight.bold, - )), - const Spacer(), + fontSize: 16, + ), + ), + ], ], ))); } diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 3a7943a54..335b02979 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -26,7 +26,7 @@ class PhonebookMainPage extends HookConsumerWidget { final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationListNotifier = ref.watch(asyncAssociationListProvider.notifier); - final associationList = ref.watch(asyncAssociationListProvider); + final associationList = ref.watch(associationSortedListProvider); final associationKindsNotifier = ref.watch(associationKindsProvider.notifier); final associationKinds = ref.watch(associationKindsProvider); @@ -121,27 +121,22 @@ class PhonebookMainPage extends HookConsumerWidget { const Text(PhonebookTextConstants.errorKindsLoading), loading: () => const CircularProgressIndicator()), const SizedBox(height: 30), - ...associationList.when( - data: (associations) { - return associations - .map((association) => AssociationCard( - association: association, - onClicked: () { - associationNotifier.setAssociation(association); - QR.to(PhonebookRouter.root + - PhonebookRouter.associationDetail); - }, - giveMemberRole: false, - )) - .toList(); - }, - loading: () => - const [Center(child: CircularProgressIndicator())], - error: (error, stack) => [ - const Center( - child: Text(PhonebookTextConstants - .errorLoadAssociationList)) - ]) + if (associationList.isEmpty) + const Center( + child: CircularProgressIndicator(), + ) + else + ...associationList + .map((association) => AssociationCard( + association: association, + onClicked: () { + associationNotifier.setAssociation(association); + QR.to(PhonebookRouter.root + + PhonebookRouter.associationDetail); + }, + giveMemberRole: false, + )) + .toList() ]))); } } diff --git a/lib/phonebook/ui/pages/member_detail_page/element_field.dart b/lib/phonebook/ui/pages/member_detail_page/element_field.dart index f3401eb40..7250bfc96 100644 --- a/lib/phonebook/ui/pages/member_detail_page/element_field.dart +++ b/lib/phonebook/ui/pages/member_detail_page/element_field.dart @@ -1,4 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/tools/functions.dart'; class ElementField extends StatelessWidget { final String label; @@ -8,23 +11,37 @@ class ElementField extends StatelessWidget { @override Widget build(BuildContext context) { + void displayToastWithContext(TypeMsg type, String msg) { + displayToast(context, type, msg); + } + return Container( - margin: const EdgeInsets.symmetric(vertical: 2.0), - child: Row( - children: [ - Expanded( - flex: 1, - child: Text( - label, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - ), - Expanded( - flex: 2, - child: Text(value), - ), - ], - ), - ); + margin: const EdgeInsets.symmetric(vertical: 5.0), + child: Row( + children: [ + Expanded( + flex: 1, + child: Center( + child: Text( + label, + style: const TextStyle( + fontWeight: FontWeight.bold, fontSize: 16), + ))), + Expanded( + flex: 4, + child: Center( + child: SelectableText( + value, + maxLines: 1, + style: const TextStyle( + fontWeight: FontWeight.bold, fontSize: 16), + onTap: () { + Clipboard.setData(ClipboardData(text: value)); + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.copied); + }, + ))), + ], + )); } } diff --git a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart index 84f4191d8..736791b21 100644 --- a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart +++ b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart @@ -24,31 +24,54 @@ class MemberDetailPage extends HookConsumerWidget { width: MediaQuery.of(context).size.width, decoration: BoxDecoration(borderRadius: BorderRadius.circular(50)), child: Column(children: [ - const Text(PhonebookTextConstants.detail), - ElementField( - label: PhonebookTextConstants.name, - value: memberProvider.member.name), - ElementField( - label: PhonebookTextConstants.firstname, - value: memberProvider.member.firstname), - if (memberProvider.member.nickname != null) - ElementField( - label: PhonebookTextConstants.nickname, - value: memberProvider.member.nickname!), - ElementField( - label: PhonebookTextConstants.email, - value: memberProvider.member.email), - ElementField( - label: PhonebookTextConstants.promotion, - value: memberProvider.member.promotion == 0 - ? PhonebookTextConstants.promoNotGiven - : memberProvider.member.promotion < 100 - ? "20${memberProvider.member.promotion}" - : memberProvider.member.promotion.toString()), + Container( + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: Colors.grey.withOpacity(0.2)), + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 5, + spreadRadius: 2) + ]), + child: Column(children: [ + ElementField( + label: PhonebookTextConstants.name, + value: memberProvider.member.name), + ElementField( + label: PhonebookTextConstants.firstname, + value: memberProvider.member.firstname), + if (memberProvider.member.nickname != null) + ElementField( + label: PhonebookTextConstants.nickname, + value: memberProvider.member.nickname!), + ElementField( + label: PhonebookTextConstants.email, + value: memberProvider.member.email), + if (memberProvider.member.phone != null) + ElementField( + label: PhonebookTextConstants.phone, + value: memberProvider.member.phone!), + ElementField( + label: PhonebookTextConstants.promotion, + value: memberProvider.member.promotion == 0 + ? PhonebookTextConstants.promoNotGiven + : memberProvider.member.promotion < 100 + ? "20${memberProvider.member.promotion}" + : memberProvider.member.promotion.toString()), + ]), + ), + const SizedBox( + height: 20, + ), if (memberProvider.memberships.isNotEmpty) - Text(memberProvider.memberships.length == 1 - ? PhonebookTextConstants.association - : PhonebookTextConstants.associations), + Text( + memberProvider.memberships.length == 1 + ? PhonebookTextConstants.association + : PhonebookTextConstants.associations, + style: const TextStyle( + fontWeight: FontWeight.bold, fontSize: 20)), ...memberProvider.memberships .map((e) => AssociationCard( association: associationList.firstWhere( diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index c3231250f..fef7f0e6e 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -160,6 +160,8 @@ class MembershipEditorPage extends HookConsumerWidget { tokenExpireWrapper(ref, () async { if (edition) { final value = await associationNotifier.updateMember( + member.memberships.firstWhere((element) => + element.associationId == association.id), association, member.member, memberRoleTags, @@ -167,7 +169,8 @@ class MembershipEditorPage extends HookConsumerWidget { if (value) { associationMemberListNotifier.loadMembers( association.id, - association.mandateYear.toString()); + association.mandateYear.toString(), + ref); displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.updatedMember); QR.back(); @@ -184,7 +187,8 @@ class MembershipEditorPage extends HookConsumerWidget { if (value) { associationMemberListNotifier.loadMembers( association.id, - association.mandateYear.toString()); + association.mandateYear.toString(), + ref); displayToastWithContext( TypeMsg.msg, PhonebookTextConstants.addedMember); QR.back(); From ee0991b192bfcc91d94e039cfb4d704858c0f07a Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:04 +0100 Subject: [PATCH 048/123] feat: updating libraries --- pubspec.lock | 48 ++++++++---------------------------------------- 1 file changed, 8 insertions(+), 40 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 4ce9cdd63..cd1300126 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -701,30 +701,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" - url: "https://pub.dev" - source: hosted - version: "10.0.0" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 - url: "https://pub.dev" - source: hosted - version: "2.0.1" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 - url: "https://pub.dev" - source: hosted - version: "2.0.1" lints: dependency: transitive description: @@ -753,26 +729,26 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.5.0" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.10.0" mime: dependency: transitive description: @@ -825,10 +801,10 @@ packages: dependency: "direct main" description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.8.3" path_parsing: dependency: transitive description: @@ -1242,14 +1218,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 - url: "https://pub.dev" - source: hosted - version: "13.0.0" web: dependency: transitive description: From 3f54bdfcabb779e5a92e3fcb9e4d5c5784e8138f Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:04 +0100 Subject: [PATCH 049/123] feat: correcting refresher import --- lib/phonebook/ui/pages/admin_page/admin_page.dart | 4 ++-- .../association_editor_page/association_editor_page.dart | 2 +- lib/phonebook/ui/pages/association_page/association_page.dart | 2 +- lib/phonebook/ui/pages/main_page/main_page.dart | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 9dd49bdb8..aac52b1b3 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -15,8 +15,8 @@ import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/association_research_bar.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/editable_association_card.dart'; import 'package:myecl/tools/functions.dart'; -import 'package:myecl/tools/ui/dialog.dart'; -import 'package:myecl/tools/ui/refresher.dart'; +import 'package:myecl/tools/ui/layouts/refresher.dart'; +import 'package:myecl/tools/ui/widgets/dialog.dart'; import 'package:qlevar_router/qlevar_router.dart'; class AdminPage extends HookConsumerWidget { diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 319e838b1..348ca0b50 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -19,7 +19,7 @@ import 'package:myecl/phonebook/ui/pages/association_editor_page/member_editable import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; -import 'package:myecl/tools/ui/refresher.dart'; +import 'package:myecl/tools/ui/layouts/refresher.dart'; import 'package:myecl/tools/ui/shrink_button.dart'; import 'package:qlevar_router/qlevar_router.dart'; diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index 97e47ba36..9de9ff177 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -9,7 +9,7 @@ import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/pages/association_page/member_card.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; -import 'package:myecl/tools/ui/refresher.dart'; +import 'package:myecl/tools/ui/layouts/refresher.dart'; import 'package:qlevar_router/qlevar_router.dart'; class AssociationPage extends HookConsumerWidget { diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 335b02979..6e2650324 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -14,7 +14,7 @@ import 'package:myecl/phonebook/ui/pages/main_page/association_card.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/phonebook/ui/pages/main_page/research_bar.dart'; -import 'package:myecl/tools/ui/refresher.dart'; +import 'package:myecl/tools/ui/layouts/refresher.dart'; import 'package:qlevar_router/qlevar_router.dart'; class PhonebookMainPage extends HookConsumerWidget { From 7596062b571b6dc1aefdf08207dffdca9ea2ffb3 Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:04 +0100 Subject: [PATCH 050/123] fix: using WaitingButton --- .../ui/pages/admin_page/delete_button.dart | 45 +--- .../association_creation_page.dart | 50 +---- .../association_editor_page.dart | 200 +++++++----------- .../membership_editor_page.dart | 5 +- 4 files changed, 94 insertions(+), 206 deletions(-) diff --git a/lib/phonebook/ui/pages/admin_page/delete_button.dart b/lib/phonebook/ui/pages/admin_page/delete_button.dart index 62f736fae..40aedfbe1 100644 --- a/lib/phonebook/ui/pages/admin_page/delete_button.dart +++ b/lib/phonebook/ui/pages/admin_page/delete_button.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:heroicons/heroicons.dart'; import 'package:myecl/tools/constants.dart'; -import 'package:myecl/tools/ui/shrink_button.dart'; +import 'package:myecl/tools/ui/builders/waiting_button.dart'; class DeleteButton extends StatelessWidget { final Future Function() onDelete; @@ -10,8 +10,8 @@ class DeleteButton extends StatelessWidget { @override Widget build(BuildContext context) { - return ShrinkButton( - waitChild: Container( + return WaitingButton( + builder: (child) => Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( gradient: const LinearGradient( @@ -31,37 +31,12 @@ class DeleteButton extends StatelessWidget { ], borderRadius: BorderRadius.circular(10), ), - child: const Center( - child: CircularProgressIndicator( - color: Colors.white, - ), - ), - ), - onTap: onDelete, - child: Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.3), - blurRadius: 10, - offset: const Offset(2, 3), - ), - ], - borderRadius: BorderRadius.circular(10), - ), - child: const HeroIcon( - HeroIcons.xMark, - color: Colors.white, - ), - )); + child: child), + onTap: onDelete, + child: const HeroIcon( + HeroIcons.xMark, + color: Colors.white, + ), + ); } } diff --git a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart index 00ef1ef00..8b46f6794 100644 --- a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart +++ b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart @@ -14,7 +14,7 @@ import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; -import 'package:myecl/tools/ui/shrink_button.dart'; +import 'package:myecl/tools/ui/builders/waiting_button.dart'; import 'package:qlevar_router/qlevar_router.dart'; class AssociationCreationPage extends HookConsumerWidget { @@ -104,8 +104,8 @@ class AssociationCreationPage extends HookConsumerWidget { controller: description, title: AdminTextConstants.description, canBeEmpty: true), - ShrinkButton( - waitChild: Container( + WaitingButton( + builder: (child) => Container( width: double.infinity, margin: const EdgeInsets.symmetric(vertical: 20), padding: const EdgeInsets.symmetric(vertical: 15), @@ -128,13 +128,7 @@ class AssociationCreationPage extends HookConsumerWidget { ], borderRadius: BorderRadius.circular(15), ), - child: const SizedBox( - height: 20, - width: 20, - child: CircularProgressIndicator( - color: Colors.white, - ), - ), + child: child, ), onTap: () async { if (!key.currentState!.validate()) { @@ -174,36 +168,12 @@ class AssociationCreationPage extends HookConsumerWidget { } }); }, - child: Container( - width: double.infinity, - margin: const EdgeInsets.symmetric(vertical: 20), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - ), - boxShadow: [ - BoxShadow( - color: - ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, - ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: const Text( - AdminTextConstants.add, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color.fromARGB(255, 255, 255, 255), - ), + child: const Text( + AdminTextConstants.add, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), ), ), ), diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 348ca0b50..fcdc92c86 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -19,8 +19,8 @@ import 'package:myecl/phonebook/ui/pages/association_editor_page/member_editable import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; +import 'package:myecl/tools/ui/builders/waiting_button.dart'; import 'package:myecl/tools/ui/layouts/refresher.dart'; -import 'package:myecl/tools/ui/shrink_button.dart'; import 'package:qlevar_router/qlevar_router.dart'; class AssociationEditorPage extends HookConsumerWidget { @@ -179,37 +179,31 @@ class AssociationEditorPage extends HookConsumerWidget { ), ], )), - ShrinkButton( - waitChild: Container( - width: double.infinity, - margin: const EdgeInsets.symmetric(vertical: 20), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, + WaitingButton( + builder: (child) => Container( + width: double.infinity, + margin: const EdgeInsets.symmetric(vertical: 20), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: const SizedBox( - height: 20, - width: 20, - child: CircularProgressIndicator( - color: Colors.white, + boxShadow: [ + BoxShadow( + color: + ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), + ], + borderRadius: BorderRadius.circular(15), ), - ), - ), + child: child), onTap: () async { if (!key.currentState!.validate()) { return; @@ -234,35 +228,12 @@ class AssociationEditorPage extends HookConsumerWidget { } }); }, - child: Container( - width: double.infinity, - margin: const EdgeInsets.symmetric(vertical: 20), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, - ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: const Text( - PhonebookTextConstants.edit, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color.fromARGB(255, 255, 255, 255), - ), + child: const Text( + PhonebookTextConstants.edit, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), ), ), ) @@ -276,7 +247,16 @@ class AssociationEditorPage extends HookConsumerWidget { children: [ const Text(PhonebookTextConstants.members), const Spacer(), - ShrinkButton( + WaitingButton( + builder: (child) => Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: ColorConstants.gradient1, + borderRadius: BorderRadius.circular(10), + ), + child: child, + ), onTap: () async { rolesTagsNotifier.resetChecked(); completeMemberNotifier @@ -293,17 +273,9 @@ class AssociationEditorPage extends HookConsumerWidget { PhonebookRouter.addEditMember); } }, - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: ColorConstants.gradient1, - borderRadius: BorderRadius.circular(10), - ), - child: const Icon( - Icons.add, - color: Colors.white, - ), + child: const Icon( + Icons.add, + color: Colors.white, ), ), ], @@ -320,37 +292,30 @@ class AssociationEditorPage extends HookConsumerWidget { const SizedBox( height: 10, ), - ShrinkButton( - waitChild: Container( - width: double.infinity, - margin: const EdgeInsets.all(30), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, + WaitingButton( + builder: (child) => Container( + width: double.infinity, + margin: const EdgeInsets.all(30), + padding: const EdgeInsets.symmetric(vertical: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: const SizedBox( - height: 20, - width: 20, - child: CircularProgressIndicator( - color: Colors.white, + boxShadow: [ + BoxShadow( + color: ColorConstants.gradient2.withOpacity(0.5), + blurRadius: 5, + offset: const Offset(2, 2), + spreadRadius: 2, + ), + ], + borderRadius: BorderRadius.circular(15), ), - ), - ), + child: child), onTap: () async { showDialog( context: context, @@ -390,35 +355,12 @@ class AssociationEditorPage extends HookConsumerWidget { ), ); }, - child: Container( - width: double.infinity, - margin: const EdgeInsets.all(30), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, - ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: Text( - "${PhonebookTextConstants.changeMandate} ${association.mandateYear + 1}", - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color.fromARGB(255, 255, 255, 255), - ), + child: Text( + "${PhonebookTextConstants.changeMandate} ${association.mandateYear + 1}", + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), ), ), ) diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index fef7f0e6e..0cd1e9452 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -13,7 +13,7 @@ import 'package:myecl/phonebook/tools/function.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; -import 'package:myecl/tools/ui/shrink_button.dart'; +import 'package:myecl/tools/ui/builders/waiting_button.dart'; import 'package:myecl/user/providers/user_list_provider.dart'; import 'package:qlevar_router/qlevar_router.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; @@ -137,7 +137,8 @@ class MembershipEditorPage extends HookConsumerWidget { controller: apparentNameController, ), const SizedBox(height: 5), - ShrinkButton( + WaitingButton( + builder: (child) => child, child: Text(!edition ? PhonebookTextConstants.add : PhonebookTextConstants.edit), From 61b186e72ca1b9bb85201242e9440593fdec2b08 Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:04 +0100 Subject: [PATCH 051/123] feat: using HorizontalListView and ItemChip --- .../ui/pages/main_page/main_page.dart | 69 ++++++++++--------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 6e2650324..5ab226f63 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -14,6 +14,9 @@ import 'package:myecl/phonebook/ui/pages/main_page/association_card.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/phonebook/ui/pages/main_page/research_bar.dart'; +import 'package:myecl/tools/functions.dart'; +import 'package:myecl/tools/ui/layouts/horizontal_list_view.dart'; +import 'package:myecl/tools/ui/layouts/item_chip.dart'; import 'package:myecl/tools/ui/layouts/refresher.dart'; import 'package:qlevar_router/qlevar_router.dart'; @@ -83,39 +86,39 @@ class PhonebookMainPage extends HookConsumerWidget { ), const SizedBox(height: 10), associationKinds.when( - data: (data) { - return SingleChildScrollView( - scrollDirection: Axis.horizontal, - physics: const BouncingScrollPhysics(), - child: Row(children: [ - const SizedBox( - width: 20, - ), - RadioChip( - label: PhonebookTextConstants.all, - selected: kind.value == "", - onTap: () { - kind.value = ""; - kindNotifier.setKind(""); - associationListNotifier.filterAssociationList( - nameFilter, kind.value); - }), - ...data.kinds - .map((e) => RadioChip( - label: e, - selected: kind.value == e, - onTap: () { - kind.value = e; - kindNotifier.setKind(e); - associationListNotifier - .filterAssociationList( - nameFilter, kind.value); - })) - .toList(), - const SizedBox( - width: 20, - ), - ])); + data: (association) { + return HorizontalListView.builder( + height: 40, + items: association.kinds, + firstChild: ItemChip( + selected: kind.value == "", + onTap: () { + kind.value = ""; + kindNotifier.setKind(""); + associationListNotifier.filterAssociationList( + nameFilter, kind.value); + }, + child: Text(PhonebookTextConstants.all, + style: TextStyle( + color: kind.value == "" + ? Colors.white + : Colors.black, + fontWeight: FontWeight.bold, + ))), + itemBuilder: (context, item, index) { + final selected = kind.value == item; + return ItemChip( + onTap: () { + kind.value = item; + }, + selected: selected, + child: Text(item, + style: TextStyle( + color: selected ? Colors.white : Colors.black, + fontWeight: FontWeight.bold, + )), + ); + }); }, error: (error, stackTrace) => const Text(PhonebookTextConstants.errorKindsLoading), From b6ad735e93c117bb06322f55a11157a8312f654d Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:04 +0100 Subject: [PATCH 052/123] feat: adding text when no association found --- lib/phonebook/tools/constants.dart | 2 ++ lib/phonebook/ui/pages/main_page/main_page.dart | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index 339147f29..8f523fae9 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -104,6 +104,8 @@ class PhonebookTextConstants { static const String validation = "Valider"; static const String promoNotGiven = "Promo non renseignée"; + + static const String noAssociationFound = "Aucune association trouvée"; } class PhonebookColorConstants { diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 5ab226f63..78fd119fd 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -126,7 +126,7 @@ class PhonebookMainPage extends HookConsumerWidget { const SizedBox(height: 30), if (associationList.isEmpty) const Center( - child: CircularProgressIndicator(), + child: Text(PhonebookTextConstants.noAssociationFound), ) else ...associationList From 8ec35a3ca951339df917af91576c45162f4701f7 Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:04 +0100 Subject: [PATCH 053/123] feat: updating admin page UI --- .../providers/association_list_provider.dart | 2 +- .../ui/pages/admin_page/admin_page.dart | 73 ++++++++++--------- 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index 85db319f7..a2ed7e088 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -102,7 +102,7 @@ final asyncAssociationListProvider = StateNotifierProvider< final associationListProvider = Provider>((ref) { final association = ref.watch(asyncAssociationListProvider); return association.maybeWhen( - data: (association) => association, orElse: () => [Association.empty()]); + data: (association) => association, orElse: () => []); }); final associationSortedListProvider = Provider>((ref) { diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index aac52b1b3..51372b2f4 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -15,6 +15,8 @@ import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/association_research_bar.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/editable_association_card.dart'; import 'package:myecl/tools/functions.dart'; +import 'package:myecl/tools/ui/layouts/horizontal_list_view.dart'; +import 'package:myecl/tools/ui/layouts/item_chip.dart'; import 'package:myecl/tools/ui/layouts/refresher.dart'; import 'package:myecl/tools/ui/widgets/dialog.dart'; import 'package:qlevar_router/qlevar_router.dart'; @@ -50,44 +52,45 @@ class AdminPage extends HookConsumerWidget { ), const SizedBox(height: 10), associationKinds.when( - data: (data) { - return SingleChildScrollView( - scrollDirection: Axis.horizontal, - physics: const BouncingScrollPhysics(), - child: Row(children: [ - const SizedBox( - width: 20, - ), - RadioChip( - label: PhonebookTextConstants.all, - selected: kind.value == "", - onTap: () { - kind.value = ""; - kindNotifier.setKind(""); - associationsNotifier.filterAssociationList( - nameFilter, kind.value); - }), - ...data.kinds - .map((e) => RadioChip( - label: e, - selected: kind.value == e, - onTap: () { - kind.value = e; - kindNotifier.setKind(e); - associationsNotifier.filterAssociationList( - nameFilter, kind.value); - })) - .toList(), - const SizedBox( - width: 20, - ), - ])); + data: (association) { + return HorizontalListView.builder( + height: 40, + items: association.kinds, + firstChild: ItemChip( + selected: kind.value == "", + onTap: () { + kind.value = ""; + kindNotifier.setKind(""); + associationsNotifier.filterAssociationList( + nameFilter, kind.value); + }, + child: Text(PhonebookTextConstants.all, + style: TextStyle( + color: kind.value == "" + ? Colors.white + : Colors.black, + fontWeight: FontWeight.bold, + ))), + itemBuilder: (context, item, index) { + final selected = kind.value == item; + return ItemChip( + onTap: () { + kind.value = item; + }, + selected: selected, + child: Text(item, + style: TextStyle( + color: selected ? Colors.white : Colors.black, + fontWeight: FontWeight.bold, + )), + ); + }); }, error: (error, stackTrace) => const Text(PhonebookTextConstants.errorRoleTagsLoading), loading: () => const CircularProgressIndicator()), Padding( - padding: const EdgeInsets.all(10), + padding: const EdgeInsets.all(30), child: Column( children: [ GestureDetector( @@ -112,8 +115,10 @@ class AdminPage extends HookConsumerWidget { child: Icon(Icons.add, color: Colors.black, size: 40))), ), + const SizedBox(height: 30), if (associations.isEmpty) - const Center(child: CircularProgressIndicator()) + const Center( + child: Text(PhonebookTextConstants.noAssociationFound)) else ...associations .map((association) => EditableAssociationCard( From 87a982eed6220932380bbeb271815be0fd66f5b3 Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:04 +0100 Subject: [PATCH 054/123] feat: updating add association UI --- .../association_creation_page.dart | 79 ++++++++----------- 1 file changed, 33 insertions(+), 46 deletions(-) diff --git a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart index 8b46f6794..4b9f0f202 100644 --- a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart +++ b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart @@ -8,13 +8,15 @@ import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/ui/pages/association_creation_page/text_entry.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; -import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:myecl/tools/ui/builders/waiting_button.dart'; +import 'package:myecl/tools/ui/layouts/add_edit_button_layout.dart'; +import 'package:myecl/tools/ui/layouts/horizontal_list_view.dart'; +import 'package:myecl/tools/ui/layouts/item_chip.dart'; +import 'package:myecl/tools/ui/widgets/text_entry.dart'; import 'package:qlevar_router/qlevar_router.dart'; class AssociationCreationPage extends HookConsumerWidget { @@ -62,23 +64,24 @@ class AssociationCreationPage extends HookConsumerWidget { height: 30, ), associationKinds.when( - data: (value) { - return SingleChildScrollView( - scrollDirection: Axis.horizontal, - physics: const BouncingScrollPhysics(), - child: Row(children: [ - const SizedBox(width: 15), - ...value.kinds - .map((e) => RadioChip( - label: e, - selected: e == kind.value, - onTap: () async { - kind.value = e; - }, - )) - .toList(), - const SizedBox(width: 15), - ])); + data: (association) { + return HorizontalListView.builder( + height: 40, + items: association.kinds, + itemBuilder: (context, item, index) { + final selected = kind.value == item; + return ItemChip( + onTap: () { + kind.value = item; + }, + selected: selected, + child: Text(item, + style: TextStyle( + color: selected ? Colors.white : Colors.black, + fontWeight: FontWeight.bold, + )), + ); + }); }, error: (error, stack) { return const Text(PhonebookTextConstants.errorKindsLoading); @@ -96,38 +99,22 @@ class AssociationCreationPage extends HookConsumerWidget { vertical: 10, ), ), - AddAssociationTextEntry( + TextEntry( controller: name, - title: AdminTextConstants.name, + label: AdminTextConstants.name, canBeEmpty: false), - AddAssociationTextEntry( + const SizedBox(height: 30), + TextEntry( controller: description, - title: AdminTextConstants.description, + label: AdminTextConstants.description, canBeEmpty: true), + const SizedBox(height: 50), WaitingButton( - builder: (child) => Container( - width: double.infinity, - margin: const EdgeInsets.symmetric(vertical: 20), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - ), - boxShadow: [ - BoxShadow( - color: - ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, - ), - ], - borderRadius: BorderRadius.circular(15), - ), + builder: (child) => AddEditButtonLayout( + colors: const [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], child: child, ), onTap: () async { From 706b079f1a5e9e96cfc3dc378f755d6f9f836c30 Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:04 +0100 Subject: [PATCH 055/123] feat: updating edit association page UI --- .../association_member_list_provider.dart | 2 +- lib/phonebook/tools/constants.dart | 2 + .../association_editor_page.dart | 200 ++++++++---------- 3 files changed, 93 insertions(+), 111 deletions(-) diff --git a/lib/phonebook/providers/association_member_list_provider.dart b/lib/phonebook/providers/association_member_list_provider.dart index 0b3b8886e..7e79ce339 100644 --- a/lib/phonebook/providers/association_member_list_provider.dart +++ b/lib/phonebook/providers/association_member_list_provider.dart @@ -51,7 +51,7 @@ final associationMemberSortedListProvider = orElse: () => [], data: (rolesTags) { return associationMemberList.maybeWhen( - orElse: () => [CompleteMember.empty()], + orElse: () => [], data: (members) { return sortMembers( members, association.id, rolesTags.keys.toList()); diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index 8f523fae9..ae3c52434 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -106,6 +106,8 @@ class PhonebookTextConstants { static const String promoNotGiven = "Promo non renseignée"; static const String noAssociationFound = "Aucune association trouvée"; + + static const String noMember = "Aucun membre"; } class PhonebookColorConstants { diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index fcdc92c86..f785cc6ca 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -20,6 +20,9 @@ import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:myecl/tools/ui/builders/waiting_button.dart'; +import 'package:myecl/tools/ui/layouts/add_edit_button_layout.dart'; +import 'package:myecl/tools/ui/layouts/horizontal_list_view.dart'; +import 'package:myecl/tools/ui/layouts/item_chip.dart'; import 'package:myecl/tools/ui/layouts/refresher.dart'; import 'package:qlevar_router/qlevar_router.dart'; @@ -35,6 +38,7 @@ class AssociationEditorPage extends HookConsumerWidget { ref.watch(associationMemberListProvider.notifier); final associationMemberList = ref.watch(associationMemberSortedListProvider); + print(associationMemberList); final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); final associationListNotifier = @@ -77,20 +81,24 @@ class AssociationEditorPage extends HookConsumerWidget { key: key, child: Column(children: [ associationKinds.when( - data: (value) { - return SingleChildScrollView( - physics: const BouncingScrollPhysics(), - scrollDirection: Axis.horizontal, - child: Row( - children: value.kinds - .map((e) => RadioChip( - label: e, - selected: e == kind.value, - onTap: () async { - kind.value = e; - }, - )) - .toList())); + data: (association) { + return HorizontalListView.builder( + height: 40, + items: association.kinds, + itemBuilder: (context, item, index) { + final selected = kind.value == item; + return ItemChip( + onTap: () { + kind.value = item; + }, + selected: selected, + child: Text(item, + style: TextStyle( + color: selected ? Colors.white : Colors.black, + fontWeight: FontWeight.bold, + )), + ); + }); }, error: (error, stack) { return const Text(PhonebookTextConstants.errorKindsLoading); @@ -180,30 +188,10 @@ class AssociationEditorPage extends HookConsumerWidget { ], )), WaitingButton( - builder: (child) => Container( - width: double.infinity, - margin: const EdgeInsets.symmetric(vertical: 20), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - ), - boxShadow: [ - BoxShadow( - color: - ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, - ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: child), + builder: (child) => AddEditButtonLayout(colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], child: child), onTap: () async { if (!key.currentState!.validate()) { return; @@ -241,6 +229,9 @@ class AssociationEditorPage extends HookConsumerWidget { ), ) ])), + const SizedBox( + height: 30, + ), Padding( padding: const EdgeInsets.symmetric(horizontal: 30), child: Row( @@ -281,89 +272,78 @@ class AssociationEditorPage extends HookConsumerWidget { ], ), ), + const SizedBox( + height: 30, + ), if (associationMemberList.isEmpty) const Center( - child: CircularProgressIndicator(), + child: Text( + PhonebookTextConstants.noMember, + ), ) else if (associationMemberList.first.member.id != '') ...associationMemberList .map((member) => MemberEditableCard(member: member)) .toList(), const SizedBox( - height: 10, + height: 50, ), - WaitingButton( - builder: (child) => Container( - width: double.infinity, - margin: const EdgeInsets.all(30), - padding: const EdgeInsets.symmetric(vertical: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], - ), - boxShadow: [ - BoxShadow( - color: ColorConstants.gradient2.withOpacity(0.5), - blurRadius: 5, - offset: const Offset(2, 2), - spreadRadius: 2, - ), - ], - borderRadius: BorderRadius.circular(15), - ), - child: child), - onTap: () async { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text(PhonebookTextConstants.newMandate), - content: - const Text(PhonebookTextConstants.changeMandateConfirm), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - }, - child: const Text(PhonebookTextConstants.cancel), - ), - TextButton( - onPressed: () async { - Navigator.pop(context); - await tokenExpireWrapper(ref, () async { - final value = await associationListNotifier - .updateAssociation(association.copyWith( - mandateYear: association.mandateYear + 1)); - if (value) { - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.newMandateConfirmed); - associationNotifier.setAssociation( - association.copyWith( - mandateYear: association.mandateYear + 1)); - } else { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.mandateChangingError); - } - }); - }, - child: const Text(PhonebookTextConstants.validation), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: WaitingButton( + builder: (child) => AddEditButtonLayout(colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], child: child), + onTap: () async { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text(PhonebookTextConstants.newMandate), + content: + const Text(PhonebookTextConstants.changeMandateConfirm), + actions: [ + TextButton( + onPressed: () { + Navigator.pop(context); + }, + child: const Text(PhonebookTextConstants.cancel), + ), + TextButton( + onPressed: () async { + Navigator.pop(context); + await tokenExpireWrapper(ref, () async { + final value = await associationListNotifier + .updateAssociation(association.copyWith( + mandateYear: association.mandateYear + 1)); + if (value) { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.newMandateConfirmed); + associationNotifier.setAssociation( + association.copyWith( + mandateYear: + association.mandateYear + 1)); + } else { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.mandateChangingError); + } + }); + }, + child: const Text(PhonebookTextConstants.validation), + ), + ], ), - ], + ); + }, + child: Text( + "${PhonebookTextConstants.changeMandate} ${association.mandateYear + 1}", + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), + ), ), - ); - }, - child: Text( - "${PhonebookTextConstants.changeMandate} ${association.mandateYear + 1}", - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color.fromARGB(255, 255, 255, 255), - ), - ), - ) + )) ]), )); } From 04c40f59db70a45b912bf9e6e916e5cd7a5d5a00 Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:04 +0100 Subject: [PATCH 056/123] feat: updating add edit member UI --- lib/phonebook/tools/function.dart | 4 +- .../membership_editor_page.dart | 76 +++++++++---------- 2 files changed, 38 insertions(+), 42 deletions(-) diff --git a/lib/phonebook/tools/function.dart b/lib/phonebook/tools/function.dart index a45a14baa..cc0f25ea7 100644 --- a/lib/phonebook/tools/function.dart +++ b/lib/phonebook/tools/function.dart @@ -12,7 +12,7 @@ String nameConstructor(Map>> data) { value.maybeWhen( data: (d) { if (d[0]) { - name += "$key,"; + name += "$key, "; } }, orElse: () {}); @@ -20,7 +20,7 @@ String nameConstructor(Map>> data) { if (name.isEmpty) { return ""; } - return name.substring(0, name.length - 1); + return name.substring(0, name.length - 2); } List sortMembers(List members, diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index 0cd1e9452..c478c60f5 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -11,9 +11,14 @@ import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/tools/function.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; +import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:myecl/tools/ui/builders/waiting_button.dart'; +import 'package:myecl/tools/ui/layouts/add_edit_button_layout.dart'; +import 'package:myecl/tools/ui/widgets/align_left_text.dart'; +import 'package:myecl/tools/ui/widgets/styled_search_bar.dart'; +import 'package:myecl/tools/ui/widgets/text_entry.dart'; import 'package:myecl/user/providers/user_list_provider.dart'; import 'package:qlevar_router/qlevar_router.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; @@ -53,45 +58,27 @@ class MembershipEditorPage extends HookConsumerWidget { return PhonebookTemplate( child: Padding( - padding: const EdgeInsets.all(20.0), + padding: const EdgeInsets.all(30.0), child: SingleChildScrollView( child: Column( children: [ - Center( - child: Container( - decoration: const BoxDecoration( - border: - Border(bottom: BorderSide(color: Colors.black)), - color: Colors.white, - ), - child: Text( - edition - ? PhonebookTextConstants.editMembership - : PhonebookTextConstants.addMember, - style: const TextStyle(fontSize: 20)))), + AlignLeftText(edition + ? PhonebookTextConstants.editMembership + : PhonebookTextConstants.addMember), if (!edition) - TextFormField( - onChanged: (value) { + StyledSearchBar( + padding: EdgeInsets.zero, + label: PhonebookTextConstants.member, + onChanged: (value) async { tokenExpireWrapper(ref, () async { - if (queryController.text.isNotEmpty) { - await usersNotifier.filterUsers(queryController.text); + queryController.text = value; + if (value.isNotEmpty) { + await usersNotifier.filterUsers(value); } else { usersNotifier.clear(); } }); }, - cursorColor: Colors.black, - controller: queryController, - decoration: const InputDecoration( - labelText: PhonebookTextConstants.member, - floatingLabelStyle: TextStyle( - color: Colors.black, - fontWeight: FontWeight.bold, - ), - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide(color: Colors.black, width: 2.0), - ), - ), ), const SizedBox( height: 10, @@ -131,17 +118,26 @@ class MembershipEditorPage extends HookConsumerWidget { ), ]), ), - const SizedBox(height: 5), - const Text(PhonebookTextConstants.apparentName), - TextField( + const SizedBox(height: 30), + TextEntry( controller: apparentNameController, + label: PhonebookTextConstants.apparentName, ), - const SizedBox(height: 5), + const SizedBox(height: 50), WaitingButton( - builder: (child) => child, - child: Text(!edition - ? PhonebookTextConstants.add - : PhonebookTextConstants.edit), + builder: (child) => AddEditButtonLayout(colors: [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], child: child), + child: Text( + !edition + ? PhonebookTextConstants.add + : PhonebookTextConstants.edit, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), + )), onTap: () async { if (member.member.id == "") { displayToastWithContext( @@ -176,7 +172,7 @@ class MembershipEditorPage extends HookConsumerWidget { PhonebookTextConstants.updatedMember); QR.back(); } else { - displayToastWithContext(TypeMsg.msg, + displayToastWithContext(TypeMsg.error, PhonebookTextConstants.updatingError); } } else { @@ -194,8 +190,8 @@ class MembershipEditorPage extends HookConsumerWidget { TypeMsg.msg, PhonebookTextConstants.addedMember); QR.back(); } else { - displayToastWithContext( - TypeMsg.msg, PhonebookTextConstants.addingError); + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.addingError); } } }); From 4be61daf6b62bab597077a761913fa9757e225e2 Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:04 +0100 Subject: [PATCH 057/123] feat: using common top bar --- lib/phonebook/ui/phonebook.dart | 32 ++++++------------ lib/phonebook/ui/top_bar.dart | 58 --------------------------------- 2 files changed, 10 insertions(+), 80 deletions(-) delete mode 100644 lib/phonebook/ui/top_bar.dart diff --git a/lib/phonebook/ui/phonebook.dart b/lib/phonebook/ui/phonebook.dart index 5dade646d..646978690 100644 --- a/lib/phonebook/ui/phonebook.dart +++ b/lib/phonebook/ui/phonebook.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/drawer/providers/animation_provider.dart'; -import 'package:myecl/drawer/providers/swipe_provider.dart'; -import 'package:myecl/phonebook/ui/top_bar.dart'; +import 'package:myecl/phonebook/router.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/tools/ui/widgets/top_bar.dart'; class PhonebookTemplate extends HookConsumerWidget { final Widget child; @@ -10,27 +10,15 @@ class PhonebookTemplate extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final animationNotifier = ref.watch(animationProvider.notifier); - final controller = - ref.watch(swipeControllerProvider(animationNotifier.animation!)); - final controllerNotifier = ref - .watch(swipeControllerProvider(animationNotifier.animation!).notifier); return Scaffold( - body: Container( - color: Colors.white, - child: SafeArea( - child: IgnorePointer( - ignoring: controller.isCompleted, - child: Column( - children: [ - TopBar( - controllerNotifier: controllerNotifier, - ), - Expanded(child: child), - ], - ), + body: Column( + children: [ + const TopBar( + title: PhonebookTextConstants.phonebook, + root: PhonebookRouter.root, ), - ), + Expanded(child: child), + ], ), ); } diff --git a/lib/phonebook/ui/top_bar.dart b/lib/phonebook/ui/top_bar.dart deleted file mode 100644 index b9645564c..000000000 --- a/lib/phonebook/ui/top_bar.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:heroicons/heroicons.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/drawer/providers/swipe_provider.dart'; -import 'package:myecl/phonebook/router.dart'; -import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:qlevar_router/qlevar_router.dart'; - -class TopBar extends HookConsumerWidget { - final SwipeControllerNotifier controllerNotifier; - const TopBar({Key? key, required this.controllerNotifier}) : super(key: key); - - @override - Widget build(BuildContext context, WidgetRef ref) { - return Column( - children: [ - const SizedBox( - height: 15, - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SizedBox( - width: 70, - child: Builder( - builder: (BuildContext appBarContext) { - return IconButton( - onPressed: () { - if (QR.currentPath == PhonebookRouter.root) { - controllerNotifier.toggle(); - } else { - QR.back(); - } - }, - icon: HeroIcon( - QR.currentPath == PhonebookRouter.root - ? HeroIcons.bars3BottomLeft - : HeroIcons.chevronLeft, - color: Colors.black, - size: 30, - )); - }, - ), - ), - const Text(PhonebookTextConstants.phonebook, - style: TextStyle( - fontSize: 40, - fontWeight: FontWeight.w700, - color: Colors.black)), - const SizedBox( - width: 70, - ), - ], - ), - ], - ); - } -} From 524f022aa319f1ec69ca7862fd50f67486a728d5 Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:04 +0100 Subject: [PATCH 058/123] feat: adapting cards UI --- .../pages/association_page/member_card.dart | 265 +++++++----------- .../ui/pages/main_page/association_card.dart | 109 ++----- .../member_detail_page/element_field.dart | 46 ++- .../member_detail_page.dart | 122 ++++---- 4 files changed, 218 insertions(+), 324 deletions(-) diff --git a/lib/phonebook/ui/pages/association_page/member_card.dart b/lib/phonebook/ui/pages/association_page/member_card.dart index 6e35676a9..6a50ddca3 100644 --- a/lib/phonebook/ui/pages/association_page/member_card.dart +++ b/lib/phonebook/ui/pages/association_page/member_card.dart @@ -14,6 +14,8 @@ import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:myecl/phonebook/providers/profile_picture_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/tools/ui/builders/auto_loader_child.dart'; +import 'package:myecl/tools/ui/layouts/card_layout.dart'; import 'package:qlevar_router/qlevar_router.dart'; class MemberCard extends HookConsumerWidget { @@ -34,194 +36,133 @@ class MemberCard extends HookConsumerWidget { memberNotifier.setCompleteMember(member); QR.to(PhonebookRouter.root + PhonebookRouter.memberDetail); }, - child: Container( - margin: const EdgeInsets.all(5), - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: Colors.white, - border: Border.all(color: Colors.grey.withOpacity(0.2)), - borderRadius: BorderRadius.circular(15), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.2), - blurRadius: 5, - spreadRadius: 2) - ]), - child: Row( - children: [ - Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - spreadRadius: 5, - blurRadius: 10, - offset: const Offset(2, 3), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: CardLayout( + margin: EdgeInsets.zero, + child: Row( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + spreadRadius: 5, + blurRadius: 10, + offset: const Offset(2, 3), + ), + ], + ), + child: AutoLoaderChild( + value: profilePictures, + notifier: profilePicturesNotifier, + mapKey: member, + loader: (member) => profilePictureNotifier + .getProfilePicture(member.member.id), + dataBuilder: (context, value) => Container( + width: 40, + height: 40, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: value.first.image, + fit: BoxFit.cover, + ), + ), + ), + )), + const SizedBox(width: 20), + if (!kIsWeb) ...[ + if (member.member.nickname != null) + CopiabledText( + data: member.member.nickname!, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + flex: 1, ), - ], - ), - child: profilePictures.when( - data: (picture) { - if (picture[member] != null) { - return picture[member]!.when(data: (data) { - if (data.isNotEmpty) { - return Container( - width: 40, - height: 40, - decoration: BoxDecoration( - shape: BoxShape.circle, - image: DecorationImage( - image: data.first.image, - fit: BoxFit.cover, - ), - ), - ); - } else { - Future.delayed( - const Duration(milliseconds: 1), - () => profilePicturesNotifier.setTData( - member, const AsyncLoading())); - tokenExpireWrapper(ref, () async { - profilePictureNotifier - .getProfilePicture(member.member.id) - .then((value) { - profilePicturesNotifier.setTData( - member, AsyncData([value])); - }); - }); - return const HeroIcon( - HeroIcons.userCircle, - size: 40, - ); - } - }, loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, error: (e, s) { - return const Center( - child: Text( - PhonebookTextConstants.errorLoadProfilePicture), - ); - }); - } else { - profilePicturesNotifier.setTData( - member, const AsyncValue.data([])); - profilePictureNotifier - .getProfilePicture(member.member.id); - return const CircleAvatar( - radius: 20, - backgroundImage: - AssetImage('assets/images/logo_alpha.png'), - ); - } - }, - loading: () { - return const CircleAvatar( - radius: 20, - backgroundImage: - AssetImage('assets/images/logo_alpha.png'), - ); - }, - error: (e, s) { - return const Center( - child: Text( - PhonebookTextConstants.errorLoadProfilePicture), - ); - }, - ), - ), - const SizedBox(width: 20), - if (kIsWeb) ...[ - if (member.member.nickname != null) CopiabledText( - data: member.member.nickname!, - style: const TextStyle( + data: "${member.member.name} ${member.member.firstname}", + style: TextStyle( fontWeight: FontWeight.bold, fontSize: 16, + color: member.member.nickname != null + ? const Color.fromARGB(255, 115, 115, 115) + : Colors.black, ), flex: 1, ), - CopiabledText( - data: "${member.member.name} ${member.member.firstname}", - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - color: member.member.nickname != null - ? const Color.fromARGB(255, 115, 115, 115) - : Colors.black, - ), - flex: 1, - ), - CopiabledText( - data: member.member.email, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - flex: 1), - if (member.member.phone != null) CopiabledText( - data: member.member.phone!, + data: member.member.email, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), flex: 1), - CopiabledText( - data: member.memberships - .firstWhere((element) => - element.associationId == association.id) - .apparentName, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - flex: 1) - ] else ...[ - if (member.member.nickname != null) - Column( - children: [ - Text( - member.member.nickname!, + if (member.member.phone != null) + CopiabledText( + data: member.member.phone!, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), + flex: 1), + CopiabledText( + data: member.memberships + .firstWhere((element) => + element.associationId == association.id) + .apparentName, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, ), - const SizedBox(height: 5), - Text( - "${member.member.name} ${member.member.firstname}", - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - color: Color.fromARGB(255, 115, 115, 115), + flex: 1) + ] else ...[ + if (member.member.nickname != null) + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + member.member.nickname!, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), ), + const SizedBox(height: 5), + Text( + "${member.member.name} ${member.member.firstname}", + style: const TextStyle( + fontSize: 16, + color: Color.fromARGB(255, 115, 115, 115), + ), + ), + ], + ) + else + Text( + "${member.member.name} ${member.member.firstname}", + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, ), - ], - ) - else + ), + const Spacer(flex: 1), Text( - "${member.member.name} ${member.member.firstname}", + member.memberships + .firstWhere((element) => + element.associationId == association.id) + .apparentName, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), ), - const Spacer(flex: 1), - Text( - member.memberships - .firstWhere((element) => - element.associationId == association.id) - .apparentName, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), + ], ], - ], - ))); + )), + )); } } diff --git a/lib/phonebook/ui/pages/main_page/association_card.dart b/lib/phonebook/ui/pages/main_page/association_card.dart index f63bcf62c..ce51a9bb5 100644 --- a/lib/phonebook/ui/pages/main_page/association_card.dart +++ b/lib/phonebook/ui/pages/main_page/association_card.dart @@ -1,12 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/associations_pictures_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; -import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/tools/token_expire_wrapper.dart'; +import 'package:myecl/tools/ui/builders/auto_loader_child.dart'; +import 'package:myecl/tools/ui/layouts/card_layout.dart'; class AssociationCard extends HookConsumerWidget { const AssociationCard({ @@ -30,87 +29,29 @@ class AssociationCard extends HookConsumerWidget { final member = ref.watch(completeMemberProvider); return Padding( - padding: const EdgeInsets.symmetric(horizontal: 10), - child: GestureDetector( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: GestureDetector( onTap: onClicked, - child: Container( - margin: const EdgeInsets.symmetric(vertical: 5), - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(15), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.2), - blurRadius: 5, - spreadRadius: 2) - ]), + child: CardLayout( + margin: EdgeInsets.zero, child: Row(children: [ - associationPictures.when( - data: (pictures) { - if (pictures[association] != null) { - return pictures[association]!.when( - data: (picture) { - if (picture.isNotEmpty) { - return Container( - width: 40, - height: 40, - decoration: BoxDecoration( - shape: BoxShape.circle, - image: DecorationImage( - image: picture.first.image, - fit: BoxFit.cover, - ), - ), - ); - } else { - Future.delayed( - const Duration(milliseconds: 1), - () => associationPicturesNotifier.setTData( - association, const AsyncLoading())); - tokenExpireWrapper(ref, () async { - associationPictureNotifier - .getAssociationPicture(association.id) - .then((value) { - associationPicturesNotifier.setTData( - association, AsyncData([value])); - }); - }); - return const HeroIcon( - HeroIcons.userCircle, - size: 40, - ); - } - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: Text(PhonebookTextConstants - .errorLoadAssociationPicture), - ); - }, - ); - } - return const HeroIcon( - HeroIcons.userCircle, - size: 40, - ); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: Text( - PhonebookTextConstants.errorLoadAssociationPicture), - ); - }, + AutoLoaderChild( + value: associationPictures, + notifier: associationPicturesNotifier, + mapKey: association, + loader: (association) => associationPictureNotifier + .getAssociationPicture(association.id), + dataBuilder: (context, value) => Container( + width: 40, + height: 40, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: value.first.image, + fit: BoxFit.cover, + ), + ), + ), ), const SizedBox(width: 10), Text( @@ -133,7 +74,7 @@ class AssociationCard extends HookConsumerWidget { fontWeight: FontWeight.bold, ), ), - ]))), - ); + ])), + )); } } diff --git a/lib/phonebook/ui/pages/member_detail_page/element_field.dart b/lib/phonebook/ui/pages/member_detail_page/element_field.dart index 7250bfc96..d66e17d61 100644 --- a/lib/phonebook/ui/pages/member_detail_page/element_field.dart +++ b/lib/phonebook/ui/pages/member_detail_page/element_field.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:myecl/phonebook/tools/constants.dart'; @@ -17,19 +18,41 @@ class ElementField extends StatelessWidget { return Container( margin: const EdgeInsets.symmetric(vertical: 5.0), - child: Row( - children: [ - Expanded( - flex: 1, - child: Center( + child: (kIsWeb) + ? Row( + children: [ + Expanded( + flex: 1, + child: Center( + child: Text( + label, + style: const TextStyle( + fontWeight: FontWeight.bold, fontSize: 16), + ))), + Expanded( + flex: 4, + child: Center( + child: SelectableText( + value, + maxLines: 1, + style: const TextStyle( + fontWeight: FontWeight.bold, fontSize: 16), + onTap: () { + Clipboard.setData(ClipboardData(text: value)); + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.copied); + }, + ))), + ], + ) + : Column(children: [ + Center( child: Text( label, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16), - ))), - Expanded( - flex: 4, - child: Center( + )), + Center( child: SelectableText( value, maxLines: 1, @@ -40,8 +63,7 @@ class ElementField extends StatelessWidget { displayToastWithContext( TypeMsg.msg, PhonebookTextConstants.copied); }, - ))), - ], - )); + )) + ])); } } diff --git a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart index 736791b21..e3749acdd 100644 --- a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart +++ b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart @@ -8,6 +8,7 @@ import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/pages/main_page/association_card.dart'; import 'package:myecl/phonebook/ui/pages/member_detail_page/element_field.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; +import 'package:myecl/tools/ui/layouts/card_layout.dart'; import 'package:qlevar_router/qlevar_router.dart'; class MemberDetailPage extends HookConsumerWidget { @@ -19,72 +20,61 @@ class MemberDetailPage extends HookConsumerWidget { final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationList = ref.watch(associationListProvider); return PhonebookTemplate( - child: Container( - margin: const EdgeInsets.all(10), - width: MediaQuery.of(context).size.width, - decoration: BoxDecoration(borderRadius: BorderRadius.circular(50)), + child: Column(children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: CardLayout( + margin: EdgeInsets.zero, child: Column(children: [ - Container( - decoration: BoxDecoration( - color: Colors.white, - border: Border.all(color: Colors.grey.withOpacity(0.2)), - borderRadius: BorderRadius.circular(15), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.2), - blurRadius: 5, - spreadRadius: 2) - ]), - child: Column(children: [ - ElementField( - label: PhonebookTextConstants.name, - value: memberProvider.member.name), - ElementField( - label: PhonebookTextConstants.firstname, - value: memberProvider.member.firstname), - if (memberProvider.member.nickname != null) - ElementField( - label: PhonebookTextConstants.nickname, - value: memberProvider.member.nickname!), - ElementField( - label: PhonebookTextConstants.email, - value: memberProvider.member.email), - if (memberProvider.member.phone != null) - ElementField( - label: PhonebookTextConstants.phone, - value: memberProvider.member.phone!), - ElementField( - label: PhonebookTextConstants.promotion, - value: memberProvider.member.promotion == 0 - ? PhonebookTextConstants.promoNotGiven - : memberProvider.member.promotion < 100 - ? "20${memberProvider.member.promotion}" - : memberProvider.member.promotion.toString()), - ]), - ), - const SizedBox( - height: 20, - ), - if (memberProvider.memberships.isNotEmpty) - Text( - memberProvider.memberships.length == 1 - ? PhonebookTextConstants.association - : PhonebookTextConstants.associations, - style: const TextStyle( - fontWeight: FontWeight.bold, fontSize: 20)), - ...memberProvider.memberships - .map((e) => AssociationCard( - association: associationList.firstWhere( - (association) => association.id == e.associationId), - onClicked: () { - associationNotifier.setAssociation( - associationList.firstWhere((association) => - association.id == e.associationId)); - QR.to(PhonebookRouter.root + - PhonebookRouter.associationDetail); - }, - giveMemberRole: true)) - .toList(), - ]))); + ElementField( + label: PhonebookTextConstants.name, + value: memberProvider.member.name), + ElementField( + label: PhonebookTextConstants.firstname, + value: memberProvider.member.firstname), + if (memberProvider.member.nickname != null) + ElementField( + label: PhonebookTextConstants.nickname, + value: memberProvider.member.nickname!), + ElementField( + label: PhonebookTextConstants.email, + value: memberProvider.member.email), + if (memberProvider.member.phone != null) + ElementField( + label: PhonebookTextConstants.phone, + value: memberProvider.member.phone!), + ElementField( + label: PhonebookTextConstants.promotion, + value: memberProvider.member.promotion == 0 + ? PhonebookTextConstants.promoNotGiven + : memberProvider.member.promotion < 100 + ? "20${memberProvider.member.promotion}" + : memberProvider.member.promotion.toString()), + ]), + )), + const SizedBox( + height: 20, + ), + if (memberProvider.memberships.isNotEmpty) + Text( + memberProvider.memberships.length == 1 + ? PhonebookTextConstants.association + : PhonebookTextConstants.associations, + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 20)), + const SizedBox( + height: 20, + ), + ...memberProvider.memberships + .map((e) => AssociationCard( + association: associationList.firstWhere( + (association) => association.id == e.associationId), + onClicked: () { + associationNotifier.setAssociation(associationList.firstWhere( + (association) => association.id == e.associationId)); + QR.to(PhonebookRouter.root + PhonebookRouter.associationDetail); + }, + giveMemberRole: true)) + .toList(), + ])); } } From 2bb6e48dd2d6516d5b0b3869a9f25e2699840473 Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:05 +0100 Subject: [PATCH 059/123] fix: adding filtering on chip --- lib/phonebook/ui/pages/main_page/main_page.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 78fd119fd..ba082d01e 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -110,6 +110,9 @@ class PhonebookMainPage extends HookConsumerWidget { return ItemChip( onTap: () { kind.value = item; + kindNotifier.setKind(item); + associationListNotifier.filterAssociationList( + nameFilter, kind.value); }, selected: selected, child: Text(item, From 330322e2e547399b84b737917cc25adf7cc71c63 Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:05 +0100 Subject: [PATCH 060/123] fix: adding filtering on chip on admin --- lib/phonebook/ui/pages/admin_page/admin_page.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 51372b2f4..135f5e3f8 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -76,6 +76,9 @@ class AdminPage extends HookConsumerWidget { return ItemChip( onTap: () { kind.value = item; + kindNotifier.setKind(item); + associationsNotifier.filterAssociationList( + nameFilter, kind.value); }, selected: selected, child: Text(item, @@ -118,7 +121,8 @@ class AdminPage extends HookConsumerWidget { const SizedBox(height: 30), if (associations.isEmpty) const Center( - child: Text(PhonebookTextConstants.noAssociationFound)) + child: + Text(PhonebookTextConstants.noAssociationFound)) else ...associations .map((association) => EditableAssociationCard( From 2f39ca07db3ac3f0083fb20413faaa53bbd9bdfc Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:05 +0100 Subject: [PATCH 061/123] feat: simplifying sorting function --- lib/phonebook/tools/function.dart | 34 +++++++++++++------------------ 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/lib/phonebook/tools/function.dart b/lib/phonebook/tools/function.dart index cc0f25ea7..3572d3211 100644 --- a/lib/phonebook/tools/function.dart +++ b/lib/phonebook/tools/function.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/foundation.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; @@ -23,28 +25,20 @@ String nameConstructor(Map>> data) { return name.substring(0, name.length - 2); } +int getPosition( + CompleteMember member, String associationId, List rolesTags) { + Membership membership = member.memberships + .firstWhere((element) => element.associationId == associationId); + return membership.rolesTags + .map((roleTag) => rolesTags.indexOf(roleTag)) + .reduce((value, element) => min(value, element)); +} + List sortMembers(List members, String associationId, List rolesTags) { - List sorted = []; - List> sortedByRole = - List.generate(rolesTags.length, (index) => []); - for (CompleteMember member in members) { - Membership membership = member.memberships - .firstWhere((element) => element.associationId == associationId); - List memberRoleTags = membership.rolesTags; - int highestPosition = 1000; - for (String roleTag in memberRoleTags) { - int position = rolesTags.indexOf(roleTag); - if (position < highestPosition) { - highestPosition = position; - } - } - sortedByRole[highestPosition].add(member); - } - for (List list in sortedByRole) { - sorted.addAll(list); - } - return sorted; + return members + ..sort((a, b) => getPosition(a, associationId, rolesTags) + .compareTo(getPosition(b, associationId, rolesTags))); } List sortAssociation( From 5172ff3b78fee2ab4fcde39110df980e2be49ee9 Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:05 +0100 Subject: [PATCH 062/123] feat: making copiable text as text --- lib/phonebook/ui/copiabled_text.dart | 8 ++------ .../ui/pages/association_page/member_card.dart | 10 +++++----- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/lib/phonebook/ui/copiabled_text.dart b/lib/phonebook/ui/copiabled_text.dart index 2ad9afa3c..ddb98203a 100644 --- a/lib/phonebook/ui/copiabled_text.dart +++ b/lib/phonebook/ui/copiabled_text.dart @@ -4,12 +4,8 @@ import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; class CopiabledText extends StatelessWidget { - const CopiabledText( - {Key? key, - required this.data, - required this.style, - required this.flex, - this.maxLines = 1}) + const CopiabledText(this.data, + {Key? key, required this.style, required this.flex, this.maxLines = 1}) : super(key: key); final String data; diff --git a/lib/phonebook/ui/pages/association_page/member_card.dart b/lib/phonebook/ui/pages/association_page/member_card.dart index 6a50ddca3..604fe4fca 100644 --- a/lib/phonebook/ui/pages/association_page/member_card.dart +++ b/lib/phonebook/ui/pages/association_page/member_card.dart @@ -76,7 +76,7 @@ class MemberCard extends HookConsumerWidget { if (!kIsWeb) ...[ if (member.member.nickname != null) CopiabledText( - data: member.member.nickname!, + member.member.nickname!, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, @@ -84,7 +84,7 @@ class MemberCard extends HookConsumerWidget { flex: 1, ), CopiabledText( - data: "${member.member.name} ${member.member.firstname}", + "${member.member.name} ${member.member.firstname}", style: TextStyle( fontWeight: FontWeight.bold, fontSize: 16, @@ -95,7 +95,7 @@ class MemberCard extends HookConsumerWidget { flex: 1, ), CopiabledText( - data: member.member.email, + member.member.email, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, @@ -103,14 +103,14 @@ class MemberCard extends HookConsumerWidget { flex: 1), if (member.member.phone != null) CopiabledText( - data: member.member.phone!, + member.member.phone!, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), flex: 1), CopiabledText( - data: member.memberships + member.memberships .firstWhere((element) => element.associationId == association.id) .apparentName, From 649ae435997bf07f15d7dd73a35523abb7e188f1 Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:05 +0100 Subject: [PATCH 063/123] lint: cleanup --- lib/phonebook/class/association.dart | 2 - lib/phonebook/class/complete_member.dart | 1 - lib/phonebook/class/member.dart | 1 + lib/phonebook/class/membership.dart | 3 - .../providers/association_kinds_provider.dart | 1 - .../providers/association_list_provider.dart | 4 - .../association_member_list_provider.dart | 2 - .../providers/member_role_tags_provider.dart | 1 - .../providers/phonebook_admin_provider.dart | 6 -- .../providers/roles_tags_provider.dart | 1 - .../repositories/association_repository.dart | 4 - .../repositories/role_tags_repository.dart | 2 - lib/phonebook/tools/function.dart | 2 - .../ui/pages/admin_page/admin_page.dart | 96 ++++++++++--------- .../association_editor_page.dart | 9 +- .../member_editable_card.dart | 32 +++---- .../association_page/association_page.dart | 16 ++-- .../pages/association_page/member_card.dart | 12 +-- .../ui/pages/main_page/main_page.dart | 2 - .../membership_editor_page.dart | 7 +- .../membership_editor_page/search_result.dart | 3 - 21 files changed, 80 insertions(+), 127 deletions(-) diff --git a/lib/phonebook/class/association.dart b/lib/phonebook/class/association.dart index f81beb3e4..9ff8b3300 100644 --- a/lib/phonebook/class/association.dart +++ b/lib/phonebook/class/association.dart @@ -1,5 +1,3 @@ -import 'package:flutter/material.dart'; - class Association { Association({ required this.id, diff --git a/lib/phonebook/class/complete_member.dart b/lib/phonebook/class/complete_member.dart index 4b87ab147..004f086fe 100644 --- a/lib/phonebook/class/complete_member.dart +++ b/lib/phonebook/class/complete_member.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:myecl/phonebook/class/membership.dart'; import 'member.dart'; diff --git a/lib/phonebook/class/member.dart b/lib/phonebook/class/member.dart index 83c461f10..9d41f2fc1 100644 --- a/lib/phonebook/class/member.dart +++ b/lib/phonebook/class/member.dart @@ -29,6 +29,7 @@ class Member extends SimpleUser { return data; } + @override Member copyWith({ String? name, String? firstname, diff --git a/lib/phonebook/class/membership.dart b/lib/phonebook/class/membership.dart index 7b4a9a80b..db93a6ebf 100644 --- a/lib/phonebook/class/membership.dart +++ b/lib/phonebook/class/membership.dart @@ -1,6 +1,3 @@ -import 'package:flutter/material.dart'; -import 'package:myecl/phonebook/class/association.dart'; - class Membership { Membership({ required this.id, diff --git a/lib/phonebook/providers/association_kinds_provider.dart b/lib/phonebook/providers/association_kinds_provider.dart index ff19c170c..c175a552f 100644 --- a/lib/phonebook/providers/association_kinds_provider.dart +++ b/lib/phonebook/providers/association_kinds_provider.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/association_kinds.dart'; diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index a2ed7e088..bdd4f1387 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -1,7 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/repositories/association_repository.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; @@ -58,8 +56,6 @@ class AssociationListNotifier extends ListNotifier { } void filterAssociationList(String nameFilter, String kindFilter) async { - debugPrint("nameFilter: $nameFilter"); - debugPrint("kindFilter: $kindFilter"); if (kindFilter == "") { associationList.maybeWhen( data: (data) => state = AsyncValue.data(data diff --git a/lib/phonebook/providers/association_member_list_provider.dart b/lib/phonebook/providers/association_member_list_provider.dart index 7e79ce339..c4c242d21 100644 --- a/lib/phonebook/providers/association_member_list_provider.dart +++ b/lib/phonebook/providers/association_member_list_provider.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; @@ -21,7 +20,6 @@ class AssociationMemberListNotifier extends ListNotifier { String associationId, String year, ref) async { final result = await loadList(() async => associationMemberRepository .getAssociationMemberList(associationId, year)); - debugPrint("loadMembers: $result"); result.whenData((value) { sortMembers(value, associationId, ref); }); diff --git a/lib/phonebook/providers/member_role_tags_provider.dart b/lib/phonebook/providers/member_role_tags_provider.dart index 10b97a90e..6d19e4fca 100644 --- a/lib/phonebook/providers/member_role_tags_provider.dart +++ b/lib/phonebook/providers/member_role_tags_provider.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; final memberRoleTagsProvider = diff --git a/lib/phonebook/providers/phonebook_admin_provider.dart b/lib/phonebook/providers/phonebook_admin_provider.dart index 1a38e4215..77b01889c 100644 --- a/lib/phonebook/providers/phonebook_admin_provider.dart +++ b/lib/phonebook/providers/phonebook_admin_provider.dart @@ -1,13 +1,8 @@ -import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:myecl/user/providers/user_provider.dart'; -import 'package:qlevar_router/qlevar_router.dart'; -import 'package:myecl/phonebook/router.dart'; final isPhonebookAdminProvider = StateProvider((ref) { final user = ref.watch(userProvider); @@ -40,6 +35,5 @@ final isAssociationPresidentProvider = StateProvider((ref) { } } }); - debugPrint("isPresident: $isPresident"); return isPresident; }); diff --git a/lib/phonebook/providers/roles_tags_provider.dart b/lib/phonebook/providers/roles_tags_provider.dart index c7a2ec22f..ee83a7868 100644 --- a/lib/phonebook/providers/roles_tags_provider.dart +++ b/lib/phonebook/providers/roles_tags_provider.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/association.dart'; diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index afad1c45d..879e5d7dd 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/association_kinds.dart'; import 'package:myecl/phonebook/class/member.dart'; @@ -47,9 +46,6 @@ class AssociationRepository extends Repository { Future updateMember(Membership membership, Association association, Member member, List rolesTags, String apparentName) async { - debugPrint( - "updateMembership :\n id : ${membership.id}\n member_id : ${member.id}\n association_id : ${association.id}\n role_tags : ${rolesTags.join(";")}\n role_name : $apparentName"); - return await update({ "id": membership.id, "member_id": member.id, diff --git a/lib/phonebook/repositories/role_tags_repository.dart b/lib/phonebook/repositories/role_tags_repository.dart index dd2710830..b894e0418 100644 --- a/lib/phonebook/repositories/role_tags_repository.dart +++ b/lib/phonebook/repositories/role_tags_repository.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:myecl/phonebook/class/roles_tags.dart'; import 'package:myecl/tools/repository/repository.dart'; @@ -9,7 +8,6 @@ class RolesTagsRepository extends Repository { Future getRolesTags() async { RolesTags rolesTags = RolesTags.fromJson(await getOne("roletags")); - debugPrint(rolesTags.toString()); return rolesTags; } } diff --git a/lib/phonebook/tools/function.dart b/lib/phonebook/tools/function.dart index 3572d3211..c26a1fefc 100644 --- a/lib/phonebook/tools/function.dart +++ b/lib/phonebook/tools/function.dart @@ -1,12 +1,10 @@ import 'dart:math'; -import 'package:flutter/foundation.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/association_kinds.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/membership.dart'; -import 'package:myecl/phonebook/class/roles_tags.dart'; String nameConstructor(Map>> data) { String name = ''; diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 135f5e3f8..b411b7e92 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -5,13 +5,11 @@ import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; -import 'package:myecl/phonebook/providers/phonebook_admin_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; -import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/association_research_bar.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/editable_association_card.dart'; import 'package:myecl/tools/functions.dart'; @@ -118,51 +116,55 @@ class AdminPage extends HookConsumerWidget { child: Icon(Icons.add, color: Colors.black, size: 40))), ), - const SizedBox(height: 30), - if (associations.isEmpty) - const Center( - child: - Text(PhonebookTextConstants.noAssociationFound)) - else - ...associations - .map((association) => EditableAssociationCard( - association: association, - onEdit: () { - associationNotifier.setAssociation(association); - QR.to(PhonebookRouter.root + - PhonebookRouter.admin + - PhonebookRouter.editAssociation); - }, - onDelete: () async { - await showDialog( - context: context, - builder: (context) { - return CustomDialogBox( - title: PhonebookTextConstants.deleting, - descriptions: PhonebookTextConstants - .deleteAssociation, - onYes: () async { - final result = - await associationsNotifier - .deleteAssociation(association); - if (result) { - displayToastWithContext( - TypeMsg.msg, - PhonebookTextConstants - .deletedAssociation); - } else { - displayToastWithContext( - TypeMsg.error, - PhonebookTextConstants - .deletingError); - } - associationsNotifier.loadAssociations(); - }, - ); - }, - ); - })) - .toList() + const SizedBox(height: 5), + (associations.isEmpty) + ? const Center( + child: + Text(PhonebookTextConstants.noAssociationFound)) + : Column( + children: associations + .map((association) => EditableAssociationCard( + association: association, + onEdit: () { + associationNotifier + .setAssociation(association); + QR.to(PhonebookRouter.root + + PhonebookRouter.admin + + PhonebookRouter.editAssociation); + }, + onDelete: () async { + await showDialog( + context: context, + builder: (context) { + return CustomDialogBox( + title: + PhonebookTextConstants.deleting, + descriptions: PhonebookTextConstants + .deleteAssociation, + onYes: () async { + final result = + await associationsNotifier + .deleteAssociation( + association); + if (result) { + displayToastWithContext( + TypeMsg.msg, + PhonebookTextConstants + .deletedAssociation); + } else { + displayToastWithContext( + TypeMsg.error, + PhonebookTextConstants + .deletingError); + } + associationsNotifier + .loadAssociations(); + }, + ); + }, + ); + })) + .toList()) ], ), ), diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index f785cc6ca..f1bbe8339 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -14,7 +14,6 @@ import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; -import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/phonebook/ui/pages/association_editor_page/member_editable_card.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; @@ -188,7 +187,7 @@ class AssociationEditorPage extends HookConsumerWidget { ], )), WaitingButton( - builder: (child) => AddEditButtonLayout(colors: [ + builder: (child) => AddEditButtonLayout(colors: const [ ColorConstants.gradient1, ColorConstants.gradient2, ], child: child), @@ -273,7 +272,7 @@ class AssociationEditorPage extends HookConsumerWidget { ), ), const SizedBox( - height: 30, + height: 10, ), if (associationMemberList.isEmpty) const Center( @@ -286,12 +285,12 @@ class AssociationEditorPage extends HookConsumerWidget { .map((member) => MemberEditableCard(member: member)) .toList(), const SizedBox( - height: 50, + height: 30, ), Padding( padding: const EdgeInsets.symmetric(horizontal: 30), child: WaitingButton( - builder: (child) => AddEditButtonLayout(colors: [ + builder: (child) => AddEditButtonLayout(colors: const [ ColorConstants.gradient1, ColorConstants.gradient2, ], child: child), diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index 63b4bd774..ad4f58493 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -78,26 +78,24 @@ class MemberEditableCard extends HookConsumerWidget { ), ), const SizedBox(width: 10), - AutoSizeText( - member.member.getName(), - style: const TextStyle( - fontWeight: FontWeight.bold, - ), - maxLines: 2, - minFontSize: 10, - maxFontSize: 15, - ), - const Spacer(), - AutoSizeText( - member.memberships - .firstWhere( - (element) => element.associationId == association.id) - .apparentName, + Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + AutoSizeText( + "${(member.member.nickname ?? member.member.firstname)} - ${member.memberships.firstWhere((element) => element.associationId == association.id).apparentName}", style: const TextStyle( fontWeight: FontWeight.bold, ), minFontSize: 10, - maxFontSize: 15), + maxFontSize: 15, + ), + const SizedBox(height: 3), + AutoSizeText( + member.member.nickname != null + ? "${member.member.firstname} ${member.member.name}" + : member.member.name, + minFontSize: 10, + maxFontSize: 15, + ), + ]), const Spacer(), EditionButton(onEdition: () async { roleTagsNotifier.resetChecked(); @@ -116,7 +114,7 @@ class MemberEditableCard extends HookConsumerWidget { PhonebookRouter.addEditMember); } }), - const SizedBox(width: 5), + const SizedBox(width: 10), DeleteButton( onDelete: () async { final result = await associationNotifier.deleteMember( diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index 9de9ff177..ba0b3f5c0 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -97,14 +97,14 @@ class AssociationPage extends HookConsumerWidget { const SizedBox( height: 20, ), - if (associationMemberList.isEmpty) - const Center( - child: CircularProgressIndicator(), - ) - else - ...associationMemberList - .map((member) => MemberCard(member: member)) - .toList() + (associationMemberList.isEmpty) + ? const Center( + child: CircularProgressIndicator(), + ) + : Column( + children: associationMemberList + .map((member) => MemberCard(member: member)) + .toList()) ]), if (isPresident) Positioned( diff --git a/lib/phonebook/ui/pages/association_page/member_card.dart b/lib/phonebook/ui/pages/association_page/member_card.dart index 604fe4fca..31763c995 100644 --- a/lib/phonebook/ui/pages/association_page/member_card.dart +++ b/lib/phonebook/ui/pages/association_page/member_card.dart @@ -1,19 +1,13 @@ -import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter/foundation.dart' show kIsWeb; -import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/profile_pictures_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/ui/copiabled_text.dart'; -import 'package:myecl/tools/functions.dart'; -import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:myecl/phonebook/providers/profile_picture_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; -import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/tools/ui/builders/auto_loader_child.dart'; import 'package:myecl/tools/ui/layouts/card_layout.dart'; import 'package:qlevar_router/qlevar_router.dart'; @@ -94,16 +88,14 @@ class MemberCard extends HookConsumerWidget { ), flex: 1, ), - CopiabledText( - member.member.email, + CopiabledText(member.member.email, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), flex: 1), if (member.member.phone != null) - CopiabledText( - member.member.phone!, + CopiabledText(member.member.phone!, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index ba082d01e..38aa77f80 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -12,9 +12,7 @@ import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/pages/main_page/association_card.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; -import 'package:myecl/phonebook/ui/radio_chip.dart'; import 'package:myecl/phonebook/ui/pages/main_page/research_bar.dart'; -import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/ui/layouts/horizontal_list_view.dart'; import 'package:myecl/tools/ui/layouts/item_chip.dart'; import 'package:myecl/tools/ui/layouts/refresher.dart'; diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index c478c60f5..fd4c77711 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -125,7 +125,7 @@ class MembershipEditorPage extends HookConsumerWidget { ), const SizedBox(height: 50), WaitingButton( - builder: (child) => AddEditButtonLayout(colors: [ + builder: (child) => AddEditButtonLayout(colors: const [ ColorConstants.gradient1, ColorConstants.gradient2, ], child: child), @@ -149,11 +149,6 @@ class MembershipEditorPage extends HookConsumerWidget { PhonebookTextConstants.emptyApparentName); return; } - debugPrint("Appui sur le bouton avec les paramètres:\n" - "association: $association\n" - "member: ${member.member}\n" - "rolesTags: $memberRoleTags\n" - "apparentName: ${apparentNameController.text}"); tokenExpireWrapper(ref, () async { if (edition) { final value = await associationNotifier.updateMember( diff --git a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart index 9a5ab73a4..51564fb3d 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart @@ -40,10 +40,7 @@ class SearchResult extends HookConsumerWidget { ]), ), onTap: () { - debugPrint(e.toString()); - debugPrint(Member.fromUser(e).toString()); memberNotifier.setMember(Member.fromUser(e)); - debugPrint(member.toString()); queryController.text = e.getName(); usersNotifier.clear(); })) From 1233b2e2490e3fd4486fa15fec05b96fd9ff4ae9 Mon Sep 17 00:00:00 2001 From: Maxime Roucher Date: Mon, 26 Feb 2024 15:57:05 +0100 Subject: [PATCH 064/123] lint: deleting remaining unused line --- lib/phonebook/ui/pages/membership_editor_page/search_result.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart index 51564fb3d..23eca7a28 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart @@ -13,7 +13,6 @@ class SearchResult extends HookConsumerWidget { final users = ref.watch(userList); final usersNotifier = ref.watch(userList.notifier); final memberNotifier = ref.watch(completeMemberProvider.notifier); - final member = ref.watch(completeMemberProvider); return users.when( data: (u) { From 190e29eee113320e6bc82cbf1d094d7471fa01d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Mon, 26 Feb 2024 15:57:05 +0100 Subject: [PATCH 065/123] lint: apply new linting --- lib/phonebook/ui/copiabled_text.dart | 3 +-- .../ui/pages/admin_page/admin_page.dart | 2 +- .../admin_page/association_research_bar.dart | 2 +- .../ui/pages/admin_page/delete_button.dart | 2 +- .../ui/pages/admin_page/edition_button.dart | 2 +- .../association_creation_page.dart | 2 +- .../association_creation_page/text_entry.dart | 5 ++--- .../association_editor_page.dart | 6 ++--- .../association_page/association_page.dart | 2 +- .../ui/pages/main_page/main_page.dart | 22 +++++++++---------- .../ui/pages/main_page/research_bar.dart | 2 +- .../member_detail_page/element_field.dart | 3 +-- .../member_detail_page.dart | 22 +++++++++---------- .../membership_editor_page.dart | 4 ++-- lib/phonebook/ui/phonebook.dart | 2 +- lib/phonebook/ui/text_input_dialog.dart | 5 ++--- 16 files changed, 38 insertions(+), 48 deletions(-) diff --git a/lib/phonebook/ui/copiabled_text.dart b/lib/phonebook/ui/copiabled_text.dart index ddb98203a..8663cde74 100644 --- a/lib/phonebook/ui/copiabled_text.dart +++ b/lib/phonebook/ui/copiabled_text.dart @@ -5,8 +5,7 @@ import 'package:myecl/tools/functions.dart'; class CopiabledText extends StatelessWidget { const CopiabledText(this.data, - {Key? key, required this.style, required this.flex, this.maxLines = 1}) - : super(key: key); + {super.key, required this.style, required this.flex, this.maxLines = 1}); final String data; final TextStyle style; diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index b411b7e92..8dab3b474 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -20,7 +20,7 @@ import 'package:myecl/tools/ui/widgets/dialog.dart'; import 'package:qlevar_router/qlevar_router.dart'; class AdminPage extends HookConsumerWidget { - const AdminPage({Key? key}) : super(key: key); + const AdminPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart index 28c3c2242..1596040aa 100644 --- a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart +++ b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart @@ -8,7 +8,7 @@ import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/tools/constants.dart'; class AssociationResearchBar extends HookConsumerWidget { - const AssociationResearchBar({Key? key}) : super(key: key); + const AssociationResearchBar({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/lib/phonebook/ui/pages/admin_page/delete_button.dart b/lib/phonebook/ui/pages/admin_page/delete_button.dart index 40aedfbe1..f024bd014 100644 --- a/lib/phonebook/ui/pages/admin_page/delete_button.dart +++ b/lib/phonebook/ui/pages/admin_page/delete_button.dart @@ -6,7 +6,7 @@ import 'package:myecl/tools/ui/builders/waiting_button.dart'; class DeleteButton extends StatelessWidget { final Future Function() onDelete; - const DeleteButton({Key? key, required this.onDelete}) : super(key: key); + const DeleteButton({super.key, required this.onDelete}); @override Widget build(BuildContext context) { diff --git a/lib/phonebook/ui/pages/admin_page/edition_button.dart b/lib/phonebook/ui/pages/admin_page/edition_button.dart index 287072146..bc0e55294 100644 --- a/lib/phonebook/ui/pages/admin_page/edition_button.dart +++ b/lib/phonebook/ui/pages/admin_page/edition_button.dart @@ -3,7 +3,7 @@ import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; class EditionButton extends HookConsumerWidget { - const EditionButton({Key? key, required this.onEdition}) : super(key: key); + const EditionButton({super.key, required this.onEdition}); final void Function() onEdition; @override diff --git a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart index 4b9f0f202..7b58f3f34 100644 --- a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart +++ b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart @@ -20,7 +20,7 @@ import 'package:myecl/tools/ui/widgets/text_entry.dart'; import 'package:qlevar_router/qlevar_router.dart'; class AssociationCreationPage extends HookConsumerWidget { - const AssociationCreationPage({Key? key}) : super(key: key); + const AssociationCreationPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/lib/phonebook/ui/pages/association_creation_page/text_entry.dart b/lib/phonebook/ui/pages/association_creation_page/text_entry.dart index d6024c2e4..0570f0138 100644 --- a/lib/phonebook/ui/pages/association_creation_page/text_entry.dart +++ b/lib/phonebook/ui/pages/association_creation_page/text_entry.dart @@ -7,11 +7,10 @@ class AddAssociationTextEntry extends StatelessWidget { final String title; final bool canBeEmpty; const AddAssociationTextEntry( - {Key? key, + {super.key, required this.controller, required this.title, - required this.canBeEmpty}) - : super(key: key); + required this.canBeEmpty}); @override Widget build(BuildContext context) { diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index f1bbe8339..537843202 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -26,7 +26,7 @@ import 'package:myecl/tools/ui/layouts/refresher.dart'; import 'package:qlevar_router/qlevar_router.dart'; class AssociationEditorPage extends HookConsumerWidget { - const AssociationEditorPage({Key? key}) : super(key: key); + const AssociationEditorPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -37,7 +37,6 @@ class AssociationEditorPage extends HookConsumerWidget { ref.watch(associationMemberListProvider.notifier); final associationMemberList = ref.watch(associationMemberSortedListProvider); - print(associationMemberList); final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); final associationListNotifier = @@ -282,8 +281,7 @@ class AssociationEditorPage extends HookConsumerWidget { ) else if (associationMemberList.first.member.id != '') ...associationMemberList - .map((member) => MemberEditableCard(member: member)) - .toList(), + .map((member) => MemberEditableCard(member: member)), const SizedBox( height: 30, ), diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index ba0b3f5c0..48aa860da 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -13,7 +13,7 @@ import 'package:myecl/tools/ui/layouts/refresher.dart'; import 'package:qlevar_router/qlevar_router.dart'; class AssociationPage extends HookConsumerWidget { - const AssociationPage({Key? key}) : super(key: key); + const AssociationPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 38aa77f80..a2a3bae47 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -19,7 +19,7 @@ import 'package:myecl/tools/ui/layouts/refresher.dart'; import 'package:qlevar_router/qlevar_router.dart'; class PhonebookMainPage extends HookConsumerWidget { - const PhonebookMainPage({Key? key}) : super(key: key); + const PhonebookMainPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -130,17 +130,15 @@ class PhonebookMainPage extends HookConsumerWidget { child: Text(PhonebookTextConstants.noAssociationFound), ) else - ...associationList - .map((association) => AssociationCard( - association: association, - onClicked: () { - associationNotifier.setAssociation(association); - QR.to(PhonebookRouter.root + - PhonebookRouter.associationDetail); - }, - giveMemberRole: false, - )) - .toList() + ...associationList.map((association) => AssociationCard( + association: association, + onClicked: () { + associationNotifier.setAssociation(association); + QR.to(PhonebookRouter.root + + PhonebookRouter.associationDetail); + }, + giveMemberRole: false, + )) ]))); } } diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart index 22e0d0c3a..0fc2f6fb7 100644 --- a/lib/phonebook/ui/pages/main_page/research_bar.dart +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -8,7 +8,7 @@ import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/tools/constants.dart'; class ResearchBar extends HookConsumerWidget { - const ResearchBar({Key? key}) : super(key: key); + const ResearchBar({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/lib/phonebook/ui/pages/member_detail_page/element_field.dart b/lib/phonebook/ui/pages/member_detail_page/element_field.dart index d66e17d61..7f6f19289 100644 --- a/lib/phonebook/ui/pages/member_detail_page/element_field.dart +++ b/lib/phonebook/ui/pages/member_detail_page/element_field.dart @@ -7,8 +7,7 @@ import 'package:myecl/tools/functions.dart'; class ElementField extends StatelessWidget { final String label; final String value; - const ElementField({Key? key, required this.label, required this.value}) - : super(key: key); + const ElementField({super.key, required this.label, required this.value}); @override Widget build(BuildContext context) { diff --git a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart index e3749acdd..b62cc6bde 100644 --- a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart +++ b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart @@ -12,7 +12,7 @@ import 'package:myecl/tools/ui/layouts/card_layout.dart'; import 'package:qlevar_router/qlevar_router.dart'; class MemberDetailPage extends HookConsumerWidget { - const MemberDetailPage({Key? key}) : super(key: key); + const MemberDetailPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -64,17 +64,15 @@ class MemberDetailPage extends HookConsumerWidget { const SizedBox( height: 20, ), - ...memberProvider.memberships - .map((e) => AssociationCard( - association: associationList.firstWhere( - (association) => association.id == e.associationId), - onClicked: () { - associationNotifier.setAssociation(associationList.firstWhere( - (association) => association.id == e.associationId)); - QR.to(PhonebookRouter.root + PhonebookRouter.associationDetail); - }, - giveMemberRole: true)) - .toList(), + ...memberProvider.memberships.map((e) => AssociationCard( + association: associationList + .firstWhere((association) => association.id == e.associationId), + onClicked: () { + associationNotifier.setAssociation(associationList.firstWhere( + (association) => association.id == e.associationId)); + QR.to(PhonebookRouter.root + PhonebookRouter.associationDetail); + }, + giveMemberRole: true)), ])); } } diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index fd4c77711..c5dab2b8a 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -26,8 +26,8 @@ import 'package:myecl/phonebook/ui/pages/membership_editor_page/search_result.da class MembershipEditorPage extends HookConsumerWidget { const MembershipEditorPage({ - Key? key, - }) : super(key: key); + super.key, + }); @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/lib/phonebook/ui/phonebook.dart b/lib/phonebook/ui/phonebook.dart index 646978690..2174df15b 100644 --- a/lib/phonebook/ui/phonebook.dart +++ b/lib/phonebook/ui/phonebook.dart @@ -6,7 +6,7 @@ import 'package:myecl/tools/ui/widgets/top_bar.dart'; class PhonebookTemplate extends HookConsumerWidget { final Widget child; - const PhonebookTemplate({Key? key, required this.child}) : super(key: key); + const PhonebookTemplate({super.key, required this.child}); @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/lib/phonebook/ui/text_input_dialog.dart b/lib/phonebook/ui/text_input_dialog.dart index d47334b1d..ced384403 100644 --- a/lib/phonebook/ui/text_input_dialog.dart +++ b/lib/phonebook/ui/text_input_dialog.dart @@ -4,13 +4,12 @@ import 'package:myecl/phonebook/tools/constants.dart'; class TextInputDialog extends HookConsumerWidget { const TextInputDialog( - {Key? key, + {super.key, required this.controller, required this.title, required this.text, required this.defaultText, - required this.onConfirm}) - : super(key: key); + required this.onConfirm}); final String title; final String text; From e572e1428c51ddf8f1c3214a38a1cc23ff174871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Mon, 26 Feb 2024 15:57:05 +0100 Subject: [PATCH 066/123] fix: match new MapNotifier --- lib/phonebook/providers/associations_pictures_provider.dart | 2 +- lib/phonebook/providers/member_role_tags_provider.dart | 4 ++-- lib/phonebook/providers/profile_pictures_provider.dart | 2 +- lib/phonebook/providers/roles_tags_provider.dart | 2 +- lib/phonebook/tools/function.dart | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/phonebook/providers/associations_pictures_provider.dart b/lib/phonebook/providers/associations_pictures_provider.dart index 82b5ab135..3b9f14fa0 100644 --- a/lib/phonebook/providers/associations_pictures_provider.dart +++ b/lib/phonebook/providers/associations_pictures_provider.dart @@ -11,7 +11,7 @@ class AssociationPictureNotifier extends MapNotifier { final associationPicturesProvider = StateNotifierProvider< AssociationPictureNotifier, - AsyncValue>>>>((ref) { + AsyncValue>?>>>((ref) { AssociationPictureNotifier associationPictureNotifier = AssociationPictureNotifier(); tokenExpireWrapperAuth(ref, () async { diff --git a/lib/phonebook/providers/member_role_tags_provider.dart b/lib/phonebook/providers/member_role_tags_provider.dart index 6d19e4fca..dbe2d0f60 100644 --- a/lib/phonebook/providers/member_role_tags_provider.dart +++ b/lib/phonebook/providers/member_role_tags_provider.dart @@ -8,10 +8,10 @@ final memberRoleTagsProvider = class MemberRoleTagsProvider extends StateNotifier> { MemberRoleTagsProvider() : super([]); - void setRoleTagsWithFilter(Map>> data) { + void setRoleTagsWithFilter(Map>?> data) { List newRoleTags = []; data.forEach((key, value) { - value.whenData( + value?.whenData( (d) { if (d[0]) { newRoleTags.add(key); diff --git a/lib/phonebook/providers/profile_pictures_provider.dart b/lib/phonebook/providers/profile_pictures_provider.dart index efde042a7..fbc52d23a 100644 --- a/lib/phonebook/providers/profile_pictures_provider.dart +++ b/lib/phonebook/providers/profile_pictures_provider.dart @@ -10,7 +10,7 @@ class ProfilePictureNotifier extends MapNotifier { } final profilePicturesProvider = StateNotifierProvider>>>>((ref) { + AsyncValue>?>>>((ref) { ProfilePictureNotifier profilePictureNotifier = ProfilePictureNotifier(); tokenExpireWrapperAuth(ref, () async { ref.watch(associationMemberListProvider).maybeWhen(data: (profile) { diff --git a/lib/phonebook/providers/roles_tags_provider.dart b/lib/phonebook/providers/roles_tags_provider.dart index ee83a7868..330011a19 100644 --- a/lib/phonebook/providers/roles_tags_provider.dart +++ b/lib/phonebook/providers/roles_tags_provider.dart @@ -43,7 +43,7 @@ class RolesTagsNotifier extends MapNotifier { } final rolesTagsProvider = StateNotifierProvider>>>>((ref) { + AsyncValue>?>>>((ref) { final token = ref.watch(tokenProvider); RolesTagsNotifier notifier = RolesTagsNotifier(token: token); tokenExpireWrapperAuth(ref, () async { diff --git a/lib/phonebook/tools/function.dart b/lib/phonebook/tools/function.dart index c26a1fefc..ec085d655 100644 --- a/lib/phonebook/tools/function.dart +++ b/lib/phonebook/tools/function.dart @@ -6,10 +6,10 @@ import 'package:myecl/phonebook/class/association_kinds.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/membership.dart'; -String nameConstructor(Map>> data) { +String nameConstructor(Map>?> data) { String name = ''; data.forEach((key, value) { - value.maybeWhen( + value?.maybeWhen( data: (d) { if (d[0]) { name += "$key, "; From 0aa3aa85a6414cc0d88c73889694ee31058e57f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Mon, 26 Feb 2024 20:30:08 +0100 Subject: [PATCH 067/123] Fix: Update to refacto and bug fix --- .../providers/association_list_provider.dart | 22 +- .../association_member_list_provider.dart | 18 -- .../associations_pictures_provider.dart | 2 +- lib/phonebook/providers/edition_provider.dart | 13 - lib/phonebook/providers/is_edit_provider.dart | 13 + .../repositories/association_repository.dart | 3 +- lib/phonebook/tools/constants.dart | 1 + lib/phonebook/tools/function.dart | 2 +- .../ui/pages/admin_page/admin_page.dart | 268 +++++++++--------- .../admin_page/association_research_bar.dart | 3 +- .../ui/pages/admin_page/delete_button.dart | 1 + .../admin_page/editable_association_card.dart | 78 ----- .../association_creation_page.dart | 5 +- .../association_editor_page.dart | 38 ++- .../member_editable_card.dart | 6 +- .../association_page/association_page.dart | 199 +++++++------ .../pages/association_page/member_card.dart | 56 +--- .../ui/pages/main_page/association_card.dart | 98 +++---- .../ui/pages/main_page/main_page.dart | 198 +++++++------ .../ui/pages/main_page/research_bar.dart | 3 +- .../member_detail_page.dart | 124 ++++---- .../membership_editor_page.dart | 78 ++--- pubspec.lock | 48 +++- 23 files changed, 586 insertions(+), 691 deletions(-) delete mode 100644 lib/phonebook/providers/edition_provider.dart create mode 100644 lib/phonebook/providers/is_edit_provider.dart diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index bdd4f1387..18d007180 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -1,11 +1,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/repositories/association_repository.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/tools/providers/list_notifier.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; -import 'package:myecl/phonebook/tools/function.dart'; class AssociationListNotifier extends ListNotifier { final AssociationRepository associationRepository = AssociationRepository(); @@ -85,8 +83,8 @@ class AssociationListNotifier extends ListNotifier { } } -final asyncAssociationListProvider = StateNotifierProvider< - AssociationListNotifier, AsyncValue>>((ref) { +final associationListProvider = StateNotifierProvider>>((ref) { final token = ref.watch(tokenProvider); AssociationListNotifier notifier = AssociationListNotifier(token: token); tokenExpireWrapperAuth(ref, () async { @@ -94,19 +92,3 @@ final asyncAssociationListProvider = StateNotifierProvider< }); return notifier; }); - -final associationListProvider = Provider>((ref) { - final association = ref.watch(asyncAssociationListProvider); - return association.maybeWhen( - data: (association) => association, orElse: () => []); -}); - -final associationSortedListProvider = Provider>((ref) { - final associationList = ref.watch(associationListProvider); - final associationKinds = ref.watch(associationKindsProvider); - return associationKinds.maybeWhen( - data: (associationKinds) { - return sortAssociation(associationList, associationKinds); - }, - orElse: () => []); -}); diff --git a/lib/phonebook/providers/association_member_list_provider.dart b/lib/phonebook/providers/association_member_list_provider.dart index c4c242d21..be55dc4f9 100644 --- a/lib/phonebook/providers/association_member_list_provider.dart +++ b/lib/phonebook/providers/association_member_list_provider.dart @@ -2,7 +2,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; -import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/repositories/association_member_repository.dart'; import 'package:myecl/phonebook/tools/function.dart'; import 'package:myecl/tools/providers/list_notifier.dart'; @@ -39,20 +38,3 @@ final associationMemberListProvider = StateNotifierProvider< }); return provider; }); - -final associationMemberSortedListProvider = - Provider>((ref) { - final association = ref.watch(associationProvider); - final associationMemberList = ref.watch(associationMemberListProvider); - final rolesTags = ref.watch(rolesTagsProvider); - return rolesTags.maybeWhen( - orElse: () => [], - data: (rolesTags) { - return associationMemberList.maybeWhen( - orElse: () => [], - data: (members) { - return sortMembers( - members, association.id, rolesTags.keys.toList()); - }); - }); -}); diff --git a/lib/phonebook/providers/associations_pictures_provider.dart b/lib/phonebook/providers/associations_pictures_provider.dart index 3b9f14fa0..b45ceb329 100644 --- a/lib/phonebook/providers/associations_pictures_provider.dart +++ b/lib/phonebook/providers/associations_pictures_provider.dart @@ -15,7 +15,7 @@ final associationPicturesProvider = StateNotifierProvider< AssociationPictureNotifier associationPictureNotifier = AssociationPictureNotifier(); tokenExpireWrapperAuth(ref, () async { - ref.watch(asyncAssociationListProvider).maybeWhen(data: (association) { + ref.watch(associationListProvider).maybeWhen(data: (association) { associationPictureNotifier.loadTList(association); for (final l in association) { associationPictureNotifier.setTData(l, const AsyncValue.data([])); diff --git a/lib/phonebook/providers/edition_provider.dart b/lib/phonebook/providers/edition_provider.dart deleted file mode 100644 index ecaec63a6..000000000 --- a/lib/phonebook/providers/edition_provider.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; - -final editionProvider = StateNotifierProvider((ref) { - return EditionProvider(); -}); - -class EditionProvider extends StateNotifier { - EditionProvider() : super(false); - - void setStatus(bool i) { - state = i; - } -} diff --git a/lib/phonebook/providers/is_edit_provider.dart b/lib/phonebook/providers/is_edit_provider.dart new file mode 100644 index 000000000..1cd77f041 --- /dev/null +++ b/lib/phonebook/providers/is_edit_provider.dart @@ -0,0 +1,13 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final isEditProvider = StateNotifierProvider((ref) { + return IsEditProvider(); +}); + +class IsEditProvider extends StateNotifier { + IsEditProvider() : super(false); + + void setStatus(bool i) { + state = i; + } +} diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index 879e5d7dd..f806e9be8 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -32,12 +32,13 @@ class AssociationRepository extends Repository { Future addMember(Association association, Member member, List rolesTags, String apparentName) async { - return await create({ + final value = await create({ "user_id": member.id, "association_id": association.id, "role_tags": rolesTags.join(";"), "role_name": apparentName }, suffix: "memberships"); + return value != null; } Future deleteMember(Membership membership) async { diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index ae3c52434..734ae2d4a 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -108,6 +108,7 @@ class PhonebookTextConstants { static const String noAssociationFound = "Aucune association trouvée"; static const String noMember = "Aucun membre"; + static const String noMemberRole = "Aucun role trouvé"; } class PhonebookColorConstants { diff --git a/lib/phonebook/tools/function.dart b/lib/phonebook/tools/function.dart index ec085d655..b95af8232 100644 --- a/lib/phonebook/tools/function.dart +++ b/lib/phonebook/tools/function.dart @@ -39,7 +39,7 @@ List sortMembers(List members, .compareTo(getPosition(b, associationId, rolesTags))); } -List sortAssociation( +List sortedAssociation( List associations, AssociationKinds kinds) { List sorted = []; List> sortedByKind = diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 8dab3b474..7728d11a8 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; @@ -9,10 +10,13 @@ import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/phonebook/tools/function.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/association_research_bar.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/editable_association_card.dart'; import 'package:myecl/tools/functions.dart'; +import 'package:myecl/tools/ui/builders/async_child.dart'; +import 'package:myecl/tools/ui/layouts/card_layout.dart'; import 'package:myecl/tools/ui/layouts/horizontal_list_view.dart'; import 'package:myecl/tools/ui/layouts/item_chip.dart'; import 'package:myecl/tools/ui/layouts/refresher.dart'; @@ -25,9 +29,8 @@ class AdminPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final associationNotifier = ref.watch(asyncAssociationProvider.notifier); - final associationsNotifier = - ref.watch(asyncAssociationListProvider.notifier); - final associations = ref.watch(associationSortedListProvider); + final associationListNotifier = ref.watch(associationListProvider.notifier); + final associationList = ref.watch(associationListProvider); final roleNotifier = ref.watch(rolesTagsProvider.notifier); final associationKinds = ref.watch(associationKindsProvider); final kind = useState(''); @@ -38,136 +41,137 @@ class AdminPage extends HookConsumerWidget { } return PhonebookTemplate( - child: Refresher( - onRefresh: () async { - await associationsNotifier.loadAssociations(); - await roleNotifier.loadRolesTags(); - }, - child: Column(children: [ - const Padding( - padding: EdgeInsets.all(30), - child: AssociationResearchBar(), - ), - const SizedBox(height: 10), - associationKinds.when( - data: (association) { - return HorizontalListView.builder( - height: 40, - items: association.kinds, - firstChild: ItemChip( - selected: kind.value == "", - onTap: () { - kind.value = ""; - kindNotifier.setKind(""); - associationsNotifier.filterAssociationList( - nameFilter, kind.value); - }, - child: Text(PhonebookTextConstants.all, - style: TextStyle( - color: kind.value == "" - ? Colors.white - : Colors.black, - fontWeight: FontWeight.bold, - ))), - itemBuilder: (context, item, index) { - final selected = kind.value == item; - return ItemChip( - onTap: () { - kind.value = item; - kindNotifier.setKind(item); - associationsNotifier.filterAssociationList( - nameFilter, kind.value); - }, - selected: selected, - child: Text(item, - style: TextStyle( - color: selected ? Colors.white : Colors.black, - fontWeight: FontWeight.bold, - )), - ); - }); - }, - error: (error, stackTrace) => - const Text(PhonebookTextConstants.errorRoleTagsLoading), - loading: () => const CircularProgressIndicator()), - Padding( - padding: const EdgeInsets.all(30), - child: Column( - children: [ - GestureDetector( - onTap: () { - QR.to(PhonebookRouter.root + - PhonebookRouter.admin + - PhonebookRouter.createAssociaiton); - }, - child: Container( - decoration: BoxDecoration( + child: Refresher( + onRefresh: () async { + await associationListNotifier.loadAssociations(); + await roleNotifier.loadRolesTags(); + }, + child: Column( + children: [ + const Padding( + padding: EdgeInsets.all(30), + child: AssociationResearchBar(), + ), + const SizedBox(height: 10), + AsyncChild( + value: associationKinds, + builder: (context, kinds) => AsyncChild( + value: associationList, + builder: (context, associations) { + associations = sortedAssociation(associations, kinds); + return Column( + children: [ + HorizontalListView.builder( + height: 40, + items: kinds.kinds, + firstChild: ItemChip( + selected: kind.value == "", + onTap: () { + kind.value = ""; + kindNotifier.setKind(""); + associationListNotifier.filterAssociationList( + nameFilter, kind.value); + }, + child: Text(PhonebookTextConstants.all, + style: TextStyle( + color: kind.value == "" + ? Colors.white + : Colors.black, + fontWeight: FontWeight.bold, + ))), + itemBuilder: (context, item, index) { + final selected = kind.value == item; + return ItemChip( + onTap: () { + kind.value = item; + kindNotifier.setKind(item); + associationListNotifier.filterAssociationList( + nameFilter, kind.value); + }, + selected: selected, + child: Text(item, + style: TextStyle( + color: selected + ? Colors.white + : Colors.black, + fontWeight: FontWeight.bold, + )), + ); + }), + GestureDetector( + onTap: () { + QR.to(PhonebookRouter.root + + PhonebookRouter.admin + + PhonebookRouter.createAssociaiton); + }, + child: CardLayout( + margin: const EdgeInsets.only( + bottom: 10, top: 20, left: 40, right: 40), + width: double.infinity, + height: 100, color: Colors.white, - borderRadius: BorderRadius.circular(15), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.2), - blurRadius: 5, - spreadRadius: 2) - ]), - height: 60, - margin: const EdgeInsets.only(bottom: 10), - child: const Center( - child: Icon(Icons.add, - color: Colors.black, size: 40))), - ), - const SizedBox(height: 5), - (associations.isEmpty) - ? const Center( + child: Center( + child: HeroIcon( + HeroIcons.plus, + size: 40, + color: Colors.grey.shade500, + ))), + ), + const SizedBox(height: 30), + if (associations.isEmpty) + const Center( child: - Text(PhonebookTextConstants.noAssociationFound)) - : Column( - children: associations - .map((association) => EditableAssociationCard( - association: association, - onEdit: () { - associationNotifier - .setAssociation(association); - QR.to(PhonebookRouter.root + - PhonebookRouter.admin + - PhonebookRouter.editAssociation); - }, - onDelete: () async { - await showDialog( - context: context, - builder: (context) { - return CustomDialogBox( - title: - PhonebookTextConstants.deleting, - descriptions: PhonebookTextConstants - .deleteAssociation, - onYes: () async { - final result = - await associationsNotifier - .deleteAssociation( - association); - if (result) { - displayToastWithContext( - TypeMsg.msg, - PhonebookTextConstants - .deletedAssociation); - } else { - displayToastWithContext( - TypeMsg.error, - PhonebookTextConstants - .deletingError); - } - associationsNotifier - .loadAssociations(); - }, - ); - }, - ); - })) - .toList()) - ], - ), - ), - ]))); + Text(PhonebookTextConstants.noAssociationFound), + ) + else + ...associations.map( + (association) => EditableAssociationCard( + association: association, + onEdit: () { + associationNotifier.setAssociation(association); + QR.to(PhonebookRouter.root + + PhonebookRouter.admin + + PhonebookRouter.editAssociation); + }, + onDelete: () async { + await showDialog( + context: context, + builder: (context) { + return CustomDialogBox( + title: PhonebookTextConstants.deleting, + descriptions: PhonebookTextConstants + .deleteAssociation, + onYes: () async { + final result = + await associationListNotifier + .deleteAssociation(association); + if (result) { + displayToastWithContext( + TypeMsg.msg, + PhonebookTextConstants + .deletedAssociation); + } else { + displayToastWithContext( + TypeMsg.error, + PhonebookTextConstants + .deletingError); + } + associationListNotifier + .loadAssociations(); // TODO + }, + ); + }, + ); + }, + ), + ), + ], + ); + }), + ), + ], + ), + ), + ); } } diff --git a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart index 1596040aa..762202578 100644 --- a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart +++ b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart @@ -15,8 +15,7 @@ class AssociationResearchBar extends HookConsumerWidget { final focusNode = useFocusNode(); final editingController = useTextEditingController(); final filterNotifier = ref.watch(filterProvider.notifier); - final associationsNotifier = - ref.watch(asyncAssociationListProvider.notifier); + final associationsNotifier = ref.watch(associationListProvider.notifier); final associationKind = ref.watch(associationKindProvider); return TextField( diff --git a/lib/phonebook/ui/pages/admin_page/delete_button.dart b/lib/phonebook/ui/pages/admin_page/delete_button.dart index f024bd014..6144501f2 100644 --- a/lib/phonebook/ui/pages/admin_page/delete_button.dart +++ b/lib/phonebook/ui/pages/admin_page/delete_button.dart @@ -35,6 +35,7 @@ class DeleteButton extends StatelessWidget { onTap: onDelete, child: const HeroIcon( HeroIcons.xMark, + size: 30, color: Colors.white, ), ); diff --git a/lib/phonebook/ui/pages/admin_page/editable_association_card.dart b/lib/phonebook/ui/pages/admin_page/editable_association_card.dart index 24b4aff54..c86da047a 100644 --- a/lib/phonebook/ui/pages/admin_page/editable_association_card.dart +++ b/lib/phonebook/ui/pages/admin_page/editable_association_card.dart @@ -1,13 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/providers/association_picture_provider.dart'; -import 'package:myecl/phonebook/providers/associations_pictures_provider.dart'; -import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/delete_button.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/edition_button.dart'; -import 'package:myecl/tools/token_expire_wrapper.dart'; class EditableAssociationCard extends HookConsumerWidget { final Association association; @@ -21,11 +16,6 @@ class EditableAssociationCard extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final associationPictures = ref.watch(associationPicturesProvider); - final associationPicturesNotifier = - ref.watch(associationPicturesProvider.notifier); - final associationPictureNotifier = - ref.watch(associationPictureProvider.notifier); return Container( margin: const EdgeInsets.symmetric(vertical: 5), padding: const EdgeInsets.all(10), @@ -40,74 +30,6 @@ class EditableAssociationCard extends HookConsumerWidget { ]), child: Row( children: [ - associationPictures.when( - data: (pictures) { - if (pictures[association] != null) { - return pictures[association]!.when( - data: (picture) { - if (picture.isNotEmpty) { - return Container( - width: 40, - height: 40, - decoration: BoxDecoration( - shape: BoxShape.circle, - image: DecorationImage( - image: picture.first.image, - fit: BoxFit.cover, - ), - ), - ); - } else { - Future.delayed( - const Duration(milliseconds: 1), - () => associationPicturesNotifier.setTData( - association, const AsyncLoading())); - tokenExpireWrapper(ref, () async { - associationPictureNotifier - .getAssociationPicture(association.id) - .then((value) { - associationPicturesNotifier.setTData( - association, AsyncData([value])); - }); - }); - return const HeroIcon( - HeroIcons.userCircle, - size: 40, - ); - } - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: Text( - PhonebookTextConstants.errorLoadAssociationPicture), - ); - }, - ); - } - return const HeroIcon( - HeroIcons.userCircle, - size: 40, - ); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: HeroIcon( - HeroIcons.exclamationCircle, - size: 40, - ), - ); - }, - ), const SizedBox(width: 10), Text( association.name, diff --git a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart index 7b58f3f34..b619eb36c 100644 --- a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart +++ b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart @@ -27,9 +27,8 @@ class AssociationCreationPage extends HookConsumerWidget { final key = GlobalKey(); final name = useTextEditingController(); final description = useTextEditingController(); - final associationListNotifier = - ref.watch(asyncAssociationListProvider.notifier); - final associations = ref.watch(asyncAssociationListProvider); + final associationListNotifier = ref.watch(associationListProvider.notifier); + final associations = ref.watch(associationListProvider); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationKinds = ref.watch(associationKindsProvider); final kind = useState(''); diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 537843202..9de1c82ce 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -9,7 +9,7 @@ import 'package:myecl/phonebook/providers/association_member_list_provider.dart' import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; -import 'package:myecl/phonebook/providers/edition_provider.dart'; +import 'package:myecl/phonebook/providers/is_edit_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; @@ -18,6 +18,7 @@ import 'package:myecl/phonebook/ui/pages/association_editor_page/member_editable import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; +import 'package:myecl/tools/ui/builders/async_child.dart'; import 'package:myecl/tools/ui/builders/waiting_button.dart'; import 'package:myecl/tools/ui/layouts/add_edit_button_layout.dart'; import 'package:myecl/tools/ui/layouts/horizontal_list_view.dart'; @@ -35,18 +36,16 @@ class AssociationEditorPage extends HookConsumerWidget { final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); - final associationMemberList = - ref.watch(associationMemberSortedListProvider); + final associationMemberList = ref.watch(associationMemberListProvider); final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); - final associationListNotifier = - ref.watch(asyncAssociationListProvider.notifier); + final associationListNotifier = ref.watch(associationListProvider.notifier); final associationKinds = ref.watch(associationKindsProvider); final kind = useState(association.kind); final name = useTextEditingController(text: association.name); final description = useTextEditingController(text: association.description); final rolesTagsNotifier = ref.watch(rolesTagsProvider.notifier); - final editionNotifier = ref.watch(editionProvider.notifier); + final isEditNotifier = ref.watch(isEditProvider.notifier); final completeMemberNotifier = ref.watch(completeMemberProvider.notifier); void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); @@ -250,7 +249,7 @@ class AssociationEditorPage extends HookConsumerWidget { rolesTagsNotifier.resetChecked(); completeMemberNotifier .setCompleteMember(CompleteMember.empty()); - editionNotifier.setStatus(false); + isEditNotifier.setStatus(false); if (QR.currentPath.contains(PhonebookRouter.admin)) { QR.to(PhonebookRouter.root + PhonebookRouter.admin + @@ -262,8 +261,9 @@ class AssociationEditorPage extends HookConsumerWidget { PhonebookRouter.addEditMember); } }, - child: const Icon( - Icons.add, + child: const HeroIcon( + HeroIcons.plus, + size: 30, color: Colors.white, ), ), @@ -273,17 +273,15 @@ class AssociationEditorPage extends HookConsumerWidget { const SizedBox( height: 10, ), - if (associationMemberList.isEmpty) - const Center( - child: Text( - PhonebookTextConstants.noMember, - ), - ) - else if (associationMemberList.first.member.id != '') - ...associationMemberList - .map((member) => MemberEditableCard(member: member)), - const SizedBox( - height: 30, + AsyncChild( + value: associationMemberList, + builder: (context, associationMembers) => associationMembers.isEmpty + ? const Text(PhonebookTextConstants.noMember) + : Column( + children: associationMembers + .map((member) => MemberEditableCard(member: member)) + .toList(), + ), ), Padding( padding: const EdgeInsets.symmetric(horizontal: 30), diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index ad4f58493..ea1932f3e 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -5,7 +5,7 @@ import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; -import 'package:myecl/phonebook/providers/edition_provider.dart'; +import 'package:myecl/phonebook/providers/is_edit_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/delete_button.dart'; @@ -28,7 +28,7 @@ class MemberEditableCard extends HookConsumerWidget { final associationMembersNotifier = ref.watch(associationMemberListProvider.notifier); final roleTagsNotifier = ref.watch(rolesTagsProvider.notifier); - final editionNotifier = ref.watch(editionProvider.notifier); + final isEditNotifier = ref.watch(isEditProvider.notifier); final completeMemberNotifier = ref.watch(completeMemberProvider.notifier); void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); @@ -101,7 +101,7 @@ class MemberEditableCard extends HookConsumerWidget { roleTagsNotifier.resetChecked(); roleTagsNotifier.loadRoleTagsFromMember(member, association); completeMemberNotifier.setCompleteMember(member); - editionNotifier.setStatus(true); + isEditNotifier.setStatus(true); if (QR.currentPath.contains(PhonebookRouter.admin)) { QR.to(PhonebookRouter.root + PhonebookRouter.admin + diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index 48aa860da..038b97e9a 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -9,6 +9,7 @@ import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/pages/association_page/member_card.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; +import 'package:myecl/tools/ui/builders/async_child.dart'; import 'package:myecl/tools/ui/layouts/refresher.dart'; import 'package:qlevar_router/qlevar_router.dart'; @@ -18,9 +19,7 @@ class AssociationPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final association = ref.watch(associationProvider); - final associationPicture = ref.watch(associationPictureProvider); - final associationMemberList = - ref.watch(associationMemberSortedListProvider); + final associationMemberList = ref.watch(associationMemberListProvider); final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); final associationPictureNotifier = @@ -28,54 +27,56 @@ class AssociationPage extends HookConsumerWidget { final isPresident = ref.watch(isAssociationPresidentProvider); return PhonebookTemplate( - child: Refresher( - onRefresh: () async { - await associationMemberListNotifier.loadMembers( - association.id, association.mandateYear.toString(), ref); - await associationPictureNotifier - .getAssociationPicture(association.id); - }, - child: Stack(children: [ - Column(children: [ - Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - spreadRadius: 5, - blurRadius: 10, - offset: const Offset(2, 3), - ), - ], - ), - child: associationPicture.when( - data: (picture) { - return Container( - width: 40, - height: 40, - decoration: BoxDecoration( - shape: BoxShape.circle, - image: DecorationImage( - image: picture.image, - fit: BoxFit.cover, - ), - ), - ); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: Text( - PhonebookTextConstants.errorLoadAssociationPicture), - ); - }, - ), - ), + child: Refresher( + onRefresh: () async { + await associationMemberListNotifier.loadMembers( + association.id, association.mandateYear.toString(), ref); + await associationPictureNotifier + .getAssociationPicture(association.id); + }, + child: Stack( + children: [ + Column( + children: [ + // Container( + // decoration: BoxDecoration( + // shape: BoxShape.circle, + // boxShadow: [ + // BoxShadow( + // color: Colors.black.withOpacity(0.1), + // spreadRadius: 5, + // blurRadius: 10, + // offset: const Offset(2, 3), + // ), + // ], + // ), + // child: associationPicture.when( + // data: (picture) { + // return Container( + // width: 40, + // height: 40, + // decoration: BoxDecoration( + // shape: BoxShape.circle, + // image: DecorationImage( + // image: picture.image, + // fit: BoxFit.cover, + // ), + // ), + // ); + // }, + // loading: () { + // return const Center( + // child: CircularProgressIndicator(), + // ); + // }, + // error: (e, s) { + // return const Center( + // child: Text( + // PhonebookTextConstants.errorLoadAssociationPicture), + // ); + // }, + // ), + // ), const SizedBox(height: 20), Text( association.name, @@ -97,51 +98,61 @@ class AssociationPage extends HookConsumerWidget { const SizedBox( height: 20, ), - (associationMemberList.isEmpty) - ? const Center( - child: CircularProgressIndicator(), - ) - : Column( - children: associationMemberList - .map((member) => MemberCard(member: member)) - .toList()) - ]), - if (isPresident) - Positioned( - top: 20, - right: 20, - child: GestureDetector( - onTap: () { - QR.to(PhonebookRouter.root + - PhonebookRouter.associationDetail + - PhonebookRouter.editAssociation); - }, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 10, - offset: const Offset(0, 5)) - ]), - child: const Row( - children: [ - HeroIcon(HeroIcons.userGroup, color: Colors.white), - SizedBox(width: 10), - Text(PhonebookTextConstants.admin, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.white)), - ], - ), + AsyncChild( + value: associationMemberList, + builder: (context, associationMembers) => + associationMembers.isEmpty + ? const Text(PhonebookTextConstants.noMember) + : Column( + children: associationMembers + .map((member) => MemberCard( + member: member, + association: association, + )) + .toList(), + ), + ) + ], + ), + if (isPresident) + Positioned( + top: 20, + right: 20, + child: GestureDetector( + onTap: () { + QR.to(PhonebookRouter.root + + PhonebookRouter.associationDetail + + PhonebookRouter.editAssociation); + }, + child: Container( + padding: + const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + blurRadius: 10, + offset: const Offset(0, 5)) + ]), + child: const Row( + children: [ + HeroIcon(HeroIcons.userGroup, color: Colors.white), + SizedBox(width: 10), + Text(PhonebookTextConstants.admin, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.white)), + ], ), ), ), - ]))); + ), + ], + ), + ), + ); } } diff --git a/lib/phonebook/ui/pages/association_page/member_card.dart b/lib/phonebook/ui/pages/association_page/member_card.dart index 31763c995..f3e748e0d 100644 --- a/lib/phonebook/ui/pages/association_page/member_card.dart +++ b/lib/phonebook/ui/pages/association_page/member_card.dart @@ -1,29 +1,30 @@ import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart' show kIsWeb; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; -import 'package:myecl/phonebook/providers/association_provider.dart'; -import 'package:myecl/phonebook/providers/profile_pictures_provider.dart'; +import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/router.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/copiabled_text.dart'; -import 'package:myecl/phonebook/providers/profile_picture_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; -import 'package:myecl/tools/ui/builders/auto_loader_child.dart'; import 'package:myecl/tools/ui/layouts/card_layout.dart'; import 'package:qlevar_router/qlevar_router.dart'; class MemberCard extends HookConsumerWidget { - const MemberCard({super.key, required this.member}); + const MemberCard( + {super.key, required this.member, required this.association}); final CompleteMember member; + final Association association; @override Widget build(BuildContext context, WidgetRef ref) { final memberNotifier = ref.watch(completeMemberProvider.notifier); - final association = ref.watch(associationProvider); - final profilePictures = ref.watch(profilePicturesProvider); - final profilePicturesNotifier = ref.watch(profilePicturesProvider.notifier); - final profilePictureNotifier = ref.watch(profilePictureProvider.notifier); + + List assoMembership = member.memberships + .where((memberships) => memberships.associationId == association.id) + .toList(); return GestureDetector( onTap: () { @@ -36,36 +37,6 @@ class MemberCard extends HookConsumerWidget { margin: EdgeInsets.zero, child: Row( children: [ - Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - spreadRadius: 5, - blurRadius: 10, - offset: const Offset(2, 3), - ), - ], - ), - child: AutoLoaderChild( - value: profilePictures, - notifier: profilePicturesNotifier, - mapKey: member, - loader: (member) => profilePictureNotifier - .getProfilePicture(member.member.id), - dataBuilder: (context, value) => Container( - width: 40, - height: 40, - decoration: BoxDecoration( - shape: BoxShape.circle, - image: DecorationImage( - image: value.first.image, - fit: BoxFit.cover, - ), - ), - ), - )), const SizedBox(width: 20), if (!kIsWeb) ...[ if (member.member.nickname != null) @@ -143,10 +114,9 @@ class MemberCard extends HookConsumerWidget { ), const Spacer(flex: 1), Text( - member.memberships - .firstWhere((element) => - element.associationId == association.id) - .apparentName, + assoMembership.isEmpty + ? PhonebookTextConstants.noMemberRole + : assoMembership.first.apparentName, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, diff --git a/lib/phonebook/ui/pages/main_page/association_card.dart b/lib/phonebook/ui/pages/main_page/association_card.dart index ce51a9bb5..4de0a3fa9 100644 --- a/lib/phonebook/ui/pages/main_page/association_card.dart +++ b/lib/phonebook/ui/pages/main_page/association_card.dart @@ -1,10 +1,9 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/providers/association_picture_provider.dart'; -import 'package:myecl/phonebook/providers/associations_pictures_provider.dart'; -import 'package:myecl/phonebook/providers/complete_member_provider.dart'; -import 'package:myecl/tools/ui/builders/auto_loader_child.dart'; +import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/membership.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/tools/ui/layouts/card_layout.dart'; class AssociationCard extends HookConsumerWidget { @@ -12,69 +11,52 @@ class AssociationCard extends HookConsumerWidget { super.key, required this.association, required this.onClicked, - required this.giveMemberRole, + this.showMemberRole = false, + this.member, }); final Association association; final VoidCallback onClicked; - final bool giveMemberRole; + final bool showMemberRole; + final CompleteMember? member; @override Widget build(BuildContext context, WidgetRef ref) { - final associationPictures = ref.watch(associationPicturesProvider); - final associationPicturesNotifier = - ref.watch(associationPicturesProvider.notifier); - final associationPictureNotifier = - ref.watch(associationPictureProvider.notifier); - final member = ref.watch(completeMemberProvider); + List assoMembership = []; + if (member != null) { + assoMembership = member!.memberships + .where((memberships) => memberships.associationId == association.id) + .toList(); + } return Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), - child: GestureDetector( - onTap: onClicked, - child: CardLayout( - margin: EdgeInsets.zero, - child: Row(children: [ - AutoLoaderChild( - value: associationPictures, - notifier: associationPicturesNotifier, - mapKey: association, - loader: (association) => associationPictureNotifier - .getAssociationPicture(association.id), - dataBuilder: (context, value) => Container( - width: 40, - height: 40, - decoration: BoxDecoration( - shape: BoxShape.circle, - image: DecorationImage( - image: value.first.image, - fit: BoxFit.cover, - ), - ), - ), + padding: const EdgeInsets.symmetric(horizontal: 30), + child: GestureDetector( + onTap: onClicked, + child: CardLayout( + margin: EdgeInsets.zero, + child: Row( + children: [ + const SizedBox(width: 10), + Text( + association.name, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, ), - const SizedBox(width: 10), - Text( - association.name, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - const Spacer(flex: 1), - Text( - giveMemberRole - ? member.memberships - .firstWhere((element) => - element.associationId == association.id) - .apparentName - : association.kind, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ])), - )); + ), + const Spacer(flex: 1), + Text(!showMemberRole + ? association.kind + : member == null + ? PhonebookTextConstants.noMember + : assoMembership.isEmpty + ? PhonebookTextConstants.noMemberRole + : assoMembership.first.apparentName) + ], + ), + ), + ), + ); } } diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index a2a3bae47..26f0172c5 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; @@ -10,14 +9,18 @@ import 'package:myecl/phonebook/providers/phonebook_admin_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/phonebook/tools/function.dart'; import 'package:myecl/phonebook/ui/pages/main_page/association_card.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/phonebook/ui/pages/main_page/research_bar.dart'; +import 'package:myecl/tools/ui/builders/async_child.dart'; import 'package:myecl/tools/ui/layouts/horizontal_list_view.dart'; import 'package:myecl/tools/ui/layouts/item_chip.dart'; import 'package:myecl/tools/ui/layouts/refresher.dart'; import 'package:qlevar_router/qlevar_router.dart'; +import '../../../../tools/ui/widgets/admin_button.dart'; + class PhonebookMainPage extends HookConsumerWidget { const PhonebookMainPage({super.key}); @@ -25,9 +28,8 @@ class PhonebookMainPage extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final isAdmin = ref.watch(isPhonebookAdminProvider); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); - final associationListNotifier = - ref.watch(asyncAssociationListProvider.notifier); - final associationList = ref.watch(associationSortedListProvider); + final associationListNotifier = ref.watch(associationListProvider.notifier); + final associationList = ref.watch(associationListProvider); final associationKindsNotifier = ref.watch(associationKindsProvider.notifier); final associationKinds = ref.watch(associationKindsProvider); @@ -36,109 +38,101 @@ class PhonebookMainPage extends HookConsumerWidget { final nameFilter = ref.watch(filterProvider); return PhonebookTemplate( - child: Refresher( - onRefresh: () async { - await associationKindsNotifier.loadAssociationKinds(); - await associationListNotifier.loadAssociations(); - }, - child: Column(children: [ - Padding( - padding: const EdgeInsets.all(30.0), - child: Row( - children: [ - const ResearchBar(), - if (isAdmin) const SizedBox(width: 20), - if (isAdmin) - GestureDetector( + child: Refresher( + onRefresh: () async { + await associationKindsNotifier.loadAssociationKinds(); + await associationListNotifier.loadAssociations(); + }, + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(30.0), + child: Row( + children: [ + const ResearchBar(), + if (isAdmin) + Padding( + padding: const EdgeInsets.only(left: 20), + child: AdminButton( onTap: () { QR.to(PhonebookRouter.root + PhonebookRouter.admin); }, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 10, - offset: const Offset(0, 5)) - ]), - child: const Row( - children: [ - HeroIcon(HeroIcons.userGroup, - color: Colors.white), - SizedBox(width: 10), - Text(PhonebookTextConstants.admin, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.white)), - ], - ), - ), ), - ], - ), + ) + ], ), - const SizedBox(height: 10), - associationKinds.when( - data: (association) { - return HorizontalListView.builder( - height: 40, - items: association.kinds, - firstChild: ItemChip( - selected: kind.value == "", - onTap: () { - kind.value = ""; - kindNotifier.setKind(""); - associationListNotifier.filterAssociationList( - nameFilter, kind.value); - }, - child: Text(PhonebookTextConstants.all, - style: TextStyle( - color: kind.value == "" - ? Colors.white - : Colors.black, - fontWeight: FontWeight.bold, - ))), - itemBuilder: (context, item, index) { - final selected = kind.value == item; - return ItemChip( - onTap: () { - kind.value = item; - kindNotifier.setKind(item); - associationListNotifier.filterAssociationList( - nameFilter, kind.value); + ), + const SizedBox(height: 10), + AsyncChild( + value: associationKinds, + builder: (context, kinds) => AsyncChild( + value: associationList, + builder: (context, associations) { + associations = sortedAssociation(associations, kinds); + return Column( + children: [ + HorizontalListView.builder( + height: 40, + items: kinds.kinds, + firstChild: ItemChip( + selected: kind.value == "", + onTap: () { + kind.value = ""; + kindNotifier.setKind(""); + associationListNotifier.filterAssociationList( + nameFilter, kind.value); + }, + child: Text(PhonebookTextConstants.all, + style: TextStyle( + color: kind.value == "" + ? Colors.white + : Colors.black, + fontWeight: FontWeight.bold, + ))), + itemBuilder: (context, item, index) { + final selected = kind.value == item; + return ItemChip( + onTap: () { + kind.value = item; + kindNotifier.setKind(item); + associationListNotifier.filterAssociationList( + nameFilter, kind.value); + }, + selected: selected, + child: Text(item, + style: TextStyle( + color: + selected ? Colors.white : Colors.black, + fontWeight: FontWeight.bold, + )), + ); + }), + const SizedBox(height: 30), + if (associations.isEmpty) + const Center( + child: + Text(PhonebookTextConstants.noAssociationFound), + ) + else + ...associations.map( + (association) => AssociationCard( + association: association, + onClicked: () { + associationNotifier.setAssociation(association); + QR.to(PhonebookRouter.root + + PhonebookRouter.associationDetail); }, - selected: selected, - child: Text(item, - style: TextStyle( - color: selected ? Colors.white : Colors.black, - fontWeight: FontWeight.bold, - )), - ); - }); - }, - error: (error, stackTrace) => - const Text(PhonebookTextConstants.errorKindsLoading), - loading: () => const CircularProgressIndicator()), - const SizedBox(height: 30), - if (associationList.isEmpty) - const Center( - child: Text(PhonebookTextConstants.noAssociationFound), - ) - else - ...associationList.map((association) => AssociationCard( - association: association, - onClicked: () { - associationNotifier.setAssociation(association); - QR.to(PhonebookRouter.root + - PhonebookRouter.associationDetail); - }, - giveMemberRole: false, - )) - ]))); + showMemberRole: false, + ), + ) + ], + ); + }, + ), + ), + ], + ), + ), + ); } } diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart index 0fc2f6fb7..1d5d0113e 100644 --- a/lib/phonebook/ui/pages/main_page/research_bar.dart +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -15,8 +15,7 @@ class ResearchBar extends HookConsumerWidget { final focusNode = useFocusNode(); final editingController = useTextEditingController(); final filterNotifier = ref.watch(filterProvider.notifier); - final associationsNotifier = - ref.watch(asyncAssociationListProvider.notifier); + final associationsNotifier = ref.watch(associationListProvider.notifier); final associationKind = ref.watch(associationKindProvider); return Expanded( diff --git a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart index b62cc6bde..777ca8c46 100644 --- a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart +++ b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart @@ -8,6 +8,7 @@ import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/pages/main_page/association_card.dart'; import 'package:myecl/phonebook/ui/pages/member_detail_page/element_field.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; +import 'package:myecl/tools/ui/builders/async_child.dart'; import 'package:myecl/tools/ui/layouts/card_layout.dart'; import 'package:qlevar_router/qlevar_router.dart'; @@ -20,59 +21,76 @@ class MemberDetailPage extends HookConsumerWidget { final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationList = ref.watch(associationListProvider); return PhonebookTemplate( - child: Column(children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), - child: CardLayout( - margin: EdgeInsets.zero, - child: Column(children: [ - ElementField( - label: PhonebookTextConstants.name, - value: memberProvider.member.name), - ElementField( - label: PhonebookTextConstants.firstname, - value: memberProvider.member.firstname), - if (memberProvider.member.nickname != null) - ElementField( - label: PhonebookTextConstants.nickname, - value: memberProvider.member.nickname!), - ElementField( - label: PhonebookTextConstants.email, - value: memberProvider.member.email), - if (memberProvider.member.phone != null) - ElementField( - label: PhonebookTextConstants.phone, - value: memberProvider.member.phone!), - ElementField( - label: PhonebookTextConstants.promotion, - value: memberProvider.member.promotion == 0 - ? PhonebookTextConstants.promoNotGiven - : memberProvider.member.promotion < 100 - ? "20${memberProvider.member.promotion}" - : memberProvider.member.promotion.toString()), - ]), - )), - const SizedBox( - height: 20, + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: CardLayout( + margin: EdgeInsets.zero, + child: Column(children: [ + ElementField( + label: PhonebookTextConstants.name, + value: memberProvider.member.name), + ElementField( + label: PhonebookTextConstants.firstname, + value: memberProvider.member.firstname), + if (memberProvider.member.nickname != null) + ElementField( + label: PhonebookTextConstants.nickname, + value: memberProvider.member.nickname!), + ElementField( + label: PhonebookTextConstants.email, + value: memberProvider.member.email), + if (memberProvider.member.phone != null) + ElementField( + label: PhonebookTextConstants.phone, + value: memberProvider.member.phone!), + ElementField( + label: PhonebookTextConstants.promotion, + value: memberProvider.member.promotion == 0 + ? PhonebookTextConstants.promoNotGiven + : memberProvider.member.promotion < 100 + ? "20${memberProvider.member.promotion}" + : memberProvider.member.promotion.toString()), + ]), + )), + const SizedBox( + height: 20, + ), + if (memberProvider.memberships.isNotEmpty) + Text( + memberProvider.memberships.length == 1 + ? PhonebookTextConstants.association + : PhonebookTextConstants.associations, + style: + const TextStyle(fontWeight: FontWeight.bold, fontSize: 20)), + const SizedBox( + height: 20, + ), + AsyncChild( + value: associationList, + builder: (context, associations) => Column( + children: [ + ...memberProvider.memberships.map( + (e) => AssociationCard( + association: associations.firstWhere( + (association) => association.id == e.associationId), + onClicked: () { + associationNotifier.setAssociation( + associations.firstWhere((association) => + association.id == e.associationId)); + QR.to(PhonebookRouter.root + + PhonebookRouter.associationDetail); + }, + showMemberRole: true, + member: memberProvider, + ), + ), + ], + ), + ), + ], ), - if (memberProvider.memberships.isNotEmpty) - Text( - memberProvider.memberships.length == 1 - ? PhonebookTextConstants.association - : PhonebookTextConstants.associations, - style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 20)), - const SizedBox( - height: 20, - ), - ...memberProvider.memberships.map((e) => AssociationCard( - association: associationList - .firstWhere((association) => association.id == e.associationId), - onClicked: () { - associationNotifier.setAssociation(associationList.firstWhere( - (association) => association.id == e.associationId)); - QR.to(PhonebookRouter.root + PhonebookRouter.associationDetail); - }, - giveMemberRole: true)), - ])); + ); } } diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index c5dab2b8a..ea1dd7524 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -5,7 +5,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; -import 'package:myecl/phonebook/providers/edition_provider.dart'; +import 'package:myecl/phonebook/providers/is_edit_provider.dart'; import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; @@ -14,6 +14,7 @@ import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; +import 'package:myecl/tools/ui/builders/async_child.dart'; import 'package:myecl/tools/ui/builders/waiting_button.dart'; import 'package:myecl/tools/ui/layouts/add_edit_button_layout.dart'; import 'package:myecl/tools/ui/widgets/align_left_text.dart'; @@ -31,14 +32,14 @@ class MembershipEditorPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final rolesTags = ref.watch(rolesTagsProvider); + final rolesTagList = ref.watch(rolesTagsProvider); final queryController = useTextEditingController(text: ''); final usersNotifier = ref.watch(userList.notifier); final rolesTagsNotifier = ref.watch(rolesTagsProvider.notifier); final apparentNameController = useTextEditingController(text: ''); final member = ref.watch(completeMemberProvider); final association = ref.watch(associationProvider); - final edition = ref.watch(editionProvider); + final isEdit = ref.watch(isEditProvider); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); @@ -49,7 +50,7 @@ class MembershipEditorPage extends HookConsumerWidget { displayToast(context, type, msg); } - if (edition) { + if (isEdit) { apparentNameController.text = member.memberships .where((e) => e.associationId == association.id) .toList()[0] @@ -62,10 +63,10 @@ class MembershipEditorPage extends HookConsumerWidget { child: SingleChildScrollView( child: Column( children: [ - AlignLeftText(edition + AlignLeftText(isEdit ? PhonebookTextConstants.editMembership : PhonebookTextConstants.addMember), - if (!edition) + if (!isEdit) StyledSearchBar( padding: EdgeInsets.zero, label: PhonebookTextConstants.member, @@ -86,37 +87,36 @@ class MembershipEditorPage extends HookConsumerWidget { SearchResult(queryController: queryController), SizedBox( width: min(MediaQuery.of(context).size.width, 300), - child: Column(children: [ - ...rolesTags.when( - data: (data) { - return data.keys - .map((e) => Row(children: [ - Text(e), - const Spacer(), - Checkbox( - value: data[e]!.maybeWhen( - data: (d) => d[0], - orElse: () => false, - ), - fillColor: - MaterialStateProperty.all(Colors.black), - onChanged: (value) { - data[e] = AsyncData([value!]); - apparentNameController.text = - nameConstructor(data); - memberRoleTagsNotifier - .setRoleTagsWithFilter(data); - rolesTagsNotifier.setTData( - e, AsyncData([value])); - }, - ), - ])) - .toList(); - }, - error: (e, s) => [const Text('Error')], - loading: () => [const Text('Loading')], - ), - ]), + child: AsyncChild( + value: rolesTagList, + builder: (context, rolesTags) => Column(children: [ + ...rolesTags.keys.map( + (tagKeys) => Row( + children: [ + Text(tagKeys), + const Spacer(), + Checkbox( + value: rolesTags[tagKeys]!.maybeWhen( + data: (d) => d[0], + orElse: () => false, + ), + fillColor: + MaterialStateProperty.all(Colors.black), + onChanged: (value) { + rolesTags[tagKeys] = AsyncData([value!]); + apparentNameController.text = + nameConstructor(rolesTags); + memberRoleTagsNotifier + .setRoleTagsWithFilter(rolesTags); + rolesTagsNotifier.setTData( + tagKeys, AsyncData([value])); + }, + ), + ], + ), + ) + ]), + ), ), const SizedBox(height: 30), TextEntry( @@ -130,7 +130,7 @@ class MembershipEditorPage extends HookConsumerWidget { ColorConstants.gradient2, ], child: child), child: Text( - !edition + !isEdit ? PhonebookTextConstants.add : PhonebookTextConstants.edit, style: const TextStyle( @@ -150,7 +150,7 @@ class MembershipEditorPage extends HookConsumerWidget { return; } tokenExpireWrapper(ref, () async { - if (edition) { + if (isEdit) { final value = await associationNotifier.updateMember( member.memberships.firstWhere((element) => element.associationId == association.id), diff --git a/pubspec.lock b/pubspec.lock index cd1300126..4ce9cdd63 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -701,6 +701,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" lints: dependency: transitive description: @@ -729,26 +753,26 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" mime: dependency: transitive description: @@ -801,10 +825,10 @@ packages: dependency: "direct main" description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_parsing: dependency: transitive description: @@ -1218,6 +1242,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + url: "https://pub.dev" + source: hosted + version: "13.0.0" web: dependency: transitive description: From 12a98aac1487508e754d2dae272e511920c8726f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Tue, 27 Feb 2024 11:48:27 +0100 Subject: [PATCH 068/123] fix: memberships --- lib/phonebook/class/membership.dart | 50 ++++++++--------- .../providers/association_provider.dart | 13 ++--- .../repositories/association_repository.dart | 22 ++------ lib/phonebook/tools/constants.dart | 2 + .../association_editor_page.dart | 15 +++-- .../member_editable_card.dart | 20 +++++-- .../association_page/association_page.dart | 39 ------------- .../pages/association_page/member_card.dart | 19 ++++--- .../membership_editor_page.dart | 55 ++++++++++++------- 9 files changed, 110 insertions(+), 125 deletions(-) diff --git a/lib/phonebook/class/membership.dart b/lib/phonebook/class/membership.dart index db93a6ebf..360a40533 100644 --- a/lib/phonebook/class/membership.dart +++ b/lib/phonebook/class/membership.dart @@ -1,29 +1,36 @@ class Membership { - Membership({ - required this.id, - required this.associationId, - required this.rolesTags, - required this.apparentName, - }); + Membership( + {required this.id, + required this.associationId, + required this.memberId, + required this.rolesTags, + required this.apparentName, + required this.mandateYear}); late final String id; late final String associationId; + late final String memberId; late final List rolesTags; late final String apparentName; + late final int mandateYear; Membership.fromJson(Map json) { id = json['id']; associationId = json['association_id']; + memberId = json['user_id']; rolesTags = json['role_tags'].split(";"); apparentName = json['role_name']; + mandateYear = json['mandate_year']; } Map toJson() { final data = { 'id': id, - 'association': associationId, + 'association_id': associationId, + 'user_id': memberId, 'role_tags': rolesTags.join(";"), 'role_name': apparentName, + 'mandate_year': mandateYear }; return data; } @@ -31,38 +38,31 @@ class Membership { Membership copyWith({ String? id, String? associationId, + String? memberId, List? rolesTags, String? apparentName, + int? mandateYear, }) { return Membership( - id: id ?? this.id, - associationId: associationId ?? this.associationId, - rolesTags: rolesTags ?? this.rolesTags, - apparentName: apparentName ?? this.apparentName, - ); + id: id ?? this.id, + associationId: associationId ?? this.associationId, + memberId: memberId ?? this.memberId, + rolesTags: rolesTags ?? this.rolesTags, + apparentName: apparentName ?? this.apparentName, + mandateYear: mandateYear ?? this.mandateYear); } Membership.empty() { id = ""; associationId = ""; + memberId = ""; rolesTags = []; apparentName = ""; - } - - Membership setAssociation(String id) { - return copyWith(associationId: id); - } - - Membership setRolesTags(List rolesTags) { - return copyWith(rolesTags: rolesTags); - } - - Membership setApparentName(String apparentName) { - return copyWith(apparentName: apparentName); + mandateYear = 0; } @override String toString() { - return 'Membership(id: $id, association: $associationId, rolesTags: ${rolesTags.join(";")}, apparentName: $apparentName)'; + return 'Membership(id: $id, associationId: $associationId, memberId: $memberId, rolesTags: ${rolesTags.join(";")}, apparentName: $apparentName,mandateYear: $mandateYear)'; } } diff --git a/lib/phonebook/providers/association_provider.dart b/lib/phonebook/providers/association_provider.dart index 4b8817e00..52ee2df49 100644 --- a/lib/phonebook/providers/association_provider.dart +++ b/lib/phonebook/providers/association_provider.dart @@ -18,11 +18,9 @@ class AssociationNotifier extends SingleNotifier { () async => associationRepository.getAssociation(associationId)); } - Future addMember(Association association, Member member, - List rolesTags, String apparentName) async { + Future addMember(Membership membership, Association association) async { return await update( - (association) async => associationRepository.addMember( - association, member, rolesTags, apparentName), + (association) async => associationRepository.addMember(membership), association); } @@ -33,11 +31,10 @@ class AssociationNotifier extends SingleNotifier { association); } - Future updateMember(Membership membership, Association association, - Member user, List rolesTags, String apparentName) async { + Future updateMember( + Membership membership, Association association) async { return await update( - (association) async => associationRepository.updateMember( - membership, association, user, rolesTags, apparentName), + (association) async => associationRepository.updateMember(membership), association); } diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index f806e9be8..87a54f330 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -30,14 +30,8 @@ class AssociationRepository extends Repository { return Association.fromJson(await create(association.toJson())); } - Future addMember(Association association, Member member, - List rolesTags, String apparentName) async { - final value = await create({ - "user_id": member.id, - "association_id": association.id, - "role_tags": rolesTags.join(";"), - "role_name": apparentName - }, suffix: "memberships"); + Future addMember(Membership membership) async { + final value = await create(membership.toJson(), suffix: "memberships"); return value != null; } @@ -45,15 +39,9 @@ class AssociationRepository extends Repository { return await delete("memberships/${membership.id}"); } - Future updateMember(Membership membership, Association association, - Member member, List rolesTags, String apparentName) async { - return await update({ - "id": membership.id, - "member_id": member.id, - "association_id": association.id, - "role_tags": rolesTags.join(";"), - "role_name": apparentName - }, "memberships/", suffix: membership.id); + Future updateMember(Membership membership) async { + return await update(membership.toJson(), "memberships/", + suffix: membership.id); } Future getAssociationKinds() async { diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index 734ae2d4a..0bfce799d 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -59,6 +59,8 @@ class PhonebookTextConstants { static const String errorLoadProfilePicture = "Erreur"; static const String errorRoleTagsLoading = "Erreur lors du chargement des tags de rôle"; + static const String existingMembership = + "Ce membre est déjà dans le mandat actuel"; static const String firstname = "Prénom :"; diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 9de1c82ce..312045314 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -3,13 +3,14 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; -import 'package:myecl/phonebook/providers/is_edit_provider.dart'; +import 'package:myecl/phonebook/providers/membership_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; @@ -45,7 +46,7 @@ class AssociationEditorPage extends HookConsumerWidget { final name = useTextEditingController(text: association.name); final description = useTextEditingController(text: association.description); final rolesTagsNotifier = ref.watch(rolesTagsProvider.notifier); - final isEditNotifier = ref.watch(isEditProvider.notifier); + final membershipNotifier = ref.watch(membershipProvider.notifier); final completeMemberNotifier = ref.watch(completeMemberProvider.notifier); void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); @@ -249,7 +250,8 @@ class AssociationEditorPage extends HookConsumerWidget { rolesTagsNotifier.resetChecked(); completeMemberNotifier .setCompleteMember(CompleteMember.empty()); - isEditNotifier.setStatus(false); + membershipNotifier.setMembership(Membership.empty() + .copyWith(associationId: association.id)); if (QR.currentPath.contains(PhonebookRouter.admin)) { QR.to(PhonebookRouter.root + PhonebookRouter.admin + @@ -279,7 +281,12 @@ class AssociationEditorPage extends HookConsumerWidget { ? const Text(PhonebookTextConstants.noMember) : Column( children: associationMembers - .map((member) => MemberEditableCard(member: member)) + .map( + (member) => MemberEditableCard( + member: member, + association: association, + ), + ) .toList(), ), ), diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index ea1932f3e..f9df09178 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -1,11 +1,15 @@ import 'package:auto_size_text/auto_size_text.dart'; +import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/providers/is_edit_provider.dart'; +import 'package:myecl/phonebook/providers/membership_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/delete_button.dart'; @@ -16,24 +20,32 @@ import 'package:myecl/phonebook/tools/constants.dart'; import 'package:qlevar_router/qlevar_router.dart'; class MemberEditableCard extends HookConsumerWidget { - const MemberEditableCard({super.key, required this.member}); + const MemberEditableCard( + {super.key, required this.member, required this.association}); final CompleteMember member; + final Association association; @override Widget build(BuildContext context, WidgetRef ref) { final profilePicture = ref.watch(profilePictureProvider); - final association = ref.watch(associationProvider); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationMembersNotifier = ref.watch(associationMemberListProvider.notifier); final roleTagsNotifier = ref.watch(rolesTagsProvider.notifier); - final isEditNotifier = ref.watch(isEditProvider.notifier); + final membershipNotifier = ref.watch(membershipProvider.notifier); final completeMemberNotifier = ref.watch(completeMemberProvider.notifier); void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); } + Membership? assoMembership = member.memberships.firstWhereOrNull( + (memberships) => + memberships.associationId == association.id && + memberships.mandateYear == association.mandateYear); + + assoMembership ??= Membership.empty(); + return Container( padding: const EdgeInsets.all(5), margin: const EdgeInsets.symmetric(horizontal: 30, vertical: 10), @@ -101,7 +113,7 @@ class MemberEditableCard extends HookConsumerWidget { roleTagsNotifier.resetChecked(); roleTagsNotifier.loadRoleTagsFromMember(member, association); completeMemberNotifier.setCompleteMember(member); - isEditNotifier.setStatus(true); + membershipNotifier.setMembership(assoMembership!); if (QR.currentPath.contains(PhonebookRouter.admin)) { QR.to(PhonebookRouter.root + PhonebookRouter.admin + diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index 038b97e9a..90c2abc8c 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -38,45 +38,6 @@ class AssociationPage extends HookConsumerWidget { children: [ Column( children: [ - // Container( - // decoration: BoxDecoration( - // shape: BoxShape.circle, - // boxShadow: [ - // BoxShadow( - // color: Colors.black.withOpacity(0.1), - // spreadRadius: 5, - // blurRadius: 10, - // offset: const Offset(2, 3), - // ), - // ], - // ), - // child: associationPicture.when( - // data: (picture) { - // return Container( - // width: 40, - // height: 40, - // decoration: BoxDecoration( - // shape: BoxShape.circle, - // image: DecorationImage( - // image: picture.image, - // fit: BoxFit.cover, - // ), - // ), - // ); - // }, - // loading: () { - // return const Center( - // child: CircularProgressIndicator(), - // ); - // }, - // error: (e, s) { - // return const Center( - // child: Text( - // PhonebookTextConstants.errorLoadAssociationPicture), - // ); - // }, - // ), - // ), const SizedBox(height: 20), Text( association.name, diff --git a/lib/phonebook/ui/pages/association_page/member_card.dart b/lib/phonebook/ui/pages/association_page/member_card.dart index f3e748e0d..e13c33dd7 100644 --- a/lib/phonebook/ui/pages/association_page/member_card.dart +++ b/lib/phonebook/ui/pages/association_page/member_card.dart @@ -1,3 +1,4 @@ +import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart' show kIsWeb; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -22,9 +23,10 @@ class MemberCard extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final memberNotifier = ref.watch(completeMemberProvider.notifier); - List assoMembership = member.memberships - .where((memberships) => memberships.associationId == association.id) - .toList(); + Membership? assoMembership = member.memberships.firstWhereOrNull( + (memberships) => + memberships.associationId == association.id && + memberships.mandateYear == association.mandateYear); return GestureDetector( onTap: () { @@ -73,10 +75,9 @@ class MemberCard extends HookConsumerWidget { ), flex: 1), CopiabledText( - member.memberships - .firstWhere((element) => - element.associationId == association.id) - .apparentName, + assoMembership == null + ? PhonebookTextConstants.noMemberRole + : assoMembership.apparentName, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, @@ -114,9 +115,9 @@ class MemberCard extends HookConsumerWidget { ), const Spacer(flex: 1), Text( - assoMembership.isEmpty + assoMembership == null ? PhonebookTextConstants.noMemberRole - : assoMembership.first.apparentName, + : assoMembership.apparentName, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index ea1dd7524..8ddd5ef8d 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -3,10 +3,11 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; -import 'package:myecl/phonebook/providers/is_edit_provider.dart'; import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; +import 'package:myecl/phonebook/providers/membership_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/tools/function.dart'; @@ -38,8 +39,9 @@ class MembershipEditorPage extends HookConsumerWidget { final rolesTagsNotifier = ref.watch(rolesTagsProvider.notifier); final apparentNameController = useTextEditingController(text: ''); final member = ref.watch(completeMemberProvider); + final membership = ref.watch(membershipProvider); final association = ref.watch(associationProvider); - final isEdit = ref.watch(isEditProvider); + final isEdit = membership.id != Membership.empty().id; final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); @@ -50,12 +52,7 @@ class MembershipEditorPage extends HookConsumerWidget { displayToast(context, type, msg); } - if (isEdit) { - apparentNameController.text = member.memberships - .where((e) => e.associationId == association.id) - .toList()[0] - .apparentName; - } + apparentNameController.text = membership.apparentName; return PhonebookTemplate( child: Padding( @@ -97,7 +94,7 @@ class MembershipEditorPage extends HookConsumerWidget { const Spacer(), Checkbox( value: rolesTags[tagKeys]!.maybeWhen( - data: (d) => d[0], + data: (rolesTag) => rolesTag[0], orElse: () => false, ), fillColor: @@ -149,15 +146,30 @@ class MembershipEditorPage extends HookConsumerWidget { PhonebookTextConstants.emptyApparentName); return; } + print(member.memberships.map((mappedMembership) => ( + mappedMembership.associationId, + mappedMembership.memberId, + mappedMembership.mandateYear + ))); + print(( + membership.associationId, + membership.memberId, + membership.mandateYear + )); tokenExpireWrapper(ref, () async { if (isEdit) { + final membershipEdit = Membership( + id: membership.id, + memberId: membership.memberId, + associationId: membership.associationId, + rolesTags: memberRoleTags, + apparentName: apparentNameController.text, + mandateYear: membership.mandateYear, + ); final value = await associationNotifier.updateMember( - member.memberships.firstWhere((element) => - element.associationId == association.id), - association, - member.member, - memberRoleTags, - apparentNameController.text); + membershipEdit, + association, + ); if (value) { associationMemberListNotifier.loadMembers( association.id, @@ -171,11 +183,16 @@ class MembershipEditorPage extends HookConsumerWidget { PhonebookTextConstants.updatingError); } } else { + final membershipAdd = Membership( + id: "", + memberId: member.member.id, + associationId: association.id, + rolesTags: memberRoleTags, + apparentName: apparentNameController.text, + mandateYear: association.mandateYear, + ); final value = await associationNotifier.addMember( - association, - member.member, - memberRoleTags, - apparentNameController.text); + membershipAdd, association); if (value) { associationMemberListNotifier.loadMembers( association.id, From 8277f9880c8c1ac773faadc7f2f9522c08f310b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Tue, 27 Feb 2024 12:03:34 +0100 Subject: [PATCH 069/123] fix: unused imports --- lib/phonebook/providers/association_provider.dart | 1 - lib/phonebook/repositories/association_repository.dart | 1 - .../ui/pages/association_editor_page/member_editable_card.dart | 1 - 3 files changed, 3 deletions(-) diff --git a/lib/phonebook/providers/association_provider.dart b/lib/phonebook/providers/association_provider.dart index 52ee2df49..58d591f99 100644 --- a/lib/phonebook/providers/association_provider.dart +++ b/lib/phonebook/providers/association_provider.dart @@ -1,7 +1,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/class/member.dart'; import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/repositories/association_repository.dart'; import 'package:myecl/tools/providers/single_notifier.dart'; diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index 87a54f330..5e1614c1b 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -1,6 +1,5 @@ import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/association_kinds.dart'; -import 'package:myecl/phonebook/class/member.dart'; import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/tools/repository/repository.dart'; diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index f9df09178..8354cbc3b 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -8,7 +8,6 @@ import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; -import 'package:myecl/phonebook/providers/is_edit_provider.dart'; import 'package:myecl/phonebook/providers/membership_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/router.dart'; From ba356885a4861e27dcf3f2beb6bb242645744ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Tue, 27 Feb 2024 12:07:26 +0100 Subject: [PATCH 070/123] fix: add padding --- lib/phonebook/ui/pages/main_page/association_card.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/phonebook/ui/pages/main_page/association_card.dart b/lib/phonebook/ui/pages/main_page/association_card.dart index 4de0a3fa9..c16a03025 100644 --- a/lib/phonebook/ui/pages/main_page/association_card.dart +++ b/lib/phonebook/ui/pages/main_page/association_card.dart @@ -30,7 +30,7 @@ class AssociationCard extends HookConsumerWidget { } return Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), + padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 5), child: GestureDetector( onTap: onClicked, child: CardLayout( From e09e9fbbe53f9132ad41c4ef47ffd4708b52806b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Tue, 27 Feb 2024 12:16:55 +0100 Subject: [PATCH 071/123] fix: research bar autocompletion --- .../membership_editor_page.dart | 11 +---------- .../pages/membership_editor_page/search_result.dart | 12 ++++++------ 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index 8ddd5ef8d..ff4700f7e 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -67,6 +67,7 @@ class MembershipEditorPage extends HookConsumerWidget { StyledSearchBar( padding: EdgeInsets.zero, label: PhonebookTextConstants.member, + editingController: queryController, onChanged: (value) async { tokenExpireWrapper(ref, () async { queryController.text = value; @@ -146,16 +147,6 @@ class MembershipEditorPage extends HookConsumerWidget { PhonebookTextConstants.emptyApparentName); return; } - print(member.memberships.map((mappedMembership) => ( - mappedMembership.associationId, - mappedMembership.memberId, - mappedMembership.mandateYear - ))); - print(( - membership.associationId, - membership.memberId, - membership.mandateYear - )); tokenExpireWrapper(ref, () async { if (isEdit) { final membershipEdit = Membership( diff --git a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart index 23eca7a28..12459b287 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart @@ -15,10 +15,10 @@ class SearchResult extends HookConsumerWidget { final memberNotifier = ref.watch(completeMemberProvider.notifier); return users.when( - data: (u) { + data: (usersData) { return Column( - children: u - .map((e) => GestureDetector( + children: usersData + .map((user) => GestureDetector( child: Padding( padding: const EdgeInsets.all(8.0), child: Row( @@ -29,7 +29,7 @@ class SearchResult extends HookConsumerWidget { ), Expanded( child: Text( - e.getName(), + user.getName(), style: const TextStyle( fontSize: 13, ), @@ -39,8 +39,8 @@ class SearchResult extends HookConsumerWidget { ]), ), onTap: () { - memberNotifier.setMember(Member.fromUser(e)); - queryController.text = e.getName(); + memberNotifier.setMember(Member.fromUser(user)); + queryController.text = user.getName(); usersNotifier.clear(); })) .toList()); From 2c72fdedb0d24c36dfda7b23d85f0d1cbf5316a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Tue, 27 Feb 2024 12:40:03 +0100 Subject: [PATCH 072/123] fix: split association card and membership card --- .../ui/pages/main_page/association_card.dart | 22 +-------- .../ui/pages/main_page/main_page.dart | 1 - .../member_detail_page.dart | 30 +++++++------ .../member_detail_page/membership_card.dart | 45 +++++++++++++++++++ 4 files changed, 62 insertions(+), 36 deletions(-) create mode 100644 lib/phonebook/ui/pages/member_detail_page/membership_card.dart diff --git a/lib/phonebook/ui/pages/main_page/association_card.dart b/lib/phonebook/ui/pages/main_page/association_card.dart index c16a03025..657c82487 100644 --- a/lib/phonebook/ui/pages/main_page/association_card.dart +++ b/lib/phonebook/ui/pages/main_page/association_card.dart @@ -1,9 +1,6 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/class/complete_member.dart'; -import 'package:myecl/phonebook/class/membership.dart'; -import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/tools/ui/layouts/card_layout.dart'; class AssociationCard extends HookConsumerWidget { @@ -11,24 +8,13 @@ class AssociationCard extends HookConsumerWidget { super.key, required this.association, required this.onClicked, - this.showMemberRole = false, - this.member, }); final Association association; final VoidCallback onClicked; - final bool showMemberRole; - final CompleteMember? member; @override Widget build(BuildContext context, WidgetRef ref) { - List assoMembership = []; - if (member != null) { - assoMembership = member!.memberships - .where((memberships) => memberships.associationId == association.id) - .toList(); - } - return Padding( padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 5), child: GestureDetector( @@ -46,13 +32,7 @@ class AssociationCard extends HookConsumerWidget { ), ), const Spacer(flex: 1), - Text(!showMemberRole - ? association.kind - : member == null - ? PhonebookTextConstants.noMember - : assoMembership.isEmpty - ? PhonebookTextConstants.noMemberRole - : assoMembership.first.apparentName) + Text(association.kind) ], ), ), diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 26f0172c5..a04d376fb 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -122,7 +122,6 @@ class PhonebookMainPage extends HookConsumerWidget { QR.to(PhonebookRouter.root + PhonebookRouter.associationDetail); }, - showMemberRole: false, ), ) ], diff --git a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart index 777ca8c46..92cf9bc17 100644 --- a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart +++ b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart @@ -5,8 +5,8 @@ import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/ui/pages/main_page/association_card.dart'; import 'package:myecl/phonebook/ui/pages/member_detail_page/element_field.dart'; +import 'package:myecl/phonebook/ui/pages/member_detail_page/membership_card.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/tools/ui/builders/async_child.dart'; import 'package:myecl/tools/ui/layouts/card_layout.dart'; @@ -72,19 +72,21 @@ class MemberDetailPage extends HookConsumerWidget { builder: (context, associations) => Column( children: [ ...memberProvider.memberships.map( - (e) => AssociationCard( - association: associations.firstWhere( - (association) => association.id == e.associationId), - onClicked: () { - associationNotifier.setAssociation( - associations.firstWhere((association) => - association.id == e.associationId)); - QR.to(PhonebookRouter.root + - PhonebookRouter.associationDetail); - }, - showMemberRole: true, - member: memberProvider, - ), + (membership) { + final associationMembership = associations.firstWhere( + (association) => + association.id == membership.associationId); + return MembershipCard( + association: associationMembership, + onClicked: () { + associationNotifier + .setAssociation(associationMembership); + QR.to(PhonebookRouter.root + + PhonebookRouter.associationDetail); + }, + membership: membership, + ); + }, ), ], ), diff --git a/lib/phonebook/ui/pages/member_detail_page/membership_card.dart b/lib/phonebook/ui/pages/member_detail_page/membership_card.dart new file mode 100644 index 000000000..a7aca5961 --- /dev/null +++ b/lib/phonebook/ui/pages/member_detail_page/membership_card.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/class/membership.dart'; +import 'package:myecl/tools/ui/layouts/card_layout.dart'; + +class MembershipCard extends HookConsumerWidget { + const MembershipCard({ + super.key, + required this.association, + required this.membership, + required this.onClicked, + }); + + final Association association; + final VoidCallback onClicked; + final Membership membership; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 5), + child: GestureDetector( + onTap: onClicked, + child: CardLayout( + margin: EdgeInsets.zero, + child: Row( + children: [ + const SizedBox(width: 10), + Text( + "${association.name} - ${membership.mandateYear}", + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + const Spacer(flex: 1), + Text(membership.apparentName) + ], + ), + ), + ), + ); + } +} From badf7643604ac99ef5bd71524ef100c1b465aaee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Tue, 27 Feb 2024 22:51:25 +0100 Subject: [PATCH 073/123] fix: set default asso year to now year --- .../association_creation_page.dart | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart index b619eb36c..948f9ea7d 100644 --- a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart +++ b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart @@ -128,11 +128,14 @@ class AssociationCreationPage extends HookConsumerWidget { return; } await tokenExpireWrapper(ref, () async { - final value = await associationListNotifier - .createAssociation(Association.empty().copyWith( - name: name.text, - description: description.text, - kind: kind.value)); + final value = + await associationListNotifier.createAssociation( + Association.empty().copyWith( + name: name.text, + description: description.text, + kind: kind.value, + mandateYear: DateTime.now().year), + ); if (value) { displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.addedAssociation); From 03e154510a119408b6f99fdcd2bf8a714f465299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Tue, 27 Feb 2024 23:22:13 +0100 Subject: [PATCH 074/123] fix: simplify membership add edit checkbox behavior --- lib/phonebook/providers/is_edit_provider.dart | 13 ------ lib/phonebook/tools/function.dart | 18 -------- .../membership_editor_page.dart | 43 +++++++++++++------ 3 files changed, 31 insertions(+), 43 deletions(-) delete mode 100644 lib/phonebook/providers/is_edit_provider.dart diff --git a/lib/phonebook/providers/is_edit_provider.dart b/lib/phonebook/providers/is_edit_provider.dart deleted file mode 100644 index 1cd77f041..000000000 --- a/lib/phonebook/providers/is_edit_provider.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; - -final isEditProvider = StateNotifierProvider((ref) { - return IsEditProvider(); -}); - -class IsEditProvider extends StateNotifier { - IsEditProvider() : super(false); - - void setStatus(bool i) { - state = i; - } -} diff --git a/lib/phonebook/tools/function.dart b/lib/phonebook/tools/function.dart index b95af8232..fe918ecda 100644 --- a/lib/phonebook/tools/function.dart +++ b/lib/phonebook/tools/function.dart @@ -1,28 +1,10 @@ import 'dart:math'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/association_kinds.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/membership.dart'; -String nameConstructor(Map>?> data) { - String name = ''; - data.forEach((key, value) { - value?.maybeWhen( - data: (d) { - if (d[0]) { - name += "$key, "; - } - }, - orElse: () {}); - }); - if (name.isEmpty) { - return ""; - } - return name.substring(0, name.length - 2); -} - int getPosition( CompleteMember member, String associationId, List rolesTags) { Membership membership = member.memberships diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index ff4700f7e..24e3529b6 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -10,7 +10,6 @@ import 'package:myecl/phonebook/providers/member_role_tags_provider.dart'; import 'package:myecl/phonebook/providers/membership_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/tools/function.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; @@ -37,7 +36,6 @@ class MembershipEditorPage extends HookConsumerWidget { final queryController = useTextEditingController(text: ''); final usersNotifier = ref.watch(userList.notifier); final rolesTagsNotifier = ref.watch(rolesTagsProvider.notifier); - final apparentNameController = useTextEditingController(text: ''); final member = ref.watch(completeMemberProvider); final membership = ref.watch(membershipProvider); final association = ref.watch(associationProvider); @@ -47,13 +45,13 @@ class MembershipEditorPage extends HookConsumerWidget { ref.watch(associationMemberListProvider.notifier); final memberRoleTagsNotifier = ref.watch(memberRoleTagsProvider.notifier); final memberRoleTags = ref.watch(memberRoleTagsProvider); + final apparentNameController = + useTextEditingController(text: membership.apparentName); void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); } - apparentNameController.text = membership.apparentName; - return PhonebookTemplate( child: Padding( padding: const EdgeInsets.all(30.0), @@ -78,7 +76,23 @@ class MembershipEditorPage extends HookConsumerWidget { } }); }, - ), + ) + else + member.member.nickname == null + ? Text( + "${member.member.firstname} ${member.member.name}", + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + ), + ) + : Text( + "${member.member.nickname} (${member.member.firstname} ${member.member.name})", + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + ), + ), const SizedBox( height: 10, ), @@ -89,25 +103,30 @@ class MembershipEditorPage extends HookConsumerWidget { value: rolesTagList, builder: (context, rolesTags) => Column(children: [ ...rolesTags.keys.map( - (tagKeys) => Row( + (tagKey) => Row( children: [ - Text(tagKeys), + Text(tagKey), const Spacer(), Checkbox( - value: rolesTags[tagKeys]!.maybeWhen( + value: rolesTags[tagKey]!.maybeWhen( data: (rolesTag) => rolesTag[0], orElse: () => false, ), fillColor: MaterialStateProperty.all(Colors.black), onChanged: (value) { - rolesTags[tagKeys] = AsyncData([value!]); - apparentNameController.text = - nameConstructor(rolesTags); + rolesTags[tagKey] = AsyncData([value!]); memberRoleTagsNotifier .setRoleTagsWithFilter(rolesTags); rolesTagsNotifier.setTData( - tagKeys, AsyncData([value])); + tagKey, AsyncData([value])); + if (value && + apparentNameController.text == "") { + apparentNameController.text = tagKey; + } else if (!value && + apparentNameController.text == tagKey) { + apparentNameController.text = ""; + } }, ), ], From 28b8d755c7c7c45f8767ffc2d79fe9bce4288366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 00:52:48 +0100 Subject: [PATCH 075/123] fix: validation while adding existing membership --- lib/phonebook/class/complete_member.dart | 7 ++++-- .../providers/complete_member_provider.dart | 21 ++++++++++++++-- .../repositories/member_repository.dart | 17 +------------ .../membership_editor_page.dart | 24 +++++++++++++++---- .../membership_editor_page/search_result.dart | 1 + 5 files changed, 46 insertions(+), 24 deletions(-) diff --git a/lib/phonebook/class/complete_member.dart b/lib/phonebook/class/complete_member.dart index 004f086fe..187ec6c17 100644 --- a/lib/phonebook/class/complete_member.dart +++ b/lib/phonebook/class/complete_member.dart @@ -19,8 +19,11 @@ class CompleteMember { email: json['email'], phone: json['phone'], promotion: json['promo'] ?? 0); - memberships = List.from(json['memberships'] - .map((membership) => Membership.fromJson(membership))); + memberships = List.from( + json['memberships'].map((membership) { + return Membership.fromJson(membership); + }), + ); } Map toJson() { diff --git a/lib/phonebook/providers/complete_member_provider.dart b/lib/phonebook/providers/complete_member_provider.dart index 8ef8973c4..400b47485 100644 --- a/lib/phonebook/providers/complete_member_provider.dart +++ b/lib/phonebook/providers/complete_member_provider.dart @@ -1,14 +1,21 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/member.dart'; +import 'package:myecl/phonebook/repositories/member_repository.dart'; final completeMemberProvider = StateNotifierProvider((ref) { - return CompleteMemberProvider(); + final token = ref.watch(tokenProvider); + return CompleteMemberProvider(token: token); }); class CompleteMemberProvider extends StateNotifier { - CompleteMemberProvider() : super(CompleteMember.empty()); + final MemberRepository memberRepository = MemberRepository(); + CompleteMemberProvider({required String token}) + : super(CompleteMember.empty()) { + memberRepository.setToken(token); + } void setCompleteMember(CompleteMember i) { state = i; @@ -17,4 +24,14 @@ class CompleteMemberProvider extends StateNotifier { void setMember(Member i) { state = state.copyWith(member: i); } + + Future loadMembership() async { + try { + final data = await memberRepository.getCompleteMember(state.member.id); + state = state.copyWith(membership: data.memberships); + return true; + } catch (e) { + return false; + } + } } diff --git a/lib/phonebook/repositories/member_repository.dart b/lib/phonebook/repositories/member_repository.dart index 0231a1412..d12fead5a 100644 --- a/lib/phonebook/repositories/member_repository.dart +++ b/lib/phonebook/repositories/member_repository.dart @@ -1,6 +1,4 @@ import 'package:myecl/phonebook/class/complete_member.dart'; -import 'package:myecl/phonebook/class/member.dart'; -import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/tools/repository/repository.dart'; class MemberRepository extends Repository { @@ -8,20 +6,7 @@ class MemberRepository extends Repository { // ignore: overridden_fields final ext = "phonebook/member/"; - Future> getMemberMembershipList(int memberId) async { - return List.from((await getList(suffix: "/$memberId/posts")) - .map((x) => Membership.fromJson(x))); - } - - Future getMember(String memberId) async { - return Member.fromJson(await getOne(memberId)); - } - Future getCompleteMember(String memberId) async { - return CompleteMember.fromJson(await getOne(memberId, suffix: "complete")); - } - - Future getMe() async { - return CompleteMember.fromJson(await getOne("me", suffix: "complete")); + return CompleteMember.fromJson(await getOne(memberId)); } } diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index 24e3529b6..8b7aa23e7 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -61,7 +61,7 @@ class MembershipEditorPage extends HookConsumerWidget { AlignLeftText(isEdit ? PhonebookTextConstants.editMembership : PhonebookTextConstants.addMember), - if (!isEdit) + if (!isEdit) ...[ StyledSearchBar( padding: EdgeInsets.zero, label: PhonebookTextConstants.member, @@ -76,8 +76,9 @@ class MembershipEditorPage extends HookConsumerWidget { } }); }, - ) - else + ), + SearchResult(queryController: queryController), + ] else member.member.nickname == null ? Text( "${member.member.firstname} ${member.member.name}", @@ -96,7 +97,6 @@ class MembershipEditorPage extends HookConsumerWidget { const SizedBox( height: 10, ), - SearchResult(queryController: queryController), SizedBox( width: min(MediaQuery.of(context).size.width, 300), child: AsyncChild( @@ -166,6 +166,7 @@ class MembershipEditorPage extends HookConsumerWidget { PhonebookTextConstants.emptyApparentName); return; } + tokenExpireWrapper(ref, () async { if (isEdit) { final membershipEdit = Membership( @@ -193,6 +194,21 @@ class MembershipEditorPage extends HookConsumerWidget { PhonebookTextConstants.updatingError); } } else { + // Test if the membership already exists with (association_id,member_id,mandate_year) + final memberAssociationMemberships = member.memberships + .where((membership) => + membership.associationId == association.id); + + if (memberAssociationMemberships + .where((membership) => + membership.mandateYear == + association.mandateYear) + .isNotEmpty) { + displayToastWithContext(TypeMsg.msg, + PhonebookTextConstants.existingMembership); + return; + } + final membershipAdd = Membership( id: "", memberId: member.member.id, diff --git a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart index 12459b287..d6aae146e 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart @@ -42,6 +42,7 @@ class SearchResult extends HookConsumerWidget { memberNotifier.setMember(Member.fromUser(user)); queryController.text = user.getName(); usersNotifier.clear(); + memberNotifier.loadMembership(); })) .toList()); }, From d75e5b64d451583a5680881c6f6e7eb7b155ae72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 00:59:19 +0100 Subject: [PATCH 076/123] fix: add edit membership research bar --- .../ui/pages/membership_editor_page/membership_editor_page.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index 8b7aa23e7..a9cc92f54 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -68,7 +68,6 @@ class MembershipEditorPage extends HookConsumerWidget { editingController: queryController, onChanged: (value) async { tokenExpireWrapper(ref, () async { - queryController.text = value; if (value.isNotEmpty) { await usersNotifier.filterUsers(value); } else { From b8370e97887aa7597086a1a9717ac5cc5e0d1dbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 09:45:03 +0100 Subject: [PATCH 077/123] fix: routing while not in admin route --- .../pages/association_editor_page/association_editor_page.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 312045314..365bd1784 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -259,6 +259,7 @@ class AssociationEditorPage extends HookConsumerWidget { PhonebookRouter.addEditMember); } else { QR.to(PhonebookRouter.root + + PhonebookRouter.associationDetail + PhonebookRouter.editAssociation + PhonebookRouter.addEditMember); } From 9faf6e3315c58b94460ac6295e212f36d2ea0b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 10:21:24 +0100 Subject: [PATCH 078/123] fix: change edit association button design on association detail --- .../association_page/association_page.dart | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index 90c2abc8c..6b3dec76a 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -89,25 +89,28 @@ class AssociationPage extends HookConsumerWidget { padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 10, - offset: const Offset(0, 5)) - ]), - child: const Row( - children: [ - HeroIcon(HeroIcons.userGroup, color: Colors.white), - SizedBox(width: 10), - Text(PhonebookTextConstants.admin, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.white)), + borderRadius: BorderRadius.circular(10), + gradient: const RadialGradient( + colors: [ + Color.fromARGB(255, 98, 98, 98), + Color.fromARGB(255, 27, 27, 27), + ], + center: Alignment.topLeft, + radius: 1.3, + ), + boxShadow: [ + BoxShadow( + color: const Color.fromARGB(255, 27, 27, 27) + .withOpacity(0.3), + spreadRadius: 5, + blurRadius: 10, + offset: + const Offset(3, 3), // changes position of shadow + ), ], ), + child: + const HeroIcon(HeroIcons.pencil, color: Colors.white), ), ), ), From bb9f3cde1138e1bed59326f4869f1096e3af58f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 10:33:52 +0100 Subject: [PATCH 079/123] fix: member card on mobile --- lib/phonebook/ui/copiabled_text.dart | 24 ++- .../pages/association_page/member_card.dart | 162 +++++++++--------- 2 files changed, 87 insertions(+), 99 deletions(-) diff --git a/lib/phonebook/ui/copiabled_text.dart b/lib/phonebook/ui/copiabled_text.dart index 8663cde74..ce4953538 100644 --- a/lib/phonebook/ui/copiabled_text.dart +++ b/lib/phonebook/ui/copiabled_text.dart @@ -5,11 +5,10 @@ import 'package:myecl/tools/functions.dart'; class CopiabledText extends StatelessWidget { const CopiabledText(this.data, - {super.key, required this.style, required this.flex, this.maxLines = 1}); + {super.key, required this.style, this.maxLines = 1}); final String data; final TextStyle style; - final int flex; final int maxLines; @override @@ -18,17 +17,14 @@ class CopiabledText extends StatelessWidget { displayToast(context, type, msg); } - return Expanded( - flex: flex, - child: Center( - child: SelectableText( - data, - maxLines: maxLines, - style: style, - onTap: () { - Clipboard.setData(ClipboardData(text: data)); - displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.copied); - }, - ))); + return SelectableText( + data, + maxLines: maxLines, + style: style, + onTap: () { + Clipboard.setData(ClipboardData(text: data)); + displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.copied); + }, + ); } } diff --git a/lib/phonebook/ui/pages/association_page/member_card.dart b/lib/phonebook/ui/pages/association_page/member_card.dart index e13c33dd7..a46bfb282 100644 --- a/lib/phonebook/ui/pages/association_page/member_card.dart +++ b/lib/phonebook/ui/pages/association_page/member_card.dart @@ -29,103 +29,95 @@ class MemberCard extends HookConsumerWidget { memberships.mandateYear == association.mandateYear); return GestureDetector( - onTap: () { - memberNotifier.setCompleteMember(member); - QR.to(PhonebookRouter.root + PhonebookRouter.memberDetail); - }, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), - child: CardLayout( - margin: EdgeInsets.zero, - child: Row( - children: [ - const SizedBox(width: 20), - if (!kIsWeb) ...[ - if (member.member.nickname != null) - CopiabledText( + onTap: () { + memberNotifier.setCompleteMember(member); + QR.to(PhonebookRouter.root + PhonebookRouter.memberDetail); + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 5), + child: CardLayout( + margin: EdgeInsets.zero, + child: Row( + children: [ + if (!kIsWeb) ...[ + if (member.member.nickname != null) ...[ + CopiabledText( + member.member.nickname!, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + CopiabledText( + "(${member.member.name} ${member.member.firstname})", + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + color: Color.fromARGB(255, 115, 115, 115), + ), + ), + ] else + CopiabledText( + "${member.member.name} ${member.member.firstname}", + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + const Spacer(), + CopiabledText( + assoMembership == null + ? PhonebookTextConstants.noMemberRole + : assoMembership.apparentName, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ) + ] else ...[ + if (member.member.nickname != null) + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( member.member.nickname!, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), - flex: 1, ), - CopiabledText( - "${member.member.name} ${member.member.firstname}", - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - color: member.member.nickname != null - ? const Color.fromARGB(255, 115, 115, 115) - : Colors.black, - ), - flex: 1, - ), - CopiabledText(member.member.email, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - flex: 1), - if (member.member.phone != null) - CopiabledText(member.member.phone!, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - flex: 1), - CopiabledText( - assoMembership == null - ? PhonebookTextConstants.noMemberRole - : assoMembership.apparentName, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - flex: 1) - ] else ...[ - if (member.member.nickname != null) - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - member.member.nickname!, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - const SizedBox(height: 5), - Text( - "${member.member.name} ${member.member.firstname}", - style: const TextStyle( - fontSize: 16, - color: Color.fromARGB(255, 115, 115, 115), - ), - ), - ], - ) - else Text( "${member.member.name} ${member.member.firstname}", style: const TextStyle( - fontWeight: FontWeight.bold, fontSize: 16, + color: Color.fromARGB(255, 115, 115, 115), ), ), - const Spacer(flex: 1), - Text( - assoMembership == null - ? PhonebookTextConstants.noMemberRole - : assoMembership.apparentName, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), + ], + ) + else + Text( + "${member.member.name} ${member.member.firstname}", + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, ), - ], - ], - )), - )); + ), + const Spacer(flex: 1), + Text( + assoMembership == null + ? PhonebookTextConstants.noMemberRole + : assoMembership.apparentName, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ], + ], + ), + ), + ), + ); } } From 54b236c69f9a434b33308c250c0b6f9af9b34047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 11:43:12 +0100 Subject: [PATCH 080/123] refacto: KindsBar --- lib/phonebook/ui/kinds_bar.dart | 48 +++++++++++++++++++ .../ui/pages/admin_page/admin_page.dart | 47 +----------------- .../association_creation_page.dart | 33 +------------ .../association_editor_page.dart | 40 +++------------- .../ui/pages/main_page/main_page.dart | 46 +----------------- 5 files changed, 60 insertions(+), 154 deletions(-) create mode 100644 lib/phonebook/ui/kinds_bar.dart diff --git a/lib/phonebook/ui/kinds_bar.dart b/lib/phonebook/ui/kinds_bar.dart new file mode 100644 index 000000000..cec825b78 --- /dev/null +++ b/lib/phonebook/ui/kinds_bar.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/association_kind_provider.dart'; +import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; +import 'package:myecl/phonebook/providers/association_list_provider.dart'; +import 'package:myecl/phonebook/providers/research_filter_provider.dart'; +import 'package:myecl/tools/ui/builders/async_child.dart'; +import 'package:myecl/tools/ui/layouts/horizontal_list_view.dart'; +import 'package:myecl/tools/ui/layouts/item_chip.dart'; + +class KindsBar extends ConsumerWidget { + const KindsBar({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final kind = ref.watch(associationKindProvider); + final kindNotifier = ref.watch(associationKindProvider.notifier); + final associationKinds = ref.watch(associationKindsProvider); + final nameFilter = ref.watch(filterProvider); + final associationListNotifier = ref.watch(associationListProvider.notifier); + + return AsyncChild( + value: associationKinds, + builder: (context, kinds) => HorizontalListView.builder( + height: 40, + items: kinds.kinds, + itemBuilder: (context, item, index) { + final selected = kind == item; + return ItemChip( + onTap: () { + kindNotifier.setKind(!selected ? item : ""); + associationListNotifier.filterAssociationList( + nameFilter, !selected ? item : ""); + }, + selected: selected, + child: Text( + item, + style: TextStyle( + color: selected ? Colors.white : Colors.black, + fontWeight: FontWeight.bold, + ), + ), + ); + }, + ), + ); + } +} diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 7728d11a8..04d01f76c 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -1,24 +1,20 @@ import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; -import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/tools/function.dart'; +import 'package:myecl/phonebook/ui/kinds_bar.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/association_research_bar.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/editable_association_card.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/ui/builders/async_child.dart'; import 'package:myecl/tools/ui/layouts/card_layout.dart'; -import 'package:myecl/tools/ui/layouts/horizontal_list_view.dart'; -import 'package:myecl/tools/ui/layouts/item_chip.dart'; import 'package:myecl/tools/ui/layouts/refresher.dart'; import 'package:myecl/tools/ui/widgets/dialog.dart'; import 'package:qlevar_router/qlevar_router.dart'; @@ -33,9 +29,6 @@ class AdminPage extends HookConsumerWidget { final associationList = ref.watch(associationListProvider); final roleNotifier = ref.watch(rolesTagsProvider.notifier); final associationKinds = ref.watch(associationKindsProvider); - final kind = useState(''); - final kindNotifier = ref.watch(associationKindProvider.notifier); - final nameFilter = ref.watch(filterProvider); void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); } @@ -61,43 +54,7 @@ class AdminPage extends HookConsumerWidget { associations = sortedAssociation(associations, kinds); return Column( children: [ - HorizontalListView.builder( - height: 40, - items: kinds.kinds, - firstChild: ItemChip( - selected: kind.value == "", - onTap: () { - kind.value = ""; - kindNotifier.setKind(""); - associationListNotifier.filterAssociationList( - nameFilter, kind.value); - }, - child: Text(PhonebookTextConstants.all, - style: TextStyle( - color: kind.value == "" - ? Colors.white - : Colors.black, - fontWeight: FontWeight.bold, - ))), - itemBuilder: (context, item, index) { - final selected = kind.value == item; - return ItemChip( - onTap: () { - kind.value = item; - kindNotifier.setKind(item); - associationListNotifier.filterAssociationList( - nameFilter, kind.value); - }, - selected: selected, - child: Text(item, - style: TextStyle( - color: selected - ? Colors.white - : Colors.black, - fontWeight: FontWeight.bold, - )), - ); - }), + const KindsBar(), GestureDetector( onTap: () { QR.to(PhonebookRouter.root + diff --git a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart index 948f9ea7d..0ad67d4dc 100644 --- a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart +++ b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart @@ -3,19 +3,17 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/admin/tools/constants.dart'; import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/phonebook/ui/kinds_bar.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:myecl/tools/ui/builders/waiting_button.dart'; import 'package:myecl/tools/ui/layouts/add_edit_button_layout.dart'; -import 'package:myecl/tools/ui/layouts/horizontal_list_view.dart'; -import 'package:myecl/tools/ui/layouts/item_chip.dart'; import 'package:myecl/tools/ui/widgets/text_entry.dart'; import 'package:qlevar_router/qlevar_router.dart'; @@ -30,7 +28,6 @@ class AssociationCreationPage extends HookConsumerWidget { final associationListNotifier = ref.watch(associationListProvider.notifier); final associations = ref.watch(associationListProvider); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); - final associationKinds = ref.watch(associationKindsProvider); final kind = useState(''); void displayToastWithContext(TypeMsg type, String msg) { @@ -62,33 +59,7 @@ class AssociationCreationPage extends HookConsumerWidget { const SizedBox( height: 30, ), - associationKinds.when( - data: (association) { - return HorizontalListView.builder( - height: 40, - items: association.kinds, - itemBuilder: (context, item, index) { - final selected = kind.value == item; - return ItemChip( - onTap: () { - kind.value = item; - }, - selected: selected, - child: Text(item, - style: TextStyle( - color: selected ? Colors.white : Colors.black, - fontWeight: FontWeight.bold, - )), - ); - }); - }, - error: (error, stack) { - return const Text(PhonebookTextConstants.errorKindsLoading); - }, - loading: () { - return const CircularProgressIndicator(); - }, - ), + const KindsBar(), Padding( padding: const EdgeInsets.symmetric(horizontal: 30.0), child: Column( diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 365bd1784..9e8fb552d 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -4,7 +4,7 @@ import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/membership.dart'; -import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; +import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; @@ -14,6 +14,7 @@ import 'package:myecl/phonebook/providers/membership_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/phonebook/ui/kinds_bar.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/phonebook/ui/pages/association_editor_page/member_editable_card.dart'; import 'package:myecl/tools/constants.dart'; @@ -22,8 +23,6 @@ import 'package:myecl/tools/token_expire_wrapper.dart'; import 'package:myecl/tools/ui/builders/async_child.dart'; import 'package:myecl/tools/ui/builders/waiting_button.dart'; import 'package:myecl/tools/ui/layouts/add_edit_button_layout.dart'; -import 'package:myecl/tools/ui/layouts/horizontal_list_view.dart'; -import 'package:myecl/tools/ui/layouts/item_chip.dart'; import 'package:myecl/tools/ui/layouts/refresher.dart'; import 'package:qlevar_router/qlevar_router.dart'; @@ -41,8 +40,7 @@ class AssociationEditorPage extends HookConsumerWidget { final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); final associationListNotifier = ref.watch(associationListProvider.notifier); - final associationKinds = ref.watch(associationKindsProvider); - final kind = useState(association.kind); + final kind = ref.watch(associationKindProvider); final name = useTextEditingController(text: association.name); final description = useTextEditingController(text: association.description); final rolesTagsNotifier = ref.watch(rolesTagsProvider.notifier); @@ -78,33 +76,7 @@ class AssociationEditorPage extends HookConsumerWidget { Form( key: key, child: Column(children: [ - associationKinds.when( - data: (association) { - return HorizontalListView.builder( - height: 40, - items: association.kinds, - itemBuilder: (context, item, index) { - final selected = kind.value == item; - return ItemChip( - onTap: () { - kind.value = item; - }, - selected: selected, - child: Text(item, - style: TextStyle( - color: selected ? Colors.white : Colors.black, - fontWeight: FontWeight.bold, - )), - ); - }); - }, - error: (error, stack) { - return const Text(PhonebookTextConstants.errorKindsLoading); - }, - loading: () { - return const CircularProgressIndicator(); - }, - ), + const KindsBar(), Padding( padding: const EdgeInsets.symmetric(horizontal: 30), child: Column( @@ -194,7 +166,7 @@ class AssociationEditorPage extends HookConsumerWidget { if (!key.currentState!.validate()) { return; } - if (kind.value == '') { + if (kind == '') { displayToastWithContext(TypeMsg.error, PhonebookTextConstants.emptyKindError); return; @@ -204,7 +176,7 @@ class AssociationEditorPage extends HookConsumerWidget { .updateAssociation(association.copyWith( name: name.text, description: description.text, - kind: kind.value)); + kind: kind)); if (value) { displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.updatedAssociation); diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index a04d376fb..4ebb06968 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -1,21 +1,17 @@ import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_admin_provider.dart'; -import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/tools/function.dart'; +import 'package:myecl/phonebook/ui/kinds_bar.dart'; import 'package:myecl/phonebook/ui/pages/main_page/association_card.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/phonebook/ui/pages/main_page/research_bar.dart'; import 'package:myecl/tools/ui/builders/async_child.dart'; -import 'package:myecl/tools/ui/layouts/horizontal_list_view.dart'; -import 'package:myecl/tools/ui/layouts/item_chip.dart'; import 'package:myecl/tools/ui/layouts/refresher.dart'; import 'package:qlevar_router/qlevar_router.dart'; @@ -33,9 +29,6 @@ class PhonebookMainPage extends HookConsumerWidget { final associationKindsNotifier = ref.watch(associationKindsProvider.notifier); final associationKinds = ref.watch(associationKindsProvider); - final kind = useState(''); - final kindNotifier = ref.watch(associationKindProvider.notifier); - final nameFilter = ref.watch(filterProvider); return PhonebookTemplate( child: Refresher( @@ -71,42 +64,7 @@ class PhonebookMainPage extends HookConsumerWidget { associations = sortedAssociation(associations, kinds); return Column( children: [ - HorizontalListView.builder( - height: 40, - items: kinds.kinds, - firstChild: ItemChip( - selected: kind.value == "", - onTap: () { - kind.value = ""; - kindNotifier.setKind(""); - associationListNotifier.filterAssociationList( - nameFilter, kind.value); - }, - child: Text(PhonebookTextConstants.all, - style: TextStyle( - color: kind.value == "" - ? Colors.white - : Colors.black, - fontWeight: FontWeight.bold, - ))), - itemBuilder: (context, item, index) { - final selected = kind.value == item; - return ItemChip( - onTap: () { - kind.value = item; - kindNotifier.setKind(item); - associationListNotifier.filterAssociationList( - nameFilter, kind.value); - }, - selected: selected, - child: Text(item, - style: TextStyle( - color: - selected ? Colors.white : Colors.black, - fontWeight: FontWeight.bold, - )), - ); - }), + const KindsBar(), const SizedBox(height: 30), if (associations.isEmpty) const Center( From 6a10072a5e5255a666178dc8f7b6242061a40545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 11:49:44 +0100 Subject: [PATCH 081/123] fix: scrolling in asso edit page --- lib/phonebook/router.dart | 4 ++-- .../association_editor_page/association_editor_page.dart | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/phonebook/router.dart b/lib/phonebook/router.dart index 424e37ee7..fe3cc411b 100644 --- a/lib/phonebook/router.dart +++ b/lib/phonebook/router.dart @@ -40,7 +40,7 @@ class PhonebookRouter { ], children: [ QRoute( path: editAssociation, - builder: () => const AssociationEditorPage(), + builder: () => AssociationEditorPage(), children: [ QRoute( path: addEditMember, @@ -57,7 +57,7 @@ class PhonebookRouter { children: [ QRoute( path: editAssociation, - builder: () => const AssociationEditorPage(), + builder: () => AssociationEditorPage(), middleware: [ AdminMiddleware(ref, isAssociationPresidentProvider) ], diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 9e8fb552d..466ee1cd1 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -27,7 +27,8 @@ import 'package:myecl/tools/ui/layouts/refresher.dart'; import 'package:qlevar_router/qlevar_router.dart'; class AssociationEditorPage extends HookConsumerWidget { - const AssociationEditorPage({super.key}); + final scrollKey = GlobalKey(); + AssociationEditorPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -76,7 +77,7 @@ class AssociationEditorPage extends HookConsumerWidget { Form( key: key, child: Column(children: [ - const KindsBar(), + KindsBar(key: scrollKey), Padding( padding: const EdgeInsets.symmetric(horizontal: 30), child: Column( From f7a38761c37a8529dd25554b2a9ce38b02d9a056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 11:52:46 +0100 Subject: [PATCH 082/123] fix: ui --- .../pages/association_editor_page/association_editor_page.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 466ee1cd1..af659ef5d 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -264,6 +264,9 @@ class AssociationEditorPage extends HookConsumerWidget { .toList(), ), ), + const SizedBox( + height: 10, + ), Padding( padding: const EdgeInsets.symmetric(horizontal: 30), child: WaitingButton( From b62700096ca435fd3e7633417e3a07c14c7c6d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 11:56:32 +0100 Subject: [PATCH 083/123] refacto: add components folder --- lib/phonebook/ui/{ => components}/copiabled_text.dart | 0 lib/phonebook/ui/{ => components}/kinds_bar.dart | 0 lib/phonebook/ui/{ => components}/radio_chip.dart | 0 lib/phonebook/ui/{ => components}/text_input_dialog.dart | 0 lib/phonebook/ui/pages/admin_page/admin_page.dart | 2 +- .../association_creation_page/association_creation_page.dart | 2 +- .../pages/association_editor_page/association_editor_page.dart | 2 +- lib/phonebook/ui/pages/association_page/member_card.dart | 2 +- lib/phonebook/ui/pages/main_page/main_page.dart | 2 +- 9 files changed, 5 insertions(+), 5 deletions(-) rename lib/phonebook/ui/{ => components}/copiabled_text.dart (100%) rename lib/phonebook/ui/{ => components}/kinds_bar.dart (100%) rename lib/phonebook/ui/{ => components}/radio_chip.dart (100%) rename lib/phonebook/ui/{ => components}/text_input_dialog.dart (100%) diff --git a/lib/phonebook/ui/copiabled_text.dart b/lib/phonebook/ui/components/copiabled_text.dart similarity index 100% rename from lib/phonebook/ui/copiabled_text.dart rename to lib/phonebook/ui/components/copiabled_text.dart diff --git a/lib/phonebook/ui/kinds_bar.dart b/lib/phonebook/ui/components/kinds_bar.dart similarity index 100% rename from lib/phonebook/ui/kinds_bar.dart rename to lib/phonebook/ui/components/kinds_bar.dart diff --git a/lib/phonebook/ui/radio_chip.dart b/lib/phonebook/ui/components/radio_chip.dart similarity index 100% rename from lib/phonebook/ui/radio_chip.dart rename to lib/phonebook/ui/components/radio_chip.dart diff --git a/lib/phonebook/ui/text_input_dialog.dart b/lib/phonebook/ui/components/text_input_dialog.dart similarity index 100% rename from lib/phonebook/ui/text_input_dialog.dart rename to lib/phonebook/ui/components/text_input_dialog.dart diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 04d01f76c..a185625c7 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -8,7 +8,7 @@ import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/tools/function.dart'; -import 'package:myecl/phonebook/ui/kinds_bar.dart'; +import 'package:myecl/phonebook/ui/components/kinds_bar.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/association_research_bar.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/editable_association_card.dart'; diff --git a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart index 0ad67d4dc..c106dbc96 100644 --- a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart +++ b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart @@ -7,7 +7,7 @@ import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/ui/kinds_bar.dart'; +import 'package:myecl/phonebook/ui/components/kinds_bar.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index af659ef5d..cbf74c4dc 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -14,7 +14,7 @@ import 'package:myecl/phonebook/providers/membership_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/ui/kinds_bar.dart'; +import 'package:myecl/phonebook/ui/components/kinds_bar.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/phonebook/ui/pages/association_editor_page/member_editable_card.dart'; import 'package:myecl/tools/constants.dart'; diff --git a/lib/phonebook/ui/pages/association_page/member_card.dart b/lib/phonebook/ui/pages/association_page/member_card.dart index a46bfb282..2f1cd6025 100644 --- a/lib/phonebook/ui/pages/association_page/member_card.dart +++ b/lib/phonebook/ui/pages/association_page/member_card.dart @@ -7,7 +7,7 @@ import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/ui/copiabled_text.dart'; +import 'package:myecl/phonebook/ui/components/copiabled_text.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/tools/ui/layouts/card_layout.dart'; import 'package:qlevar_router/qlevar_router.dart'; diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 4ebb06968..5c817bd0b 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -7,7 +7,7 @@ import 'package:myecl/phonebook/providers/phonebook_admin_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/tools/function.dart'; -import 'package:myecl/phonebook/ui/kinds_bar.dart'; +import 'package:myecl/phonebook/ui/components/kinds_bar.dart'; import 'package:myecl/phonebook/ui/pages/main_page/association_card.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/phonebook/ui/pages/main_page/research_bar.dart'; From 8edc63be8053aa82801db38f8b6c63606fc3305b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 11:58:22 +0100 Subject: [PATCH 084/123] fix: scrolling in add asso --- lib/phonebook/router.dart | 2 +- .../association_creation_page/association_creation_page.dart | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/phonebook/router.dart b/lib/phonebook/router.dart index fe3cc411b..f918f16a4 100644 --- a/lib/phonebook/router.dart +++ b/lib/phonebook/router.dart @@ -49,7 +49,7 @@ class PhonebookRouter { ), QRoute( path: createAssociaiton, - builder: () => const AssociationCreationPage()), + builder: () => AssociationCreationPage()), ]), QRoute( path: associationDetail, diff --git a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart index c106dbc96..6c51c66cf 100644 --- a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart +++ b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart @@ -18,7 +18,8 @@ import 'package:myecl/tools/ui/widgets/text_entry.dart'; import 'package:qlevar_router/qlevar_router.dart'; class AssociationCreationPage extends HookConsumerWidget { - const AssociationCreationPage({super.key}); + final scrollKey = GlobalKey(); + AssociationCreationPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -59,7 +60,7 @@ class AssociationCreationPage extends HookConsumerWidget { const SizedBox( height: 30, ), - const KindsBar(), + KindsBar(key: scrollKey), Padding( padding: const EdgeInsets.symmetric(horizontal: 30.0), child: Column( From 0705e3dc34f3c040e5f22a4c456a0f331dfea601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 12:10:17 +0100 Subject: [PATCH 085/123] fix: add asso with new kindsbar --- .../association_creation_page.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart index 6c51c66cf..88cddb4ef 100644 --- a/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart +++ b/lib/phonebook/ui/pages/association_creation_page/association_creation_page.dart @@ -3,6 +3,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/admin/tools/constants.dart'; import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/router.dart'; @@ -29,8 +30,7 @@ class AssociationCreationPage extends HookConsumerWidget { final associationListNotifier = ref.watch(associationListProvider.notifier); final associations = ref.watch(associationListProvider); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); - final kind = useState(''); - + final kind = ref.watch(associationKindProvider); void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); } @@ -94,7 +94,7 @@ class AssociationCreationPage extends HookConsumerWidget { PhonebookTextConstants.emptyFieldError); return; } - if (kind.value == '') { + if (kind == '') { displayToastWithContext(TypeMsg.error, PhonebookTextConstants.emptyKindError); return; @@ -105,7 +105,7 @@ class AssociationCreationPage extends HookConsumerWidget { Association.empty().copyWith( name: name.text, description: description.text, - kind: kind.value, + kind: kind, mandateYear: DateTime.now().year), ); if (value) { From 1520f10cfe984afb9b578f33226229b7af34f31d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 12:20:09 +0100 Subject: [PATCH 086/123] fix: association provider --- .../providers/association_list_provider.dart | 22 ++++--------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index 18d007180..e7ec877d1 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -14,43 +14,29 @@ class AssociationListNotifier extends ListNotifier { } Future>> loadAssociations() async { - associationList = await loadList(associationRepository.getAssociationList); - return associationList; + return await loadList(associationRepository.getAssociationList); } Future createAssociation(Association association) async { - final result = - await add(associationRepository.createAssociation, association); - if (result) { - associationList = state; - } - return result; + return await add(associationRepository.createAssociation, association); } Future updateAssociation(Association association) async { - final result = await update( + return await update( associationRepository.updateAssociation, (associations, association) => associations ..[associations.indexWhere((g) => g.id == association.id)] = association, association); - if (result) { - associationList = state; - } - return result; } Future deleteAssociation(Association association) async { - final result = await delete( + return await delete( associationRepository.deleteAssociation, (associations, association) => associations..removeWhere((i) => i.id == association.id), association.id, association); - if (result) { - associationList = state; - } - return result; } void filterAssociationList(String nameFilter, String kindFilter) async { From bc2c48d044cc4aa4005c5c2ee9b4d5940f43056c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 12:21:00 +0100 Subject: [PATCH 087/123] fix: remove useless load --- .../ui/pages/admin_page/admin_page.dart | 151 +++++++++--------- 1 file changed, 76 insertions(+), 75 deletions(-) diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index a185625c7..c0a1c7369 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -49,82 +49,83 @@ class AdminPage extends HookConsumerWidget { AsyncChild( value: associationKinds, builder: (context, kinds) => AsyncChild( - value: associationList, - builder: (context, associations) { - associations = sortedAssociation(associations, kinds); - return Column( - children: [ - const KindsBar(), - GestureDetector( - onTap: () { - QR.to(PhonebookRouter.root + - PhonebookRouter.admin + - PhonebookRouter.createAssociaiton); - }, - child: CardLayout( - margin: const EdgeInsets.only( - bottom: 10, top: 20, left: 40, right: 40), - width: double.infinity, - height: 100, - color: Colors.white, - child: Center( - child: HeroIcon( - HeroIcons.plus, - size: 40, - color: Colors.grey.shade500, - ))), - ), - const SizedBox(height: 30), - if (associations.isEmpty) - const Center( - child: - Text(PhonebookTextConstants.noAssociationFound), - ) - else - ...associations.map( - (association) => EditableAssociationCard( - association: association, - onEdit: () { - associationNotifier.setAssociation(association); - QR.to(PhonebookRouter.root + - PhonebookRouter.admin + - PhonebookRouter.editAssociation); - }, - onDelete: () async { - await showDialog( - context: context, - builder: (context) { - return CustomDialogBox( - title: PhonebookTextConstants.deleting, - descriptions: PhonebookTextConstants - .deleteAssociation, - onYes: () async { - final result = - await associationListNotifier - .deleteAssociation(association); - if (result) { - displayToastWithContext( - TypeMsg.msg, - PhonebookTextConstants - .deletedAssociation); - } else { - displayToastWithContext( - TypeMsg.error, - PhonebookTextConstants - .deletingError); - } - associationListNotifier - .loadAssociations(); // TODO - }, - ); - }, - ); - }, - ), + value: associationList, + builder: (context, associations) { + associations = sortedAssociation(associations, kinds); + return Column( + children: [ + const KindsBar(), + GestureDetector( + onTap: () { + QR.to(PhonebookRouter.root + + PhonebookRouter.admin + + PhonebookRouter.createAssociaiton); + }, + child: CardLayout( + margin: const EdgeInsets.only( + bottom: 10, top: 20, left: 40, right: 40), + width: double.infinity, + height: 100, + color: Colors.white, + child: Center( + child: HeroIcon( + HeroIcons.plus, + size: 40, + color: Colors.grey.shade500, + ))), + ), + const SizedBox(height: 30), + if (associations.isEmpty) + const Center( + child: + Text(PhonebookTextConstants.noAssociationFound), + ) + else + ...associations.map( + (association) => EditableAssociationCard( + association: association, + onEdit: () { + associationNotifier.setAssociation(association); + QR.to(PhonebookRouter.root + + PhonebookRouter.admin + + PhonebookRouter.editAssociation); + }, + onDelete: () async { + await showDialog( + context: context, + builder: (context) { + return CustomDialogBox( + title: PhonebookTextConstants.deleting, + descriptions: PhonebookTextConstants + .deleteAssociation, + onYes: () async { + final result = + await associationListNotifier + .deleteAssociation(association); + if (result) { + displayToastWithContext( + TypeMsg.msg, + PhonebookTextConstants + .deletedAssociation); + } else { + displayToastWithContext( + TypeMsg.error, + PhonebookTextConstants + .deletingError); + } + associationListNotifier + .loadAssociations(); // TODO + }, + ); + }, + ); + }, ), - ], - ); - }), + ), + ], + ); + }, + ), ), ], ), From a97373779190912c4e5c15c1af6ec220ccc9dec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 12:21:26 +0100 Subject: [PATCH 088/123] fix: remove useless load --- lib/phonebook/ui/pages/admin_page/admin_page.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index c0a1c7369..c24598d8e 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -113,8 +113,6 @@ class AdminPage extends HookConsumerWidget { PhonebookTextConstants .deletingError); } - associationListNotifier - .loadAssociations(); // TODO }, ); }, From 05d3e897055cd4bcfec16dc74cb0fbde13f06ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 12:43:53 +0100 Subject: [PATCH 089/123] fix: filtering is managed by it's own provider --- .../association_filtered_list_provider.dart | 30 +++++++++++++++++++ .../providers/association_list_provider.dart | 29 ------------------ lib/phonebook/ui/components/kinds_bar.dart | 6 ---- .../ui/pages/admin_page/admin_page.dart | 4 ++- .../admin_page/association_research_bar.dart | 5 ---- .../ui/pages/main_page/main_page.dart | 7 +++-- .../ui/pages/main_page/research_bar.dart | 5 ---- 7 files changed, 37 insertions(+), 49 deletions(-) create mode 100644 lib/phonebook/providers/association_filtered_list_provider.dart diff --git a/lib/phonebook/providers/association_filtered_list_provider.dart b/lib/phonebook/providers/association_filtered_list_provider.dart new file mode 100644 index 000000000..0c7458ba2 --- /dev/null +++ b/lib/phonebook/providers/association_filtered_list_provider.dart @@ -0,0 +1,30 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/providers/association_kind_provider.dart'; +import 'package:myecl/phonebook/providers/association_list_provider.dart'; +import 'package:myecl/phonebook/providers/research_filter_provider.dart'; + +final associationFilteredListProvider = Provider>((ref) { + final associationsProvider = ref.watch(associationListProvider); + final kindFilter = ref.watch(associationKindProvider); + final searchFilter = ref.watch(filterProvider); + return associationsProvider.maybeWhen( + data: (associations) { + if (kindFilter == "") { + return associations + .where((element) => element.name + .toLowerCase() + .contains(searchFilter.toLowerCase())) + .toList(); + } else { + return associations + .where((element) => + element.name + .toLowerCase() + .contains(searchFilter.toLowerCase()) && + element.kind == kindFilter) + .toList(); + } + }, + orElse: () => []); +}); diff --git a/lib/phonebook/providers/association_list_provider.dart b/lib/phonebook/providers/association_list_provider.dart index e7ec877d1..449bc1698 100644 --- a/lib/phonebook/providers/association_list_provider.dart +++ b/lib/phonebook/providers/association_list_provider.dart @@ -38,35 +38,6 @@ class AssociationListNotifier extends ListNotifier { association.id, association); } - - void filterAssociationList(String nameFilter, String kindFilter) async { - if (kindFilter == "") { - associationList.maybeWhen( - data: (data) => state = AsyncValue.data(data - .where((element) => - element.name.toLowerCase().contains(nameFilter.toLowerCase())) - .toList()), - orElse: () => state = const AsyncLoading(), - ); - } else { - associationList.maybeWhen( - data: (data) => state = AsyncValue.data(data - .where((element) => - (element.name.toLowerCase().contains(nameFilter.toLowerCase()) & - (element.kind == kindFilter))) - .toList()), - orElse: () => state = const AsyncLoading(), - ); - } - } - - void setAssociationList(List associationList) { - state.whenData( - (d) { - state = AsyncValue.data(associationList); - }, - ); - } } final associationListProvider = StateNotifierProvider EditableAssociationCard( association: association, onEdit: () { diff --git a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart index 762202578..8e2e3a893 100644 --- a/lib/phonebook/ui/pages/admin_page/association_research_bar.dart +++ b/lib/phonebook/ui/pages/admin_page/association_research_bar.dart @@ -1,8 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/providers/association_kind_provider.dart'; -import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/tools/constants.dart'; @@ -15,12 +13,9 @@ class AssociationResearchBar extends HookConsumerWidget { final focusNode = useFocusNode(); final editingController = useTextEditingController(); final filterNotifier = ref.watch(filterProvider.notifier); - final associationsNotifier = ref.watch(associationListProvider.notifier); - final associationKind = ref.watch(associationKindProvider); return TextField( onChanged: (value) async { - associationsNotifier.filterAssociationList(value, associationKind); filterNotifier.setFilter(value); }, focusNode: focusNode, diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 5c817bd0b..d876b7798 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/association_filtered_list_provider.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; @@ -13,10 +14,9 @@ import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/phonebook/ui/pages/main_page/research_bar.dart'; import 'package:myecl/tools/ui/builders/async_child.dart'; import 'package:myecl/tools/ui/layouts/refresher.dart'; +import 'package:myecl/tools/ui/widgets/admin_button.dart'; import 'package:qlevar_router/qlevar_router.dart'; -import '../../../../tools/ui/widgets/admin_button.dart'; - class PhonebookMainPage extends HookConsumerWidget { const PhonebookMainPage({super.key}); @@ -26,6 +26,7 @@ class PhonebookMainPage extends HookConsumerWidget { final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationListNotifier = ref.watch(associationListProvider.notifier); final associationList = ref.watch(associationListProvider); + final associationFilteredList = ref.watch(associationFilteredListProvider); final associationKindsNotifier = ref.watch(associationKindsProvider.notifier); final associationKinds = ref.watch(associationKindsProvider); @@ -72,7 +73,7 @@ class PhonebookMainPage extends HookConsumerWidget { Text(PhonebookTextConstants.noAssociationFound), ) else - ...associations.map( + ...associationFilteredList.map( (association) => AssociationCard( association: association, onClicked: () { diff --git a/lib/phonebook/ui/pages/main_page/research_bar.dart b/lib/phonebook/ui/pages/main_page/research_bar.dart index 1d5d0113e..0c5cc8ca8 100644 --- a/lib/phonebook/ui/pages/main_page/research_bar.dart +++ b/lib/phonebook/ui/pages/main_page/research_bar.dart @@ -1,8 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/providers/association_kind_provider.dart'; -import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/tools/constants.dart'; @@ -15,13 +13,10 @@ class ResearchBar extends HookConsumerWidget { final focusNode = useFocusNode(); final editingController = useTextEditingController(); final filterNotifier = ref.watch(filterProvider.notifier); - final associationsNotifier = ref.watch(associationListProvider.notifier); - final associationKind = ref.watch(associationKindProvider); return Expanded( child: TextField( onChanged: (value) { - associationsNotifier.filterAssociationList(value, associationKind); filterNotifier.setFilter(value); }, focusNode: focusNode, From a4ec89893da621eca215d0dc9891941b96699d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 12:45:29 +0100 Subject: [PATCH 090/123] fix: code clarity --- .../providers/association_filtered_list_provider.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/phonebook/providers/association_filtered_list_provider.dart b/lib/phonebook/providers/association_filtered_list_provider.dart index 0c7458ba2..12184f6d3 100644 --- a/lib/phonebook/providers/association_filtered_list_provider.dart +++ b/lib/phonebook/providers/association_filtered_list_provider.dart @@ -12,17 +12,17 @@ final associationFilteredListProvider = Provider>((ref) { data: (associations) { if (kindFilter == "") { return associations - .where((element) => element.name + .where((association) => association.name .toLowerCase() .contains(searchFilter.toLowerCase())) .toList(); } else { return associations - .where((element) => - element.name + .where((association) => + association.name .toLowerCase() .contains(searchFilter.toLowerCase()) && - element.kind == kindFilter) + association.kind == kindFilter) .toList(); } }, From 23c47390ac795a9cd995250fc09cee80f8f35180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 13:07:30 +0100 Subject: [PATCH 091/123] move sorting by kinds in the filtered provider --- .../association_filtered_list_provider.dart | 28 ++-- lib/phonebook/tools/function.dart | 2 +- .../ui/pages/admin_page/admin_page.dart | 147 ++++++++---------- .../ui/pages/main_page/main_page.dart | 55 +++---- 4 files changed, 108 insertions(+), 124 deletions(-) diff --git a/lib/phonebook/providers/association_filtered_list_provider.dart b/lib/phonebook/providers/association_filtered_list_provider.dart index 12184f6d3..6dae870bf 100644 --- a/lib/phonebook/providers/association_filtered_list_provider.dart +++ b/lib/phonebook/providers/association_filtered_list_provider.dart @@ -1,30 +1,32 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/providers/association_kind_provider.dart'; +import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; +import 'package:myecl/phonebook/tools/function.dart'; final associationFilteredListProvider = Provider>((ref) { final associationsProvider = ref.watch(associationListProvider); + final associationKinds = ref.watch(associationKindsProvider); final kindFilter = ref.watch(associationKindProvider); final searchFilter = ref.watch(filterProvider); return associationsProvider.maybeWhen( data: (associations) { - if (kindFilter == "") { - return associations - .where((association) => association.name - .toLowerCase() - .contains(searchFilter.toLowerCase())) - .toList(); - } else { - return associations - .where((association) => - association.name - .toLowerCase() - .contains(searchFilter.toLowerCase()) && - association.kind == kindFilter) + List filteredAssociations = associations + .where((association) => association.name + .toLowerCase() + .contains(searchFilter.toLowerCase())) + .toList(); + if (kindFilter != "") { + filteredAssociations = filteredAssociations + .where((association) => association.kind == kindFilter) .toList(); } + return associationKinds.maybeWhen( + data: (kinds) => + sortedAssociationByKind(filteredAssociations, kinds), + orElse: () => filteredAssociations); }, orElse: () => []); }); diff --git a/lib/phonebook/tools/function.dart b/lib/phonebook/tools/function.dart index fe918ecda..860f790e2 100644 --- a/lib/phonebook/tools/function.dart +++ b/lib/phonebook/tools/function.dart @@ -21,7 +21,7 @@ List sortMembers(List members, .compareTo(getPosition(b, associationId, rolesTags))); } -List sortedAssociation( +List sortedAssociationByKind( List associations, AssociationKinds kinds) { List sorted = []; List> sortedByKind = diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 748b24c32..6487f035a 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -2,13 +2,11 @@ import 'package:flutter/material.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/providers/association_filtered_list_provider.dart'; -import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/tools/function.dart'; import 'package:myecl/phonebook/ui/components/kinds_bar.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/association_research_bar.dart'; @@ -30,7 +28,6 @@ class AdminPage extends HookConsumerWidget { final associationList = ref.watch(associationListProvider); final associationFilteredList = ref.watch(associationFilteredListProvider); final roleNotifier = ref.watch(rolesTagsProvider.notifier); - final associationKinds = ref.watch(associationKindsProvider); void displayToastWithContext(TypeMsg type, String msg) { displayToast(context, type, msg); } @@ -49,83 +46,75 @@ class AdminPage extends HookConsumerWidget { ), const SizedBox(height: 10), AsyncChild( - value: associationKinds, - builder: (context, kinds) => AsyncChild( - value: associationList, - builder: (context, associations) { - associations = sortedAssociation(associations, kinds); - return Column( - children: [ - const KindsBar(), - GestureDetector( - onTap: () { - QR.to(PhonebookRouter.root + - PhonebookRouter.admin + - PhonebookRouter.createAssociaiton); - }, - child: CardLayout( - margin: const EdgeInsets.only( - bottom: 10, top: 20, left: 40, right: 40), - width: double.infinity, - height: 100, - color: Colors.white, - child: Center( - child: HeroIcon( - HeroIcons.plus, - size: 40, - color: Colors.grey.shade500, - ))), - ), - const SizedBox(height: 30), - if (associations.isEmpty) - const Center( - child: - Text(PhonebookTextConstants.noAssociationFound), - ) - else - ...associationFilteredList.map( - (association) => EditableAssociationCard( - association: association, - onEdit: () { - associationNotifier.setAssociation(association); - QR.to(PhonebookRouter.root + - PhonebookRouter.admin + - PhonebookRouter.editAssociation); - }, - onDelete: () async { - await showDialog( - context: context, - builder: (context) { - return CustomDialogBox( - title: PhonebookTextConstants.deleting, - descriptions: PhonebookTextConstants - .deleteAssociation, - onYes: () async { - final result = - await associationListNotifier - .deleteAssociation(association); - if (result) { - displayToastWithContext( - TypeMsg.msg, - PhonebookTextConstants - .deletedAssociation); - } else { - displayToastWithContext( - TypeMsg.error, - PhonebookTextConstants - .deletingError); - } - }, - ); - }, - ); - }, - ), + value: associationList, + builder: (context, associations) { + return Column( + children: [ + const KindsBar(), + GestureDetector( + onTap: () { + QR.to(PhonebookRouter.root + + PhonebookRouter.admin + + PhonebookRouter.createAssociaiton); + }, + child: CardLayout( + margin: const EdgeInsets.only( + bottom: 10, top: 20, left: 40, right: 40), + width: double.infinity, + height: 100, + color: Colors.white, + child: Center( + child: HeroIcon( + HeroIcons.plus, + size: 40, + color: Colors.grey.shade500, + ))), + ), + const SizedBox(height: 30), + if (associations.isEmpty) + const Center( + child: Text(PhonebookTextConstants.noAssociationFound), + ) + else + ...associationFilteredList.map( + (association) => EditableAssociationCard( + association: association, + onEdit: () { + associationNotifier.setAssociation(association); + QR.to(PhonebookRouter.root + + PhonebookRouter.admin + + PhonebookRouter.editAssociation); + }, + onDelete: () async { + await showDialog( + context: context, + builder: (context) { + return CustomDialogBox( + title: PhonebookTextConstants.deleting, + descriptions: + PhonebookTextConstants.deleteAssociation, + onYes: () async { + final result = await associationListNotifier + .deleteAssociation(association); + if (result) { + displayToastWithContext( + TypeMsg.msg, + PhonebookTextConstants + .deletedAssociation); + } else { + displayToastWithContext(TypeMsg.error, + PhonebookTextConstants.deletingError); + } + }, + ); + }, + ); + }, ), - ], - ); - }, - ), + ), + ], + ); + }, ), ], ), diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index d876b7798..152db60a3 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -7,7 +7,6 @@ import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/phonebook_admin_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/tools/function.dart'; import 'package:myecl/phonebook/ui/components/kinds_bar.dart'; import 'package:myecl/phonebook/ui/pages/main_page/association_card.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; @@ -29,7 +28,6 @@ class PhonebookMainPage extends HookConsumerWidget { final associationFilteredList = ref.watch(associationFilteredListProvider); final associationKindsNotifier = ref.watch(associationKindsProvider.notifier); - final associationKinds = ref.watch(associationKindsProvider); return PhonebookTemplate( child: Refresher( @@ -58,35 +56,30 @@ class PhonebookMainPage extends HookConsumerWidget { ), const SizedBox(height: 10), AsyncChild( - value: associationKinds, - builder: (context, kinds) => AsyncChild( - value: associationList, - builder: (context, associations) { - associations = sortedAssociation(associations, kinds); - return Column( - children: [ - const KindsBar(), - const SizedBox(height: 30), - if (associations.isEmpty) - const Center( - child: - Text(PhonebookTextConstants.noAssociationFound), - ) - else - ...associationFilteredList.map( - (association) => AssociationCard( - association: association, - onClicked: () { - associationNotifier.setAssociation(association); - QR.to(PhonebookRouter.root + - PhonebookRouter.associationDetail); - }, - ), - ) - ], - ); - }, - ), + value: associationList, + builder: (context, associations) { + return Column( + children: [ + const KindsBar(), + const SizedBox(height: 30), + if (associations.isEmpty) + const Center( + child: Text(PhonebookTextConstants.noAssociationFound), + ) + else + ...associationFilteredList.map( + (association) => AssociationCard( + association: association, + onClicked: () { + associationNotifier.setAssociation(association); + QR.to(PhonebookRouter.root + + PhonebookRouter.associationDetail); + }, + ), + ) + ], + ); + }, ), ], ), From 379782f661b06b095869d67821ac53b049e8aca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 13:39:00 +0100 Subject: [PATCH 092/123] fix: routing --- lib/phonebook/ui/pages/admin_page/admin_page.dart | 2 +- lib/phonebook/ui/phonebook.dart | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 6487f035a..44f2bf1f4 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -39,7 +39,7 @@ class AdminPage extends HookConsumerWidget { await roleNotifier.loadRolesTags(); }, child: Column( - children: [ + children: [ const Padding( padding: EdgeInsets.all(30), child: AssociationResearchBar(), diff --git a/lib/phonebook/ui/phonebook.dart b/lib/phonebook/ui/phonebook.dart index 2174df15b..fc927b8fe 100644 --- a/lib/phonebook/ui/phonebook.dart +++ b/lib/phonebook/ui/phonebook.dart @@ -3,6 +3,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/tools/ui/widgets/top_bar.dart'; +import 'package:qlevar_router/qlevar_router.dart'; class PhonebookTemplate extends HookConsumerWidget { final Widget child; @@ -13,9 +14,19 @@ class PhonebookTemplate extends HookConsumerWidget { return Scaffold( body: Column( children: [ - const TopBar( + TopBar( title: PhonebookTextConstants.phonebook, root: PhonebookRouter.root, + onBack: () { + if (QR.currentPath == + PhonebookRouter.root + + PhonebookRouter.admin + + PhonebookRouter.editAssociation) { + QR.to(PhonebookRouter.root + + PhonebookRouter + .admin); // Used on back after adding an association + } + }, ), Expanded(child: child), ], From 91160d91f1a4d866b9f6c25a51a83ba9561f7384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 13:58:04 +0100 Subject: [PATCH 093/123] fix: improve admin ui --- .../ui/pages/admin_page/admin_page.dart | 72 ++++++++++--------- .../admin_page/editable_association_card.dart | 35 +++++---- 2 files changed, 62 insertions(+), 45 deletions(-) diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 44f2bf1f4..7133682bf 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -77,39 +77,45 @@ class AdminPage extends HookConsumerWidget { ) else ...associationFilteredList.map( - (association) => EditableAssociationCard( - association: association, - onEdit: () { - associationNotifier.setAssociation(association); - QR.to(PhonebookRouter.root + - PhonebookRouter.admin + - PhonebookRouter.editAssociation); - }, - onDelete: () async { - await showDialog( - context: context, - builder: (context) { - return CustomDialogBox( - title: PhonebookTextConstants.deleting, - descriptions: - PhonebookTextConstants.deleteAssociation, - onYes: () async { - final result = await associationListNotifier - .deleteAssociation(association); - if (result) { - displayToastWithContext( - TypeMsg.msg, - PhonebookTextConstants - .deletedAssociation); - } else { - displayToastWithContext(TypeMsg.error, - PhonebookTextConstants.deletingError); - } - }, - ); - }, - ); - }, + (association) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: EditableAssociationCard( + association: association, + onEdit: () { + associationNotifier.setAssociation(association); + QR.to(PhonebookRouter.root + + PhonebookRouter.admin + + PhonebookRouter.editAssociation); + }, + onDelete: () async { + await showDialog( + context: context, + builder: (context) { + return CustomDialogBox( + title: PhonebookTextConstants.deleting, + descriptions: PhonebookTextConstants + .deleteAssociation, + onYes: () async { + final result = + await associationListNotifier + .deleteAssociation(association); + if (result) { + displayToastWithContext( + TypeMsg.msg, + PhonebookTextConstants + .deletedAssociation); + } else { + displayToastWithContext( + TypeMsg.error, + PhonebookTextConstants + .deletingError); + } + }, + ); + }, + ); + }, + ), ), ), ], diff --git a/lib/phonebook/ui/pages/admin_page/editable_association_card.dart b/lib/phonebook/ui/pages/admin_page/editable_association_card.dart index c86da047a..03e304205 100644 --- a/lib/phonebook/ui/pages/admin_page/editable_association_card.dart +++ b/lib/phonebook/ui/pages/admin_page/editable_association_card.dart @@ -1,4 +1,6 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/delete_button.dart'; @@ -29,23 +31,32 @@ class EditableAssociationCard extends HookConsumerWidget { spreadRadius: 2) ]), child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ const SizedBox(width: 10), - Text( - association.name, - style: const TextStyle( - color: Colors.black, fontSize: 16, fontWeight: FontWeight.bold), - ), - const Spacer(), - Text(association.kind, + Expanded( + child: Text( + association.name, style: const TextStyle( color: Colors.black, fontSize: 16, - fontWeight: FontWeight.bold)), - const Spacer(), - EditionButton(onEdition: onEdit), - const SizedBox(width: 5), - DeleteButton(onDelete: onDelete), + fontWeight: FontWeight.bold), + ), + ), + Expanded( + child: Text(association.kind, + style: const TextStyle( + color: Colors.black, + fontSize: 16, + fontWeight: FontWeight.bold)), + ), + Row( + children: [ + EditionButton(onEdition: onEdit), + const SizedBox(width: 5), + DeleteButton(onDelete: onDelete), + ], + ), ], ), ); From 9ebba5626d4bc3d53fb939b37434275845e4fd63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 14:22:05 +0100 Subject: [PATCH 094/123] fix: improve main page ui --- .../ui/pages/main_page/association_card.dart | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/phonebook/ui/pages/main_page/association_card.dart b/lib/phonebook/ui/pages/main_page/association_card.dart index 657c82487..70dd9bdc0 100644 --- a/lib/phonebook/ui/pages/main_page/association_card.dart +++ b/lib/phonebook/ui/pages/main_page/association_card.dart @@ -24,14 +24,15 @@ class AssociationCard extends HookConsumerWidget { child: Row( children: [ const SizedBox(width: 10), - Text( - association.name, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, + Expanded( + child: Text( + association.name, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), ), ), - const Spacer(flex: 1), Text(association.kind) ], ), From 879c55bdd7e3ff40a785b268117f0a06a7dc5df3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 14:30:48 +0100 Subject: [PATCH 095/123] fix: make assoMembership non nullable --- .../member_editable_card.dart | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index 8354cbc3b..e188a8487 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -1,5 +1,4 @@ import 'package:auto_size_text/auto_size_text.dart'; -import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; @@ -38,12 +37,12 @@ class MemberEditableCard extends HookConsumerWidget { displayToast(context, type, msg); } - Membership? assoMembership = member.memberships.firstWhereOrNull( - (memberships) => - memberships.associationId == association.id && - memberships.mandateYear == association.mandateYear); - - assoMembership ??= Membership.empty(); + Membership assoMembership = member.memberships.firstWhere( + (memberships) => + memberships.associationId == association.id && + memberships.mandateYear == association.mandateYear, + orElse: () => Membership.empty(), + ); return Container( padding: const EdgeInsets.all(5), @@ -112,7 +111,7 @@ class MemberEditableCard extends HookConsumerWidget { roleTagsNotifier.resetChecked(); roleTagsNotifier.loadRoleTagsFromMember(member, association); completeMemberNotifier.setCompleteMember(member); - membershipNotifier.setMembership(assoMembership!); + membershipNotifier.setMembership(assoMembership); if (QR.currentPath.contains(PhonebookRouter.admin)) { QR.to(PhonebookRouter.root + PhonebookRouter.admin + From 50211199d387d53fbc8223776a2f79c881c468b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 14:44:17 +0100 Subject: [PATCH 096/123] fix: remove unused provider --- .../providers/association_id_provider.dart | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 lib/phonebook/providers/association_id_provider.dart diff --git a/lib/phonebook/providers/association_id_provider.dart b/lib/phonebook/providers/association_id_provider.dart deleted file mode 100644 index 1ce49655a..000000000 --- a/lib/phonebook/providers/association_id_provider.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:hooks_riverpod/hooks_riverpod.dart'; - -class AssociationIdNotifier extends StateNotifier { - AssociationIdNotifier() : super(""); - - void setId(String id) { - state = id; - } -} - -final associationIdProvider = - StateNotifierProvider( - (ref) => AssociationIdNotifier()); From 9e90fbb34ec730e97ce638b31668a899feb91991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 15:27:54 +0100 Subject: [PATCH 097/123] fix: sorting for member is done on it's own provider --- .../association_member_list_provider.dart | 11 +- ...sociation_member_sorted_list_provider.dart | 24 +++ lib/phonebook/tools/function.dart | 2 +- .../association_editor_page.dart | 9 +- .../member_editable_card.dart | 5 - .../association_page/association_page.dart | 9 +- .../membership_editor_page.dart | 183 ++++++++++-------- 7 files changed, 140 insertions(+), 103 deletions(-) create mode 100644 lib/phonebook/providers/association_member_sorted_list_provider.dart diff --git a/lib/phonebook/providers/association_member_list_provider.dart b/lib/phonebook/providers/association_member_list_provider.dart index be55dc4f9..d547e734b 100644 --- a/lib/phonebook/providers/association_member_list_provider.dart +++ b/lib/phonebook/providers/association_member_list_provider.dart @@ -3,7 +3,6 @@ import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/repositories/association_member_repository.dart'; -import 'package:myecl/phonebook/tools/function.dart'; import 'package:myecl/tools/providers/list_notifier.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; @@ -16,13 +15,9 @@ class AssociationMemberListNotifier extends ListNotifier { } Future>> loadMembers( - String associationId, String year, ref) async { - final result = await loadList(() async => associationMemberRepository + String associationId, String year) async { + return await loadList(() async => associationMemberRepository .getAssociationMemberList(associationId, year)); - result.whenData((value) { - sortMembers(value, associationId, ref); - }); - return result; } } @@ -34,7 +29,7 @@ final associationMemberListProvider = StateNotifierProvider< tokenExpireWrapperAuth(ref, () async { final association = ref.watch(associationProvider); await provider.loadMembers( - association.id, association.mandateYear.toString(), ref); + association.id, association.mandateYear.toString()); }); return provider; }); diff --git a/lib/phonebook/providers/association_member_sorted_list_provider.dart b/lib/phonebook/providers/association_member_sorted_list_provider.dart new file mode 100644 index 000000000..497bd9bfe --- /dev/null +++ b/lib/phonebook/providers/association_member_sorted_list_provider.dart @@ -0,0 +1,24 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; +import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; +import 'package:myecl/phonebook/tools/function.dart'; + +final associationMemberSortedListProvider = + Provider>((ref) { + final memberListProvider = ref.watch(associationMemberListProvider); + final association = ref.watch(associationProvider); + final roleTagsProvider = ref.watch(rolesTagsProvider); + return memberListProvider.maybeWhen( + data: (members) { + return roleTagsProvider.maybeWhen( + data: (roleTags) => sortedMembers( + members, + association.id, + roleTags.keys.toList(), + ), + orElse: () => members); + }, + orElse: () => []); +}); diff --git a/lib/phonebook/tools/function.dart b/lib/phonebook/tools/function.dart index 860f790e2..dfc5d15ca 100644 --- a/lib/phonebook/tools/function.dart +++ b/lib/phonebook/tools/function.dart @@ -14,7 +14,7 @@ int getPosition( .reduce((value, element) => min(value, element)); } -List sortMembers(List members, +List sortedMembers(List members, String associationId, List rolesTags) { return members ..sort((a, b) => getPosition(a, associationId, rolesTags) diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index cbf74c4dc..18c7f10a8 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -7,6 +7,7 @@ import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; +import 'package:myecl/phonebook/providers/association_member_sorted_list_provider.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; @@ -38,6 +39,8 @@ class AssociationEditorPage extends HookConsumerWidget { final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); final associationMemberList = ref.watch(associationMemberListProvider); + final associationMemberSortedList = + ref.watch(associationMemberSortedListProvider); final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); final associationListNotifier = ref.watch(associationListProvider.notifier); @@ -55,7 +58,9 @@ class AssociationEditorPage extends HookConsumerWidget { child: Refresher( onRefresh: () async { await associationMemberListNotifier.loadMembers( - association.id, association.mandateYear.toString(), ref); + association.id, + association.mandateYear.toString(), + ); await associationPictureNotifier.getAssociationPicture(association.id); }, child: Column(children: [ @@ -254,7 +259,7 @@ class AssociationEditorPage extends HookConsumerWidget { builder: (context, associationMembers) => associationMembers.isEmpty ? const Text(PhonebookTextConstants.noMember) : Column( - children: associationMembers + children: associationMemberSortedList .map( (member) => MemberEditableCard( member: member, diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index e188a8487..333090f98 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -4,7 +4,6 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/membership.dart'; -import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/providers/membership_provider.dart'; @@ -28,8 +27,6 @@ class MemberEditableCard extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final profilePicture = ref.watch(profilePictureProvider); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); - final associationMembersNotifier = - ref.watch(associationMemberListProvider.notifier); final roleTagsNotifier = ref.watch(rolesTagsProvider.notifier); final membershipNotifier = ref.watch(membershipProvider.notifier); final completeMemberNotifier = ref.watch(completeMemberProvider.notifier); @@ -131,8 +128,6 @@ class MemberEditableCard extends HookConsumerWidget { member.memberships.firstWhere( (element) => element.associationId == association.id), association); - await associationMembersNotifier.loadMembers( - association.id, association.mandateYear.toString(), ref); if (result) { displayToastWithContext( TypeMsg.msg, PhonebookTextConstants.deletedMember); diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index 6b3dec76a..e4f59a77b 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/association_member_sorted_list_provider.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; @@ -20,6 +21,8 @@ class AssociationPage extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final association = ref.watch(associationProvider); final associationMemberList = ref.watch(associationMemberListProvider); + final associationMemberSortedList = + ref.watch(associationMemberSortedListProvider); final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); final associationPictureNotifier = @@ -30,7 +33,9 @@ class AssociationPage extends HookConsumerWidget { child: Refresher( onRefresh: () async { await associationMemberListNotifier.loadMembers( - association.id, association.mandateYear.toString(), ref); + association.id, + association.mandateYear.toString(), + ); await associationPictureNotifier .getAssociationPicture(association.id); }, @@ -65,7 +70,7 @@ class AssociationPage extends HookConsumerWidget { associationMembers.isEmpty ? const Text(PhonebookTextConstants.noMember) : Column( - children: associationMembers + children: associationMemberSortedList .map((member) => MemberCard( member: member, association: association, diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index a9cc92f54..327e85f43 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -53,54 +53,58 @@ class MembershipEditorPage extends HookConsumerWidget { } return PhonebookTemplate( - child: Padding( - padding: const EdgeInsets.all(30.0), - child: SingleChildScrollView( - child: Column( - children: [ - AlignLeftText(isEdit - ? PhonebookTextConstants.editMembership - : PhonebookTextConstants.addMember), - if (!isEdit) ...[ - StyledSearchBar( - padding: EdgeInsets.zero, - label: PhonebookTextConstants.member, - editingController: queryController, - onChanged: (value) async { - tokenExpireWrapper(ref, () async { + child: Padding( + padding: const EdgeInsets.all(30.0), + child: SingleChildScrollView( + child: Column( + children: [ + AlignLeftText(isEdit + ? PhonebookTextConstants.editMembership + : PhonebookTextConstants.addMember), + if (!isEdit) ...[ + StyledSearchBar( + padding: EdgeInsets.zero, + label: PhonebookTextConstants.member, + editingController: queryController, + onChanged: (value) async { + tokenExpireWrapper( + ref, + () async { if (value.isNotEmpty) { await usersNotifier.filterUsers(value); } else { usersNotifier.clear(); } - }); - }, - ), - SearchResult(queryController: queryController), - ] else - member.member.nickname == null - ? Text( - "${member.member.firstname} ${member.member.name}", - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ) - : Text( - "${member.member.nickname} (${member.member.firstname} ${member.member.name})", - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - const SizedBox( - height: 10, + }, + ); + }, ), - SizedBox( - width: min(MediaQuery.of(context).size.width, 300), - child: AsyncChild( - value: rolesTagList, - builder: (context, rolesTags) => Column(children: [ + SearchResult(queryController: queryController), + ] else + member.member.nickname == null + ? Text( + "${member.member.firstname} ${member.member.name}", + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + ), + ) + : Text( + "${member.member.nickname} (${member.member.firstname} ${member.member.name})", + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + ), + ), + const SizedBox( + height: 10, + ), + SizedBox( + width: min(MediaQuery.of(context).size.width, 300), + child: AsyncChild( + value: rolesTagList, + builder: (context, rolesTags) => Column( + children: [ ...rolesTags.keys.map( (tagKey) => Row( children: [ @@ -131,42 +135,46 @@ class MembershipEditorPage extends HookConsumerWidget { ], ), ) - ]), + ], ), ), - const SizedBox(height: 30), - TextEntry( - controller: apparentNameController, - label: PhonebookTextConstants.apparentName, + ), + const SizedBox(height: 30), + TextEntry( + controller: apparentNameController, + label: PhonebookTextConstants.apparentName, + ), + const SizedBox(height: 50), + WaitingButton( + builder: (child) => AddEditButtonLayout(colors: const [ + ColorConstants.gradient1, + ColorConstants.gradient2, + ], child: child), + child: Text( + !isEdit + ? PhonebookTextConstants.add + : PhonebookTextConstants.edit, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), + ), ), - const SizedBox(height: 50), - WaitingButton( - builder: (child) => AddEditButtonLayout(colors: const [ - ColorConstants.gradient1, - ColorConstants.gradient2, - ], child: child), - child: Text( - !isEdit - ? PhonebookTextConstants.add - : PhonebookTextConstants.edit, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color.fromARGB(255, 255, 255, 255), - )), - onTap: () async { - if (member.member.id == "") { - displayToastWithContext( - TypeMsg.msg, PhonebookTextConstants.emptyMember); - return; - } - if (apparentNameController.text == "") { - displayToastWithContext(TypeMsg.msg, - PhonebookTextConstants.emptyApparentName); - return; - } + onTap: () async { + if (member.member.id == "") { + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.emptyMember); + return; + } + if (apparentNameController.text == "") { + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.emptyApparentName); + return; + } - tokenExpireWrapper(ref, () async { + tokenExpireWrapper( + ref, + () async { if (isEdit) { final membershipEdit = Membership( id: membership.id, @@ -182,9 +190,9 @@ class MembershipEditorPage extends HookConsumerWidget { ); if (value) { associationMemberListNotifier.loadMembers( - association.id, - association.mandateYear.toString(), - ref); + association.id, + association.mandateYear.toString(), + ); displayToastWithContext(TypeMsg.msg, PhonebookTextConstants.updatedMember); QR.back(); @@ -220,9 +228,10 @@ class MembershipEditorPage extends HookConsumerWidget { membershipAdd, association); if (value) { associationMemberListNotifier.loadMembers( - association.id, - association.mandateYear.toString(), - ref); + //TODO + association.id, + association.mandateYear.toString(), + ); displayToastWithContext( TypeMsg.msg, PhonebookTextConstants.addedMember); QR.back(); @@ -231,10 +240,14 @@ class MembershipEditorPage extends HookConsumerWidget { PhonebookTextConstants.addingError); } } - }); - }, - ), - ], - )))); + }, + ); + }, + ), + ], + ), + ), + ), + ); } } From e3136214f82d8a0dc679bcdf6ee838fe00645d32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 16:06:00 +0100 Subject: [PATCH 098/123] fix: some member card ui overflow --- .../pages/association_page/member_card.dart | 68 +++++-------------- 1 file changed, 16 insertions(+), 52 deletions(-) diff --git a/lib/phonebook/ui/pages/association_page/member_card.dart b/lib/phonebook/ui/pages/association_page/member_card.dart index 2f1cd6025..e77601755 100644 --- a/lib/phonebook/ui/pages/association_page/member_card.dart +++ b/lib/phonebook/ui/pages/association_page/member_card.dart @@ -1,13 +1,13 @@ import 'package:collection/collection.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:flutter/widgets.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; -import 'package:myecl/phonebook/ui/components/copiabled_text.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/tools/ui/layouts/card_layout.dart'; import 'package:qlevar_router/qlevar_router.dart'; @@ -38,17 +38,18 @@ class MemberCard extends HookConsumerWidget { child: CardLayout( margin: EdgeInsets.zero, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - if (!kIsWeb) ...[ - if (member.member.nickname != null) ...[ - CopiabledText( + if (member.member.nickname != null) ...[ + Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text( member.member.nickname!, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), ), - CopiabledText( + Text( "(${member.member.name} ${member.member.firstname})", style: const TextStyle( fontWeight: FontWeight.bold, @@ -56,55 +57,18 @@ class MemberCard extends HookConsumerWidget { color: Color.fromARGB(255, 115, 115, 115), ), ), - ] else - CopiabledText( - "${member.member.name} ${member.member.firstname}", - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - const Spacer(), - CopiabledText( - assoMembership == null - ? PhonebookTextConstants.noMemberRole - : assoMembership.apparentName, + ]), + ] else + Text( + "${member.member.name} ${member.member.firstname}", style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), - ) - ] else ...[ - if (member.member.nickname != null) - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - member.member.nickname!, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - Text( - "${member.member.name} ${member.member.firstname}", - style: const TextStyle( - fontSize: 16, - color: Color.fromARGB(255, 115, 115, 115), - ), - ), - ], - ) - else - Text( - "${member.member.name} ${member.member.firstname}", - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - const Spacer(flex: 1), - Text( + ), + Flexible( + child: Text( + textAlign: TextAlign.right, assoMembership == null ? PhonebookTextConstants.noMemberRole : assoMembership.apparentName, @@ -113,7 +77,7 @@ class MemberCard extends HookConsumerWidget { fontSize: 16, ), ), - ], + ), ], ), ), From 02d8b94689f9666253e602e89ebc884a01124644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 17:01:42 +0100 Subject: [PATCH 099/123] feat: add profile picture in edit asso page --- .../member_editable_card.dart | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index 333090f98..b1c6a1998 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -1,5 +1,6 @@ import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; @@ -25,7 +26,7 @@ class MemberEditableCard extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final profilePicture = ref.watch(profilePictureProvider); + final profilePictureNotifier = ref.watch(profilePictureProvider.notifier); final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final roleTagsNotifier = ref.watch(rolesTagsProvider.notifier); final membershipNotifier = ref.watch(membershipProvider.notifier); @@ -34,6 +35,14 @@ class MemberEditableCard extends HookConsumerWidget { displayToast(context, type, msg); } + final profilePicture = useState(const AsyncValue.loading()); + if (!profilePicture.value.hasValue) { + profilePictureNotifier.getProfilePicture(member.member.id).then( + (pictureAsync) => pictureAsync.maybeWhen( + data: (picture) => profilePicture.value = AsyncData(picture), + orElse: () {})); + } + Membership assoMembership = member.memberships.firstWhere( (memberships) => memberships.associationId == association.id && @@ -63,7 +72,7 @@ class MemberEditableCard extends HookConsumerWidget { ), ], ), - child: profilePicture.when( + child: profilePicture.value.when( data: (picture) { return CircleAvatar( radius: 20, From 59ac6c86f90d346b62c5866b29d25bd7c50a6fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 19:48:12 +0100 Subject: [PATCH 100/123] fix: members without tag appear after the ones with tags --- lib/phonebook/tools/function.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/phonebook/tools/function.dart b/lib/phonebook/tools/function.dart index dfc5d15ca..ec09c7773 100644 --- a/lib/phonebook/tools/function.dart +++ b/lib/phonebook/tools/function.dart @@ -9,6 +9,9 @@ int getPosition( CompleteMember member, String associationId, List rolesTags) { Membership membership = member.memberships .firstWhere((element) => element.associationId == associationId); + if (membership.rolesTags.isEmpty || membership.rolesTags.first == "") { + return rolesTags.length; + } return membership.rolesTags .map((roleTag) => rolesTags.indexOf(roleTag)) .reduce((value, element) => min(value, element)); From b633ae298f9920b136481887a5358a49c6beb967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 22:42:31 +0100 Subject: [PATCH 101/123] feat:create a responsive association page --- .../association_page/association_page.dart | 15 +- .../ui/pages/association_page/card_field.dart | 41 ++++ .../association_page/web_member_card.dart | 230 ++++++++++++++++++ .../member_detail_page/element_field.dart | 3 +- .../member_detail_page.dart | 2 +- 5 files changed, 284 insertions(+), 7 deletions(-) create mode 100644 lib/phonebook/ui/pages/association_page/card_field.dart create mode 100644 lib/phonebook/ui/pages/association_page/web_member_card.dart diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index e4f59a77b..a106d7d17 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -9,6 +10,7 @@ import 'package:myecl/phonebook/providers/phonebook_admin_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/phonebook/ui/pages/association_page/member_card.dart'; +import 'package:myecl/phonebook/ui/pages/association_page/web_member_card.dart'; import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/tools/ui/builders/async_child.dart'; import 'package:myecl/tools/ui/layouts/refresher.dart'; @@ -71,10 +73,15 @@ class AssociationPage extends HookConsumerWidget { ? const Text(PhonebookTextConstants.noMember) : Column( children: associationMemberSortedList - .map((member) => MemberCard( - member: member, - association: association, - )) + .map((member) => kIsWeb + ? WebMemberCard( + member: member, + association: association, + ) + : MemberCard( + member: member, + association: association, + )) .toList(), ), ) diff --git a/lib/phonebook/ui/pages/association_page/card_field.dart b/lib/phonebook/ui/pages/association_page/card_field.dart new file mode 100644 index 000000000..02366bdb5 --- /dev/null +++ b/lib/phonebook/ui/pages/association_page/card_field.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:myecl/phonebook/ui/components/copiabled_text.dart'; + +class CardField extends StatelessWidget { + final String label; + final String value; + final bool showLabel; + const CardField( + {super.key, + required this.label, + required this.value, + this.showLabel = true}); + + @override + Widget build(BuildContext context) { + return Container( + margin: const EdgeInsets.symmetric(vertical: 5.0, horizontal: 10), + child: Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (showLabel) ...[ + Text( + label, + style: const TextStyle(fontSize: 16), + ), + const SizedBox( + width: 5, + ) + ], + CopiabledText( + value, + maxLines: 1, + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16), + ), + ], + ), + ), + ); + } +} diff --git a/lib/phonebook/ui/pages/association_page/web_member_card.dart b/lib/phonebook/ui/pages/association_page/web_member_card.dart new file mode 100644 index 000000000..70a45989b --- /dev/null +++ b/lib/phonebook/ui/pages/association_page/web_member_card.dart @@ -0,0 +1,230 @@ +import 'package:collection/collection.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/association.dart'; +import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/membership.dart'; +import 'package:myecl/phonebook/providers/complete_member_provider.dart'; +import 'package:myecl/phonebook/router.dart'; +import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/phonebook/ui/pages/association_page/card_field.dart'; +import 'package:myecl/tools/ui/layouts/card_layout.dart'; +import 'package:qlevar_router/qlevar_router.dart'; + +class WebMemberCard extends HookConsumerWidget { + const WebMemberCard( + {super.key, required this.member, required this.association}); + + final CompleteMember member; + final Association association; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final memberNotifier = ref.watch(completeMemberProvider.notifier); + Membership? assoMembership = member.memberships.firstWhereOrNull( + (memberships) => + memberships.associationId == association.id && + memberships.mandateYear == association.mandateYear); + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 5), + child: GestureDetector( + onTap: () { + memberNotifier.setCompleteMember(member); + QR.to(PhonebookRouter.root + PhonebookRouter.memberDetail); + }, + child: CardLayout( + margin: EdgeInsets.zero, + child: LayoutBuilder( + builder: (context, constraints) { + if (constraints.maxWidth > 700) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (member.member.nickname != null) ...[ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SelectableText( + member.member.nickname!, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 20, + ), + ), + const SizedBox( + width: 10, + ), + SelectableText( + "(${member.member.name} ${member.member.firstname})", + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 20, + color: Color.fromARGB(255, 115, 115, 115), + ), + ), + ]), + ] else + SelectableText( + "${member.member.name} ${member.member.firstname}", + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 20, + ), + ), + const SizedBox( + height: 5, + ), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + CardField( + label: PhonebookTextConstants.promotion, + value: member.member.promotion == 0 + ? PhonebookTextConstants.promoNotGiven + : member.member.promotion < 100 + ? "20${member.member.promotion}" + : member.member.promotion + .toString()), + CardField( + label: PhonebookTextConstants.email, + value: member.member.email), + if (member.member.phone != null) + CardField( + label: PhonebookTextConstants.phone, + value: member.member.phone!), + ], + ), + ) + ], + ), + ), + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + textAlign: TextAlign.right, + assoMembership == null + ? PhonebookTextConstants.noMemberRole + : assoMembership.apparentName, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 20, + ), + ), + ], + ) + ], + ); + } + return Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (member.member.nickname != null) ...[ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SelectableText( + member.member.nickname!, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 20, + ), + ), + const SizedBox( + width: 10, + ), + SelectableText( + "(${member.member.name} ${member.member.firstname})", + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 20, + color: Color.fromARGB(255, 115, 115, 115), + ), + ), + ]), + ] else + SelectableText( + "${member.member.name} ${member.member.firstname}", + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 20, + ), + ), + const SizedBox( + height: 5, + ), + CardField( + label: PhonebookTextConstants.promotion, + value: member.member.promotion == 0 + ? PhonebookTextConstants.promoNotGiven + : member.member.promotion < 100 + ? "20${member.member.promotion}" + : member.member.promotion.toString()), + if (constraints.maxWidth > 500) + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: [ + CardField( + label: PhonebookTextConstants.email, + value: member.member.email, + ), + if (member.member.phone != null) + CardField( + label: PhonebookTextConstants.phone, + value: member.member.phone!, + ), + ], + ), + ) + else + Column( + children: [ + CardField( + label: PhonebookTextConstants.email, + value: member.member.email, + showLabel: false), + if (member.member.phone != null) + CardField( + label: PhonebookTextConstants.phone, + value: member.member.phone!, + showLabel: false), + ], + ) + ], + ), + Column( + children: [ + Text( + textAlign: TextAlign.right, + assoMembership == null + ? PhonebookTextConstants.noMemberRole + : assoMembership.apparentName, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 20, + ), + ), + ], + ) + ], + ); + }, + ), + ), + ), + ); + } +} diff --git a/lib/phonebook/ui/pages/member_detail_page/element_field.dart b/lib/phonebook/ui/pages/member_detail_page/element_field.dart index 7f6f19289..f98fa6b36 100644 --- a/lib/phonebook/ui/pages/member_detail_page/element_field.dart +++ b/lib/phonebook/ui/pages/member_detail_page/element_field.dart @@ -48,8 +48,7 @@ class ElementField extends StatelessWidget { Center( child: Text( label, - style: const TextStyle( - fontWeight: FontWeight.bold, fontSize: 16), + style: const TextStyle(fontSize: 16), )), Center( child: SelectableText( diff --git a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart index 92cf9bc17..be752cac9 100644 --- a/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart +++ b/lib/phonebook/ui/pages/member_detail_page/member_detail_page.dart @@ -24,7 +24,7 @@ class MemberDetailPage extends HookConsumerWidget { child: Column( children: [ Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), + padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 30), child: CardLayout( margin: EdgeInsets.zero, child: Column(children: [ From bbabec47089dd2aa2fadd3e14a1e19bb8ca3645b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 22:49:08 +0100 Subject: [PATCH 102/123] fix: overflow --- .../member_editable_card.dart | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index b1c6a1998..ad5e6308b 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -94,25 +94,28 @@ class MemberEditableCard extends HookConsumerWidget { ), ), const SizedBox(width: 10), - Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - AutoSizeText( - "${(member.member.nickname ?? member.member.firstname)} - ${member.memberships.firstWhere((element) => element.associationId == association.id).apparentName}", - style: const TextStyle( - fontWeight: FontWeight.bold, - ), - minFontSize: 10, - maxFontSize: 15, - ), - const SizedBox(height: 3), - AutoSizeText( - member.member.nickname != null - ? "${member.member.firstname} ${member.member.name}" - : member.member.name, - minFontSize: 10, - maxFontSize: 15, - ), - ]), - const Spacer(), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AutoSizeText( + "${(member.member.nickname ?? member.member.firstname)} - ${member.memberships.firstWhere((element) => element.associationId == association.id).apparentName}", + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + minFontSize: 10, + maxFontSize: 15, + ), + const SizedBox(height: 3), + AutoSizeText( + member.member.nickname != null + ? "${member.member.firstname} ${member.member.name}" + : member.member.name, + minFontSize: 10, + maxFontSize: 15, + ), + ]), + ), EditionButton(onEdition: () async { roleTagsNotifier.resetChecked(); roleTagsNotifier.loadRoleTagsFromMember(member, association); From b515be2bd7fb35946ec427e28bf8ceba1ea0ec30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 23:13:47 +0100 Subject: [PATCH 103/123] fix: MemberListProvider deletion --- .../association_member_list_provider.dart | 11 +++++++++++ lib/phonebook/providers/association_provider.dart | 7 ------- .../association_member_repository.dart | 4 ++++ .../repositories/association_repository.dart | 4 ---- .../member_editable_card.dart | 15 +++++++++------ 5 files changed, 24 insertions(+), 17 deletions(-) diff --git a/lib/phonebook/providers/association_member_list_provider.dart b/lib/phonebook/providers/association_member_list_provider.dart index d547e734b..4e9fd9a0c 100644 --- a/lib/phonebook/providers/association_member_list_provider.dart +++ b/lib/phonebook/providers/association_member_list_provider.dart @@ -1,6 +1,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/repositories/association_member_repository.dart'; import 'package:myecl/tools/providers/list_notifier.dart'; @@ -19,6 +20,16 @@ class AssociationMemberListNotifier extends ListNotifier { return await loadList(() async => associationMemberRepository .getAssociationMemberList(associationId, year)); } + + Future deleteMember( + CompleteMember member, Membership membership) async { + return await delete( + associationMemberRepository.deleteMember, + (members, member) => + members..removeWhere((i) => i.member.id == member.member.id), + membership.id, + member); + } } final associationMemberListProvider = StateNotifierProvider< diff --git a/lib/phonebook/providers/association_provider.dart b/lib/phonebook/providers/association_provider.dart index 58d591f99..43ac4f459 100644 --- a/lib/phonebook/providers/association_provider.dart +++ b/lib/phonebook/providers/association_provider.dart @@ -23,13 +23,6 @@ class AssociationNotifier extends SingleNotifier { association); } - Future deleteMember( - Membership membership, Association association) async { - return await update( - (association) async => associationRepository.deleteMember(membership), - association); - } - Future updateMember( Membership membership, Association association) async { return await update( diff --git a/lib/phonebook/repositories/association_member_repository.dart b/lib/phonebook/repositories/association_member_repository.dart index 9330f86c6..ddab096e2 100644 --- a/lib/phonebook/repositories/association_member_repository.dart +++ b/lib/phonebook/repositories/association_member_repository.dart @@ -12,4 +12,8 @@ class AssociationMemberRepository extends Repository { (await getList(suffix: "$associationId/members/$year")) .map((x) => CompleteMember.fromJson(x))); } + + Future deleteMember(String membershipId) async { + return await delete("memberships/$membershipId"); + } } diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index 5e1614c1b..df18d2797 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -34,10 +34,6 @@ class AssociationRepository extends Repository { return value != null; } - Future deleteMember(Membership membership) async { - return await delete("memberships/${membership.id}"); - } - Future updateMember(Membership membership) async { return await update(membership.toJson(), "memberships/", suffix: membership.id); diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index ad5e6308b..8856a32f0 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -5,7 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/membership.dart'; -import 'package:myecl/phonebook/providers/association_provider.dart'; +import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/providers/membership_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; @@ -27,7 +27,8 @@ class MemberEditableCard extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final profilePictureNotifier = ref.watch(profilePictureProvider.notifier); - final associationNotifier = ref.watch(asyncAssociationProvider.notifier); + final associationMemberListNotifier = + ref.watch(associationMemberListProvider.notifier); final roleTagsNotifier = ref.watch(rolesTagsProvider.notifier); final membershipNotifier = ref.watch(membershipProvider.notifier); final completeMemberNotifier = ref.watch(completeMemberProvider.notifier); @@ -136,10 +137,12 @@ class MemberEditableCard extends HookConsumerWidget { const SizedBox(width: 10), DeleteButton( onDelete: () async { - final result = await associationNotifier.deleteMember( - member.memberships.firstWhere( - (element) => element.associationId == association.id), - association); + final result = await associationMemberListNotifier.deleteMember( + member, + member.memberships.firstWhere((element) => + element.associationId == association.id && + element.mandateYear == association.mandateYear), + ); if (result) { displayToastWithContext( TypeMsg.msg, PhonebookTextConstants.deletedMember); From e24e65ead6e54c9c867ce5b60d44dddf599a27f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 23:29:36 +0100 Subject: [PATCH 104/123] fix: profile picture --- .../association_editor_page/member_editable_card.dart | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index 8856a32f0..66c6b722f 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -8,12 +8,12 @@ import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/phonebook/providers/membership_provider.dart'; +import 'package:myecl/phonebook/providers/profile_picture_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/delete_button.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/edition_button.dart'; import 'package:myecl/tools/functions.dart'; -import 'package:myecl/user/providers/profile_picture_provider.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:qlevar_router/qlevar_router.dart'; @@ -39,9 +39,8 @@ class MemberEditableCard extends HookConsumerWidget { final profilePicture = useState(const AsyncValue.loading()); if (!profilePicture.value.hasValue) { profilePictureNotifier.getProfilePicture(member.member.id).then( - (pictureAsync) => pictureAsync.maybeWhen( - data: (picture) => profilePicture.value = AsyncData(picture), - orElse: () {})); + (picture) => profilePicture.value = AsyncData(picture), + ); } Membership assoMembership = member.memberships.firstWhere( @@ -77,9 +76,7 @@ class MemberEditableCard extends HookConsumerWidget { data: (picture) { return CircleAvatar( radius: 20, - backgroundImage: picture.isEmpty - ? const AssetImage('assets/images/logo_alpha.png') - : Image.memory(picture).image, + backgroundImage: picture.image, ); }, loading: () { From e8945a6be76650fb8e9604a880cf0ab097acce48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Wed, 28 Feb 2024 23:46:55 +0100 Subject: [PATCH 105/123] fix: setKind on route changes --- lib/phonebook/ui/pages/admin_page/admin_page.dart | 3 +++ .../ui/pages/admin_page/editable_association_card.dart | 2 -- lib/phonebook/ui/pages/main_page/main_page.dart | 3 +++ lib/phonebook/ui/phonebook.dart | 9 +++++++++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 7133682bf..002af1294 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/providers/association_filtered_list_provider.dart'; +import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; @@ -24,6 +25,7 @@ class AdminPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final associationNotifier = ref.watch(asyncAssociationProvider.notifier); + final kindNotifier = ref.watch(associationKindProvider.notifier); final associationListNotifier = ref.watch(associationListProvider.notifier); final associationList = ref.watch(associationListProvider); final associationFilteredList = ref.watch(associationFilteredListProvider); @@ -82,6 +84,7 @@ class AdminPage extends HookConsumerWidget { child: EditableAssociationCard( association: association, onEdit: () { + kindNotifier.setKind(association.kind); associationNotifier.setAssociation(association); QR.to(PhonebookRouter.root + PhonebookRouter.admin + diff --git a/lib/phonebook/ui/pages/admin_page/editable_association_card.dart b/lib/phonebook/ui/pages/admin_page/editable_association_card.dart index 03e304205..ff61e422d 100644 --- a/lib/phonebook/ui/pages/admin_page/editable_association_card.dart +++ b/lib/phonebook/ui/pages/admin_page/editable_association_card.dart @@ -1,6 +1,4 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/delete_button.dart'; diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 152db60a3..4c33a6d42 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/providers/association_filtered_list_provider.dart'; +import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; @@ -28,6 +29,7 @@ class PhonebookMainPage extends HookConsumerWidget { final associationFilteredList = ref.watch(associationFilteredListProvider); final associationKindsNotifier = ref.watch(associationKindsProvider.notifier); + final kindNotifier = ref.watch(associationKindProvider.notifier); return PhonebookTemplate( child: Refresher( @@ -47,6 +49,7 @@ class PhonebookMainPage extends HookConsumerWidget { padding: const EdgeInsets.only(left: 20), child: AdminButton( onTap: () { + kindNotifier.setKind(''); QR.to(PhonebookRouter.root + PhonebookRouter.admin); }, ), diff --git a/lib/phonebook/ui/phonebook.dart b/lib/phonebook/ui/phonebook.dart index fc927b8fe..67dd35e9c 100644 --- a/lib/phonebook/ui/phonebook.dart +++ b/lib/phonebook/ui/phonebook.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/router.dart'; import 'package:myecl/phonebook/tools/constants.dart'; import 'package:myecl/tools/ui/widgets/top_bar.dart'; @@ -11,6 +12,7 @@ class PhonebookTemplate extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { + final kindNotifier = ref.watch(associationKindProvider.notifier); return Scaffold( body: Column( children: [ @@ -18,6 +20,13 @@ class PhonebookTemplate extends HookConsumerWidget { title: PhonebookTextConstants.phonebook, root: PhonebookRouter.root, onBack: () { + if (QR.currentPath != + PhonebookRouter.root + + PhonebookRouter.admin + + PhonebookRouter.editAssociation + + PhonebookRouter.addEditMember) { + kindNotifier.setKind(''); + } if (QR.currentPath == PhonebookRouter.root + PhonebookRouter.admin + From 6956ae4a82f05e3205d7759a7c731a365511a385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Thu, 29 Feb 2024 00:25:30 +0100 Subject: [PATCH 106/123] fix: cleaner provider use for addedit membership --- .../association_member_list_provider.dart | 18 ++++++++++++++++++ .../providers/association_provider.dart | 14 -------------- .../association_member_repository.dart | 11 +++++++++++ .../repositories/association_repository.dart | 11 ----------- .../membership_editor_page.dart | 19 +++++++++---------- 5 files changed, 38 insertions(+), 35 deletions(-) diff --git a/lib/phonebook/providers/association_member_list_provider.dart b/lib/phonebook/providers/association_member_list_provider.dart index 4e9fd9a0c..8f5517968 100644 --- a/lib/phonebook/providers/association_member_list_provider.dart +++ b/lib/phonebook/providers/association_member_list_provider.dart @@ -21,6 +21,24 @@ class AssociationMemberListNotifier extends ListNotifier { .getAssociationMemberList(associationId, year)); } + Future addMember(CompleteMember member, Membership membership) async { + return await add((member) async { + member.memberships + .add(await associationMemberRepository.addMember(membership)); + return member; + }, member); + } + + Future updateMember( + CompleteMember member, Membership membership) async { + return await update( + (member) => associationMemberRepository.updateMember(membership), + (members, member) => members + ..[members.indexWhere((e) => e.member.id == member.member.id)] = + member, + member); + } + Future deleteMember( CompleteMember member, Membership membership) async { return await delete( diff --git a/lib/phonebook/providers/association_provider.dart b/lib/phonebook/providers/association_provider.dart index 43ac4f459..5e53f1b7c 100644 --- a/lib/phonebook/providers/association_provider.dart +++ b/lib/phonebook/providers/association_provider.dart @@ -1,7 +1,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:myecl/auth/providers/openid_provider.dart'; import 'package:myecl/phonebook/class/association.dart'; -import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/repositories/association_repository.dart'; import 'package:myecl/tools/providers/single_notifier.dart'; @@ -17,19 +16,6 @@ class AssociationNotifier extends SingleNotifier { () async => associationRepository.getAssociation(associationId)); } - Future addMember(Membership membership, Association association) async { - return await update( - (association) async => associationRepository.addMember(membership), - association); - } - - Future updateMember( - Membership membership, Association association) async { - return await update( - (association) async => associationRepository.updateMember(membership), - association); - } - void setAssociation(Association association) { state = AsyncValue.data(association); } diff --git a/lib/phonebook/repositories/association_member_repository.dart b/lib/phonebook/repositories/association_member_repository.dart index ddab096e2..8787c488d 100644 --- a/lib/phonebook/repositories/association_member_repository.dart +++ b/lib/phonebook/repositories/association_member_repository.dart @@ -1,4 +1,5 @@ import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/tools/repository/repository.dart'; class AssociationMemberRepository extends Repository { @@ -13,6 +14,16 @@ class AssociationMemberRepository extends Repository { .map((x) => CompleteMember.fromJson(x))); } + Future addMember(Membership membership) async { + return Membership.fromJson( + await create(membership.toJson(), suffix: "memberships")); + } + + Future updateMember(Membership membership) async { + return await update(membership.toJson(), "memberships/", + suffix: membership.id); + } + Future deleteMember(String membershipId) async { return await delete("memberships/$membershipId"); } diff --git a/lib/phonebook/repositories/association_repository.dart b/lib/phonebook/repositories/association_repository.dart index df18d2797..aa354460e 100644 --- a/lib/phonebook/repositories/association_repository.dart +++ b/lib/phonebook/repositories/association_repository.dart @@ -1,6 +1,5 @@ import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/association_kinds.dart'; -import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/tools/repository/repository.dart'; class AssociationRepository extends Repository { @@ -29,16 +28,6 @@ class AssociationRepository extends Repository { return Association.fromJson(await create(association.toJson())); } - Future addMember(Membership membership) async { - final value = await create(membership.toJson(), suffix: "memberships"); - return value != null; - } - - Future updateMember(Membership membership) async { - return await update(membership.toJson(), "memberships/", - suffix: membership.id); - } - Future getAssociationKinds() async { return AssociationKinds.fromJson(await getOne("kinds")); } diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index 327e85f43..156d4812f 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -40,7 +40,6 @@ class MembershipEditorPage extends HookConsumerWidget { final membership = ref.watch(membershipProvider); final association = ref.watch(associationProvider); final isEdit = membership.id != Membership.empty().id; - final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationMemberListNotifier = ref.watch(associationMemberListProvider.notifier); final memberRoleTagsNotifier = ref.watch(memberRoleTagsProvider.notifier); @@ -184,9 +183,14 @@ class MembershipEditorPage extends HookConsumerWidget { apparentName: apparentNameController.text, mandateYear: membership.mandateYear, ); - final value = await associationNotifier.updateMember( + member.memberships[member.memberships.indexWhere( + (membership) => + membership.id == membershipEdit.id)] = + membershipEdit; + final value = + await associationMemberListNotifier.updateMember( + member, membershipEdit, - association, ); if (value) { associationMemberListNotifier.loadMembers( @@ -224,14 +228,9 @@ class MembershipEditorPage extends HookConsumerWidget { apparentName: apparentNameController.text, mandateYear: association.mandateYear, ); - final value = await associationNotifier.addMember( - membershipAdd, association); + final value = await associationMemberListNotifier + .addMember(member, membershipAdd); if (value) { - associationMemberListNotifier.loadMembers( - //TODO - association.id, - association.mandateYear.toString(), - ); displayToastWithContext( TypeMsg.msg, PhonebookTextConstants.addedMember); QR.back(); From 8577ee864a2b2f314c903b360388dac7073636da Mon Sep 17 00:00:00 2001 From: Thonyk Date: Thu, 29 Feb 2024 01:00:10 +0100 Subject: [PATCH 107/123] fix: use diacritic to convert accent into regular character --- .../providers/association_filtered_list_provider.dart | 7 ++++--- pubspec.lock | 8 ++++++++ pubspec.yaml | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/phonebook/providers/association_filtered_list_provider.dart b/lib/phonebook/providers/association_filtered_list_provider.dart index 6dae870bf..8131511b0 100644 --- a/lib/phonebook/providers/association_filtered_list_provider.dart +++ b/lib/phonebook/providers/association_filtered_list_provider.dart @@ -5,6 +5,7 @@ import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/phonebook/providers/association_list_provider.dart'; import 'package:myecl/phonebook/providers/research_filter_provider.dart'; import 'package:myecl/phonebook/tools/function.dart'; +import 'package:diacritic/diacritic.dart'; final associationFilteredListProvider = Provider>((ref) { final associationsProvider = ref.watch(associationListProvider); @@ -14,9 +15,9 @@ final associationFilteredListProvider = Provider>((ref) { return associationsProvider.maybeWhen( data: (associations) { List filteredAssociations = associations - .where((association) => association.name - .toLowerCase() - .contains(searchFilter.toLowerCase())) + .where((association) => + removeDiacritics(association.name.toLowerCase()) + .contains(removeDiacritics(searchFilter.toLowerCase()))) .toList(); if (kindFilter != "") { filteredAssociations = filteredAssociations diff --git a/pubspec.lock b/pubspec.lock index 4ce9cdd63..05b066c76 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -185,6 +185,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + diacritic: + dependency: "direct main" + description: + name: diacritic + sha256: "96db5db6149cbe4aa3cfcbfd170aca9b7648639be7e48025f9d458517f807fe4" + url: "https://pub.dev" + source: hosted + version: "0.1.5" dotenv: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 8038ef18b..056c058e3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,6 +14,7 @@ dependencies: crypto: ^3.0.2 datetime_picker_formfield: ^2.0.1 device_info_plus: ^9.1.2 + diacritic: ^0.1.5 dotenv: ^4.0.1 firebase_core: ^2.25.5 either_dart: ^1.0.0 From 469315031917af94f13b677e02fa5964acf12dec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Thu, 29 Feb 2024 14:38:14 +0100 Subject: [PATCH 108/123] feat: animate KindsBar to selected --- lib/phonebook/ui/components/kinds_bar.dart | 62 ++++++++++++------- .../ui/pages/admin_page/admin_page.dart | 2 +- .../ui/pages/main_page/main_page.dart | 2 +- 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/lib/phonebook/ui/components/kinds_bar.dart b/lib/phonebook/ui/components/kinds_bar.dart index a8128833a..1a1d70dcd 100644 --- a/lib/phonebook/ui/components/kinds_bar.dart +++ b/lib/phonebook/ui/components/kinds_bar.dart @@ -1,41 +1,59 @@ import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_kinds_provider.dart'; import 'package:myecl/tools/ui/builders/async_child.dart'; -import 'package:myecl/tools/ui/layouts/horizontal_list_view.dart'; import 'package:myecl/tools/ui/layouts/item_chip.dart'; -class KindsBar extends ConsumerWidget { - const KindsBar({super.key}); - +class KindsBar extends HookConsumerWidget { + KindsBar({super.key}); + final dataKey = GlobalKey(); @override Widget build(BuildContext context, WidgetRef ref) { final kind = ref.watch(associationKindProvider); final kindNotifier = ref.watch(associationKindProvider.notifier); final associationKinds = ref.watch(associationKindsProvider); - + useEffect( + () { + Future( + () => Scrollable.ensureVisible( + dataKey.currentContext!, + duration: const Duration(milliseconds: 500), + alignment: 0.5, + ), + ); + return; + }, + [dataKey], + ); return AsyncChild( value: associationKinds, - builder: (context, kinds) => HorizontalListView.builder( + builder: (context, kinds) => SizedBox( + width: MediaQuery.of(context).size.width, height: 40, - items: kinds.kinds, - itemBuilder: (context, item, index) { - final selected = kind == item; - return ItemChip( - onTap: () { - kindNotifier.setKind(!selected ? item : ""); - }, - selected: selected, - child: Text( - item, - style: TextStyle( - color: selected ? Colors.white : Colors.black, - fontWeight: FontWeight.bold, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: kinds.kinds.length, + itemBuilder: (context, index) { + final item = kinds.kinds[index]; + final selected = kind == item; + return ItemChip( + key: selected ? dataKey : null, + onTap: () { + kindNotifier.setKind(!selected ? item : ""); + }, + selected: selected, + child: Text( + item, + style: TextStyle( + color: selected ? Colors.white : Colors.black, + fontWeight: FontWeight.bold, + ), ), - ), - ); - }, + ); + }, + ), ), ); } diff --git a/lib/phonebook/ui/pages/admin_page/admin_page.dart b/lib/phonebook/ui/pages/admin_page/admin_page.dart index 002af1294..22f818ba6 100644 --- a/lib/phonebook/ui/pages/admin_page/admin_page.dart +++ b/lib/phonebook/ui/pages/admin_page/admin_page.dart @@ -52,7 +52,7 @@ class AdminPage extends HookConsumerWidget { builder: (context, associations) { return Column( children: [ - const KindsBar(), + KindsBar(), GestureDetector( onTap: () { QR.to(PhonebookRouter.root + diff --git a/lib/phonebook/ui/pages/main_page/main_page.dart b/lib/phonebook/ui/pages/main_page/main_page.dart index 4c33a6d42..d1f71b2dc 100644 --- a/lib/phonebook/ui/pages/main_page/main_page.dart +++ b/lib/phonebook/ui/pages/main_page/main_page.dart @@ -63,7 +63,7 @@ class PhonebookMainPage extends HookConsumerWidget { builder: (context, associations) { return Column( children: [ - const KindsBar(), + KindsBar(), const SizedBox(height: 30), if (associations.isEmpty) const Center( From 5a8cc0174d95124d96dc477444ac691fda74869e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Thu, 29 Feb 2024 15:50:43 +0100 Subject: [PATCH 109/123] lint and remove unused code --- .../member_detail_page/element_field.dart | 71 ++++++------------- 1 file changed, 23 insertions(+), 48 deletions(-) diff --git a/lib/phonebook/ui/pages/member_detail_page/element_field.dart b/lib/phonebook/ui/pages/member_detail_page/element_field.dart index f98fa6b36..21163787c 100644 --- a/lib/phonebook/ui/pages/member_detail_page/element_field.dart +++ b/lib/phonebook/ui/pages/member_detail_page/element_field.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:myecl/phonebook/tools/constants.dart'; @@ -16,52 +15,28 @@ class ElementField extends StatelessWidget { } return Container( - margin: const EdgeInsets.symmetric(vertical: 5.0), - child: (kIsWeb) - ? Row( - children: [ - Expanded( - flex: 1, - child: Center( - child: Text( - label, - style: const TextStyle( - fontWeight: FontWeight.bold, fontSize: 16), - ))), - Expanded( - flex: 4, - child: Center( - child: SelectableText( - value, - maxLines: 1, - style: const TextStyle( - fontWeight: FontWeight.bold, fontSize: 16), - onTap: () { - Clipboard.setData(ClipboardData(text: value)); - displayToastWithContext( - TypeMsg.msg, PhonebookTextConstants.copied); - }, - ))), - ], - ) - : Column(children: [ - Center( - child: Text( - label, - style: const TextStyle(fontSize: 16), - )), - Center( - child: SelectableText( - value, - maxLines: 1, - style: const TextStyle( - fontWeight: FontWeight.bold, fontSize: 16), - onTap: () { - Clipboard.setData(ClipboardData(text: value)); - displayToastWithContext( - TypeMsg.msg, PhonebookTextConstants.copied); - }, - )) - ])); + margin: const EdgeInsets.symmetric(vertical: 5.0), + child: Column( + children: [ + Center( + child: Text( + label, + style: const TextStyle(fontSize: 16), + )), + Center( + child: SelectableText( + value, + maxLines: 1, + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16), + onTap: () { + Clipboard.setData(ClipboardData(text: value)); + displayToastWithContext( + TypeMsg.msg, PhonebookTextConstants.copied); + }, + ), + ) + ], + ), + ); } } From 7cd820e616f73863507c21429604c5a740a33801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Thu, 29 Feb 2024 16:33:23 +0100 Subject: [PATCH 110/123] fix: get user info on membership add --- lib/phonebook/providers/complete_member_provider.dart | 9 +++++++++ .../ui/pages/membership_editor_page/search_result.dart | 4 +--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/phonebook/providers/complete_member_provider.dart b/lib/phonebook/providers/complete_member_provider.dart index 400b47485..98657967a 100644 --- a/lib/phonebook/providers/complete_member_provider.dart +++ b/lib/phonebook/providers/complete_member_provider.dart @@ -25,6 +25,15 @@ class CompleteMemberProvider extends StateNotifier { state = state.copyWith(member: i); } + Future loadMember(String userId) async { + try { + state = await memberRepository.getCompleteMember(userId); + return true; + } catch (e) { + return false; + } + } + Future loadMembership() async { try { final data = await memberRepository.getCompleteMember(state.member.id); diff --git a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart index d6aae146e..37b3a086c 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:myecl/phonebook/class/member.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/user/providers/user_list_provider.dart'; @@ -39,10 +38,9 @@ class SearchResult extends HookConsumerWidget { ]), ), onTap: () { - memberNotifier.setMember(Member.fromUser(user)); + memberNotifier.loadMember(user.id); queryController.text = user.getName(); usersNotifier.clear(); - memberNotifier.loadMembership(); })) .toList()); }, From 6278ce16333f4e3c9a0e4235ecd3e0ce2cdac67b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Thu, 29 Feb 2024 16:40:41 +0100 Subject: [PATCH 111/123] fix: return a member when search fails --- .../ui/pages/membership_editor_page/search_result.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart index 37b3a086c..6dd7dacac 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/class/member.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; import 'package:myecl/user/providers/user_list_provider.dart'; @@ -38,7 +39,11 @@ class SearchResult extends HookConsumerWidget { ]), ), onTap: () { - memberNotifier.loadMember(user.id); + memberNotifier.loadMember(user.id).then((value) { + if (!value) { + memberNotifier.setMember(Member.fromUser(user)); + } + }); queryController.text = user.getName(); usersNotifier.clear(); })) From dab4758c5865a54e25be33bb41693485ead82cfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Thu, 29 Feb 2024 17:31:09 +0100 Subject: [PATCH 112/123] fix: member data recuperation --- .../providers/complete_member_provider.dart | 13 ++----------- .../pages/membership_editor_page/search_result.dart | 7 ++----- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/lib/phonebook/providers/complete_member_provider.dart b/lib/phonebook/providers/complete_member_provider.dart index 98657967a..33d137c42 100644 --- a/lib/phonebook/providers/complete_member_provider.dart +++ b/lib/phonebook/providers/complete_member_provider.dart @@ -25,19 +25,10 @@ class CompleteMemberProvider extends StateNotifier { state = state.copyWith(member: i); } - Future loadMember(String userId) async { - try { - state = await memberRepository.getCompleteMember(userId); - return true; - } catch (e) { - return false; - } - } - - Future loadMembership() async { + Future loadMemberComplete() async { try { final data = await memberRepository.getCompleteMember(state.member.id); - state = state.copyWith(membership: data.memberships); + state = state.copyWith(member: data.member, membership: data.memberships); return true; } catch (e) { return false; diff --git a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart index 6dd7dacac..4c19fcaea 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart @@ -39,13 +39,10 @@ class SearchResult extends HookConsumerWidget { ]), ), onTap: () { - memberNotifier.loadMember(user.id).then((value) { - if (!value) { - memberNotifier.setMember(Member.fromUser(user)); - } - }); + memberNotifier.setMember(Member.fromUser(user)); queryController.text = user.getName(); usersNotifier.clear(); + memberNotifier.loadMemberComplete(); })) .toList()); }, From a37bd8d7fa823545ad86079c5b4db03bf5bba5c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Fri, 1 Mar 2024 11:40:35 +0100 Subject: [PATCH 113/123] fix: cleaner profile pictures usage with AutoLoaderChild --- .../providers/member_pictures_provider.dart | 25 ++++++++++++ .../member_editable_card.dart | 38 +++++++------------ 2 files changed, 39 insertions(+), 24 deletions(-) create mode 100644 lib/phonebook/providers/member_pictures_provider.dart diff --git a/lib/phonebook/providers/member_pictures_provider.dart b/lib/phonebook/providers/member_pictures_provider.dart new file mode 100644 index 000000000..c2d10683e --- /dev/null +++ b/lib/phonebook/providers/member_pictures_provider.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:myecl/phonebook/class/complete_member.dart'; +import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; +import 'package:myecl/tools/providers/map_provider.dart'; +import 'package:myecl/tools/token_expire_wrapper.dart'; + +class MemberPicturesNotifier extends MapNotifier { + MemberPicturesNotifier() : super(); +} + +final memberPicturesProvider = StateNotifierProvider>?>>>((ref) { + MemberPicturesNotifier memberPicturesNotifier = MemberPicturesNotifier(); + tokenExpireWrapperAuth(ref, () async { + ref.watch(associationMemberListProvider).maybeWhen(data: (member) { + memberPicturesNotifier.loadTList(member); + return MemberPicturesNotifier; + }, orElse: () { + memberPicturesNotifier.loadTList([]); + return memberPicturesNotifier; + }); + }); + return memberPicturesNotifier; +}); diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index 66c6b722f..b552113a8 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -1,12 +1,12 @@ import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:myecl/phonebook/class/association.dart'; import 'package:myecl/phonebook/class/complete_member.dart'; import 'package:myecl/phonebook/class/membership.dart'; import 'package:myecl/phonebook/providers/association_member_list_provider.dart'; import 'package:myecl/phonebook/providers/complete_member_provider.dart'; +import 'package:myecl/phonebook/providers/member_pictures_provider.dart'; import 'package:myecl/phonebook/providers/membership_provider.dart'; import 'package:myecl/phonebook/providers/profile_picture_provider.dart'; import 'package:myecl/phonebook/providers/roles_tags_provider.dart'; @@ -15,6 +15,7 @@ import 'package:myecl/phonebook/ui/pages/admin_page/delete_button.dart'; import 'package:myecl/phonebook/ui/pages/admin_page/edition_button.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/phonebook/tools/constants.dart'; +import 'package:myecl/tools/ui/builders/auto_loader_child.dart'; import 'package:qlevar_router/qlevar_router.dart'; class MemberEditableCard extends HookConsumerWidget { @@ -36,12 +37,8 @@ class MemberEditableCard extends HookConsumerWidget { displayToast(context, type, msg); } - final profilePicture = useState(const AsyncValue.loading()); - if (!profilePicture.value.hasValue) { - profilePictureNotifier.getProfilePicture(member.member.id).then( - (picture) => profilePicture.value = AsyncData(picture), - ); - } + final memberPictures = ref.watch(memberPicturesProvider); + final memberPicturesNotifier = ref.watch(memberPicturesProvider.notifier); Membership assoMembership = member.memberships.firstWhere( (memberships) => @@ -72,23 +69,16 @@ class MemberEditableCard extends HookConsumerWidget { ), ], ), - child: profilePicture.value.when( - data: (picture) { - return CircleAvatar( - radius: 20, - backgroundImage: picture.image, - ); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return const Center( - child: Text("Error"), - ); - }, + child: AutoLoaderChild( + value: memberPictures, + notifier: memberPicturesNotifier, + mapKey: member, + loader: (ref) => + profilePictureNotifier.getProfilePicture(member.member.id), + loadingBuilder: (context) => const CircleAvatar( + radius: 20, child: CircularProgressIndicator()), + dataBuilder: (context, data) => + CircleAvatar(radius: 20, backgroundImage: data.first.image), ), ), const SizedBox(width: 10), From d9ef91e533684868b36a3e9aadf585a7140fd064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Fri, 1 Mar 2024 11:50:09 +0100 Subject: [PATCH 114/123] fix: setKind before editing association from association page --- lib/phonebook/ui/pages/association_page/association_page.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index a106d7d17..3e141d417 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:heroicons/heroicons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:myecl/phonebook/providers/association_kind_provider.dart'; import 'package:myecl/phonebook/providers/association_member_sorted_list_provider.dart'; import 'package:myecl/phonebook/providers/association_picture_provider.dart'; import 'package:myecl/phonebook/providers/association_provider.dart'; @@ -30,6 +31,7 @@ class AssociationPage extends HookConsumerWidget { final associationPictureNotifier = ref.watch(associationPictureProvider.notifier); final isPresident = ref.watch(isAssociationPresidentProvider); + final kindNotifier = ref.watch(associationKindProvider.notifier); return PhonebookTemplate( child: Refresher( @@ -93,6 +95,7 @@ class AssociationPage extends HookConsumerWidget { right: 20, child: GestureDetector( onTap: () { + kindNotifier.setKind(association.kind); QR.to(PhonebookRouter.root + PhonebookRouter.associationDetail + PhonebookRouter.editAssociation); From 2063c480da8a779ca14274615de4c8df18cf2072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Fri, 1 Mar 2024 12:01:00 +0100 Subject: [PATCH 115/123] fix: use SafeArea in template --- lib/phonebook/ui/phonebook.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/phonebook/ui/phonebook.dart b/lib/phonebook/ui/phonebook.dart index 67dd35e9c..23d61ac49 100644 --- a/lib/phonebook/ui/phonebook.dart +++ b/lib/phonebook/ui/phonebook.dart @@ -13,8 +13,8 @@ class PhonebookTemplate extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final kindNotifier = ref.watch(associationKindProvider.notifier); - return Scaffold( - body: Column( + return SafeArea( + child: Column( children: [ TopBar( title: PhonebookTextConstants.phonebook, From 64cd53f8960c944426362488bcdba029fd8825a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Fri, 1 Mar 2024 12:12:14 +0100 Subject: [PATCH 116/123] fix: dataKey initialisation --- lib/phonebook/ui/components/kinds_bar.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/phonebook/ui/components/kinds_bar.dart b/lib/phonebook/ui/components/kinds_bar.dart index 1a1d70dcd..8d1a34ff7 100644 --- a/lib/phonebook/ui/components/kinds_bar.dart +++ b/lib/phonebook/ui/components/kinds_bar.dart @@ -39,7 +39,7 @@ class KindsBar extends HookConsumerWidget { final item = kinds.kinds[index]; final selected = kind == item; return ItemChip( - key: selected ? dataKey : null, + key: selected || (kind == "" && index == 0) ? dataKey : null, onTap: () { kindNotifier.setKind(!selected ? item : ""); }, From d2a6dabbfa7b2cf9f6c35b1a9ee562b3b4b16147 Mon Sep 17 00:00:00 2001 From: Rotheem <114694873+Rotheem@users.noreply.github.com> Date: Tue, 12 Mar 2024 09:47:45 +0100 Subject: [PATCH 117/123] FIX : Update constants --- lib/phonebook/tools/constants.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/phonebook/tools/constants.dart b/lib/phonebook/tools/constants.dart index 0bfce799d..803b60a93 100644 --- a/lib/phonebook/tools/constants.dart +++ b/lib/phonebook/tools/constants.dart @@ -12,7 +12,7 @@ class PhonebookTextConstants { static const String admin = "Admin"; static const String adminPage = "Page Administrateur"; static const String all = "Toutes"; - static const String apparentName = "Nom public du rôle:"; + static const String apparentName = "Nom public du rôle :"; static const String association = "Association :"; static const String associationDetail = "Détail de l'association :"; static const String associationKind = "Type d'association :"; From bf3777b6c5dafeb631a273722d6797dea6645692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Thu, 14 Mar 2024 09:32:36 +0100 Subject: [PATCH 118/123] fix: correct animation behavior --- lib/phonebook/ui/components/kinds_bar.dart | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/phonebook/ui/components/kinds_bar.dart b/lib/phonebook/ui/components/kinds_bar.dart index 8d1a34ff7..3f8f48fe4 100644 --- a/lib/phonebook/ui/components/kinds_bar.dart +++ b/lib/phonebook/ui/components/kinds_bar.dart @@ -16,13 +16,15 @@ class KindsBar extends HookConsumerWidget { final associationKinds = ref.watch(associationKindsProvider); useEffect( () { - Future( - () => Scrollable.ensureVisible( - dataKey.currentContext!, - duration: const Duration(milliseconds: 500), - alignment: 0.5, - ), - ); + Future(() { + if (kind != "") { + Scrollable.ensureVisible( + dataKey.currentContext!, + duration: const Duration(milliseconds: 500), + alignment: 0.5, + ); + } + }); return; }, [dataKey], @@ -39,7 +41,7 @@ class KindsBar extends HookConsumerWidget { final item = kinds.kinds[index]; final selected = kind == item; return ItemChip( - key: selected || (kind == "" && index == 0) ? dataKey : null, + key: selected ? dataKey : null, onTap: () { kindNotifier.setKind(!selected ? item : ""); }, From a2aef179b31c81a17f907e0363b6f79da6f4666e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Thu, 14 Mar 2024 10:14:35 +0100 Subject: [PATCH 119/123] fix: rebase to new map notifier --- ...sociation_member_sorted_list_provider.dart | 14 ++-- .../associations_pictures_provider.dart | 2 +- .../providers/member_pictures_provider.dart | 2 +- .../providers/profile_pictures_provider.dart | 2 +- .../providers/roles_tags_provider.dart | 22 ++----- .../member_editable_card.dart | 4 +- .../membership_editor_page.dart | 66 +++++++++---------- 7 files changed, 48 insertions(+), 64 deletions(-) diff --git a/lib/phonebook/providers/association_member_sorted_list_provider.dart b/lib/phonebook/providers/association_member_sorted_list_provider.dart index 497bd9bfe..ca7e10fd5 100644 --- a/lib/phonebook/providers/association_member_sorted_list_provider.dart +++ b/lib/phonebook/providers/association_member_sorted_list_provider.dart @@ -12,13 +12,11 @@ final associationMemberSortedListProvider = final roleTagsProvider = ref.watch(rolesTagsProvider); return memberListProvider.maybeWhen( data: (members) { - return roleTagsProvider.maybeWhen( - data: (roleTags) => sortedMembers( - members, - association.id, - roleTags.keys.toList(), - ), - orElse: () => members); + return sortedMembers( + members, + association.id, + roleTagsProvider.keys.toList(), + ); }, - orElse: () => []); + orElse: () => List.empty()); }); diff --git a/lib/phonebook/providers/associations_pictures_provider.dart b/lib/phonebook/providers/associations_pictures_provider.dart index b45ceb329..c716d04ef 100644 --- a/lib/phonebook/providers/associations_pictures_provider.dart +++ b/lib/phonebook/providers/associations_pictures_provider.dart @@ -11,7 +11,7 @@ class AssociationPictureNotifier extends MapNotifier { final associationPicturesProvider = StateNotifierProvider< AssociationPictureNotifier, - AsyncValue>?>>>((ref) { + Map>?>>((ref) { AssociationPictureNotifier associationPictureNotifier = AssociationPictureNotifier(); tokenExpireWrapperAuth(ref, () async { diff --git a/lib/phonebook/providers/member_pictures_provider.dart b/lib/phonebook/providers/member_pictures_provider.dart index c2d10683e..1af50cf92 100644 --- a/lib/phonebook/providers/member_pictures_provider.dart +++ b/lib/phonebook/providers/member_pictures_provider.dart @@ -10,7 +10,7 @@ class MemberPicturesNotifier extends MapNotifier { } final memberPicturesProvider = StateNotifierProvider>?>>>((ref) { + Map>?>>((ref) { MemberPicturesNotifier memberPicturesNotifier = MemberPicturesNotifier(); tokenExpireWrapperAuth(ref, () async { ref.watch(associationMemberListProvider).maybeWhen(data: (member) { diff --git a/lib/phonebook/providers/profile_pictures_provider.dart b/lib/phonebook/providers/profile_pictures_provider.dart index fbc52d23a..9a9e80d1d 100644 --- a/lib/phonebook/providers/profile_pictures_provider.dart +++ b/lib/phonebook/providers/profile_pictures_provider.dart @@ -10,7 +10,7 @@ class ProfilePictureNotifier extends MapNotifier { } final profilePicturesProvider = StateNotifierProvider>?>>>((ref) { + Map>?>>((ref) { ProfilePictureNotifier profilePictureNotifier = ProfilePictureNotifier(); tokenExpireWrapperAuth(ref, () async { ref.watch(associationMemberListProvider).maybeWhen(data: (profile) { diff --git a/lib/phonebook/providers/roles_tags_provider.dart b/lib/phonebook/providers/roles_tags_provider.dart index 330011a19..8dd4ede79 100644 --- a/lib/phonebook/providers/roles_tags_provider.dart +++ b/lib/phonebook/providers/roles_tags_provider.dart @@ -21,29 +21,21 @@ class RolesTagsNotifier extends MapNotifier { } void resetChecked() { - state.whenData((d) { - for (int i = 0; i < d.length; i++) { - d[d.keys.toList()[i]] = const AsyncData([false]); - } - state = AsyncValue.data(d); - }); + state.forEach((key, value) => state[key] = const AsyncData([false])); + state = Map.of(state); } void loadRoleTagsFromMember(CompleteMember member, Association association) { List roleTags = member.getRolesTags(association.id); - state.maybeWhen( - data: (d) { - for (int i = 0; i < roleTags.length; i++) { - d[roleTags[i]] = const AsyncData([true]); - } - state = AsyncValue.data(d); - }, - orElse: () {}); + for (var value in roleTags) { + state[value] = const AsyncData([true]); + } + state = Map.of(state); } } final rolesTagsProvider = StateNotifierProvider>?>>>((ref) { + Map>?>>((ref) { final token = ref.watch(tokenProvider); RolesTagsNotifier notifier = RolesTagsNotifier(token: token); tokenExpireWrapperAuth(ref, () async { diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index b552113a8..18b0b6de7 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -37,7 +37,7 @@ class MemberEditableCard extends HookConsumerWidget { displayToast(context, type, msg); } - final memberPictures = ref.watch(memberPicturesProvider); + final memberPictures = ref.watch(memberPicturesProvider.select((value) => value[member])); final memberPicturesNotifier = ref.watch(memberPicturesProvider.notifier); Membership assoMembership = member.memberships.firstWhere( @@ -70,7 +70,7 @@ class MemberEditableCard extends HookConsumerWidget { ], ), child: AutoLoaderChild( - value: memberPictures, + group: memberPictures, notifier: memberPicturesNotifier, mapKey: member, loader: (ref) => diff --git a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart index 156d4812f..3171ddd53 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/membership_editor_page.dart @@ -14,7 +14,6 @@ import 'package:myecl/phonebook/ui/phonebook.dart'; import 'package:myecl/tools/constants.dart'; import 'package:myecl/tools/functions.dart'; import 'package:myecl/tools/token_expire_wrapper.dart'; -import 'package:myecl/tools/ui/builders/async_child.dart'; import 'package:myecl/tools/ui/builders/waiting_button.dart'; import 'package:myecl/tools/ui/layouts/add_edit_button_layout.dart'; import 'package:myecl/tools/ui/widgets/align_left_text.dart'; @@ -100,42 +99,37 @@ class MembershipEditorPage extends HookConsumerWidget { ), SizedBox( width: min(MediaQuery.of(context).size.width, 300), - child: AsyncChild( - value: rolesTagList, - builder: (context, rolesTags) => Column( - children: [ - ...rolesTags.keys.map( - (tagKey) => Row( - children: [ - Text(tagKey), - const Spacer(), - Checkbox( - value: rolesTags[tagKey]!.maybeWhen( - data: (rolesTag) => rolesTag[0], - orElse: () => false, - ), - fillColor: - MaterialStateProperty.all(Colors.black), - onChanged: (value) { - rolesTags[tagKey] = AsyncData([value!]); - memberRoleTagsNotifier - .setRoleTagsWithFilter(rolesTags); - rolesTagsNotifier.setTData( - tagKey, AsyncData([value])); - if (value && - apparentNameController.text == "") { - apparentNameController.text = tagKey; - } else if (!value && - apparentNameController.text == tagKey) { - apparentNameController.text = ""; - } - }, + child: Column( + children: [ + ...rolesTagList.keys.map( + (tagKey) => Row( + children: [ + Text(tagKey), + const Spacer(), + Checkbox( + value: rolesTagList[tagKey]!.maybeWhen( + data: (rolesTag) => rolesTag[0], + orElse: () => false, ), - ], - ), - ) - ], - ), + fillColor: MaterialStateProperty.all(Colors.black), + onChanged: (value) { + rolesTagList[tagKey] = AsyncData([value!]); + memberRoleTagsNotifier + .setRoleTagsWithFilter(rolesTagList); + rolesTagsNotifier.setTData( + tagKey, AsyncData([value])); + if (value && apparentNameController.text == "") { + apparentNameController.text = tagKey; + } else if (!value && + apparentNameController.text == tagKey) { + apparentNameController.text = ""; + } + }, + ), + ], + ), + ) + ], ), ), const SizedBox(height: 30), From eed70a41031cb6919b3d0cbd80c9fc2626585090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Thu, 14 Mar 2024 10:21:41 +0100 Subject: [PATCH 120/123] format --- .../ui/pages/association_editor_page/member_editable_card.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart index 18b0b6de7..de1c49c1a 100644 --- a/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart +++ b/lib/phonebook/ui/pages/association_editor_page/member_editable_card.dart @@ -37,7 +37,8 @@ class MemberEditableCard extends HookConsumerWidget { displayToast(context, type, msg); } - final memberPictures = ref.watch(memberPicturesProvider.select((value) => value[member])); + final memberPictures = + ref.watch(memberPicturesProvider.select((value) => value[member])); final memberPicturesNotifier = ref.watch(memberPicturesProvider.notifier); Membership assoMembership = member.memberships.firstWhere( From 4dcd10fa1fd13c5ad349e6c5f0a47f5ff4a8dc32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Sat, 16 Mar 2024 01:38:01 +0100 Subject: [PATCH 121/123] add shadow --- .../membership_editor_page/search_result.dart | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart index 4c19fcaea..89fba94bd 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart @@ -21,22 +21,34 @@ class SearchResult extends HookConsumerWidget { .map((user) => GestureDetector( child: Padding( padding: const EdgeInsets.all(8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - width: 20, + child: Container( + decoration: const BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colors.black, + offset: Offset(2, 2), + blurRadius: 10, + spreadRadius: 2, ), - Expanded( - child: Text( - user.getName(), - style: const TextStyle( - fontSize: 13, + ], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + width: 20, + ), + Expanded( + child: Text( + user.getName(), + style: const TextStyle( + fontSize: 13, + ), + overflow: TextOverflow.ellipsis, ), - overflow: TextOverflow.ellipsis, ), - ), - ]), + ]), + ), ), onTap: () { memberNotifier.setMember(Member.fromUser(user)); From 78b5d27e4bf9702fe01f42055815c30b0bfadb2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Sat, 16 Mar 2024 02:23:19 +0100 Subject: [PATCH 122/123] add shadow to search bar --- .../membership_editor_page/search_result.dart | 44 +++++++++++-------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart index 89fba94bd..c69ed066c 100644 --- a/lib/phonebook/ui/pages/membership_editor_page/search_result.dart +++ b/lib/phonebook/ui/pages/membership_editor_page/search_result.dart @@ -20,34 +20,40 @@ class SearchResult extends HookConsumerWidget { children: usersData .map((user) => GestureDetector( child: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.symmetric(vertical: 4.0), child: Container( - decoration: const BoxDecoration( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: Colors.white, boxShadow: [ BoxShadow( - color: Colors.black, - offset: Offset(2, 2), - blurRadius: 10, + color: Colors.black.withOpacity(0.1), + offset: const Offset(0, 1), + blurRadius: 4, spreadRadius: 2, ), ], ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - width: 20, - ), - Expanded( - child: Text( - user.getName(), - style: const TextStyle( - fontSize: 13, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 14), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Container( + width: 20, + ), + Expanded( + child: Text( + user.getName(), + style: const TextStyle( + fontSize: 13, + ), + overflow: TextOverflow.ellipsis, ), - overflow: TextOverflow.ellipsis, ), - ), - ]), + ]), + ), ), ), onTap: () { From d08f9ac3529bc892ec5967b18b87b68ca4bbab24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sha=C3=AEhh?= Date: Sat, 16 Mar 2024 07:44:08 +0100 Subject: [PATCH 123/123] fix: add association refresh --- .../pages/association_editor_page/association_editor_page.dart | 1 + lib/phonebook/ui/pages/association_page/association_page.dart | 2 ++ 2 files changed, 3 insertions(+) diff --git a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart index 18c7f10a8..c78c50680 100644 --- a/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart +++ b/lib/phonebook/ui/pages/association_editor_page/association_editor_page.dart @@ -57,6 +57,7 @@ class AssociationEditorPage extends HookConsumerWidget { return PhonebookTemplate( child: Refresher( onRefresh: () async { + await associationNotifier.loadAssociation(association.id); await associationMemberListNotifier.loadMembers( association.id, association.mandateYear.toString(), diff --git a/lib/phonebook/ui/pages/association_page/association_page.dart b/lib/phonebook/ui/pages/association_page/association_page.dart index 3e141d417..a7cb37415 100644 --- a/lib/phonebook/ui/pages/association_page/association_page.dart +++ b/lib/phonebook/ui/pages/association_page/association_page.dart @@ -23,6 +23,7 @@ class AssociationPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final association = ref.watch(associationProvider); + final associationNotifier = ref.watch(asyncAssociationProvider.notifier); final associationMemberList = ref.watch(associationMemberListProvider); final associationMemberSortedList = ref.watch(associationMemberSortedListProvider); @@ -36,6 +37,7 @@ class AssociationPage extends HookConsumerWidget { return PhonebookTemplate( child: Refresher( onRefresh: () async { + await associationNotifier.loadAssociation(association.id); await associationMemberListNotifier.loadMembers( association.id, association.mandateYear.toString(),