diff --git a/Sources/justMUSIC/lib/components/profil_picture_component.dart b/Sources/justMUSIC/lib/components/profil_picture_component.dart index 48b734a..01f8b3f 100644 --- a/Sources/justMUSIC/lib/components/profil_picture_component.dart +++ b/Sources/justMUSIC/lib/components/profil_picture_component.dart @@ -24,7 +24,7 @@ class ProfilPictureComponent extends StatelessWidget { // Image radius child: FadeInImage.assetNetwork( image: user.pp, - fit: BoxFit.cover, + fit: BoxFit.fill, fadeInDuration: const Duration(milliseconds: 100), placeholder: "assets/images/loadingPlaceholder.gif", ), diff --git a/Sources/justMUSIC/lib/components/top_nav_bar_component.dart b/Sources/justMUSIC/lib/components/top_nav_bar_component.dart index 84a5b28..6d26dd1 100644 --- a/Sources/justMUSIC/lib/components/top_nav_bar_component.dart +++ b/Sources/justMUSIC/lib/components/top_nav_bar_component.dart @@ -264,6 +264,7 @@ class _TopNavBarComponentState extends State with TickerProv child: ClipOval( child: SizedBox( width: 30, + height: 30, // Image radius child: FadeInImage.assetNetwork( image: MyApp.userViewModel.userCurrent.pp, diff --git a/Sources/justMUSIC/lib/screens/detail_post_screen.dart b/Sources/justMUSIC/lib/screens/detail_post_screen.dart index 8cd6698..47b6f8a 100644 --- a/Sources/justMUSIC/lib/screens/detail_post_screen.dart +++ b/Sources/justMUSIC/lib/screens/detail_post_screen.dart @@ -435,9 +435,13 @@ class _DetailPostScreenState extends State { ClipOval( child: SizedBox.fromSize( // Rayon de l'image - child: Image.network( - MyApp.userViewModel.userCurrent.pp, + child: FadeInImage.assetNetwork( + image: MyApp.userViewModel.userCurrent.pp, width: 45, + height: 45, + fit: BoxFit.cover, + fadeInDuration: const Duration(milliseconds: 100), + placeholder: "assets/images/loadingPlaceholder.gif", ), ), ), diff --git a/Sources/justMUSIC/lib/screens/profile_screen.dart b/Sources/justMUSIC/lib/screens/profile_screen.dart index a40fd0a..1a5fafe 100644 --- a/Sources/justMUSIC/lib/screens/profile_screen.dart +++ b/Sources/justMUSIC/lib/screens/profile_screen.dart @@ -31,126 +31,135 @@ class _ProfileScreenState extends State { } return Scaffold( - appBar: PreferredSize( - preferredSize: Size(double.infinity, 58), - child: Container( - height: double.infinity, - color: bgAppBar, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: defaultPadding), - child: Stack( - alignment: Alignment.centerLeft, - children: [ - GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () { - Navigator.pop(context, true); - }, - child: Container( - padding: EdgeInsets.symmetric(horizontal: 10), - height: 30, - width: 30, - child: Image( - image: AssetImage("assets/images/return_icon.png"), - height: 8, - ), - )), - Align( - child: Text( - "Profile", - style: GoogleFonts.plusJakartaSans(color: Colors.white, fontSize: 14, fontWeight: FontWeight.bold), - ), - ) - ], + appBar: PreferredSize( + preferredSize: Size(double.infinity, 58), + child: Container( + height: double.infinity, + color: bgAppBar, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: defaultPadding), + child: Stack( + alignment: Alignment.centerLeft, + children: [ + GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + Navigator.pop(context, true); + }, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10), + height: 30, + width: 30, + child: Image( + image: AssetImage("assets/images/return_icon.png"), + height: 8, + ), + )), + Align( + child: Text( + "Profile", + style: + GoogleFonts.plusJakartaSans(color: Colors.white, fontSize: 14, fontWeight: FontWeight.bold), + ), + ) + ], + ), ), ), ), - ), - body: Container( - width: double.infinity, - height: double.infinity, - color: bgColor, - child: SingleChildScrollView( - physics: const BouncingScrollPhysics(decelerationRate: ScrollDecelerationRate.fast), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: settingPadding), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only(top: 68.h, bottom: 40), - child: ProfileComponent(user: MyApp.userViewModel.userCurrent), - ), - Padding( - padding: const EdgeInsets.only(bottom: 12, left: defaultPadding), - child: Text( - "Compte", - style: GoogleFonts.plusJakartaSans(color: grayText, fontWeight: FontWeight.w800, fontSize: 16), - ), - ), - ClipRRect( - borderRadius: BorderRadius.circular(8), - child: Column( - children: [ - SettingPartComponent( - icon: JustMusicIcon.profile, - label: 'Compte', - action: _openDetail, - ), - const SettingPartComponent( - icon: JustMusicIcon.history, - label: 'Historiques des capsules', - action: null, + body: Container( + width: double.infinity, + height: double.infinity, + color: bgColor, + child: RefreshIndicator( + displacement: 20, + triggerMode: RefreshIndicatorTriggerMode.onEdge, + onRefresh: _refresh, + child: SingleChildScrollView( + physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: settingPadding), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(top: 68.h, bottom: 40), + child: ProfileComponent(user: MyApp.userViewModel.userCurrent), + ), + Padding( + padding: const EdgeInsets.only(bottom: 12, left: defaultPadding), + child: Text( + "Compte", + style: GoogleFonts.plusJakartaSans(color: grayText, fontWeight: FontWeight.w800, fontSize: 16), ), - const SettingPartComponent( - icon: JustMusicIcon.spotify, - label: 'Lier un compte Spotify', - action: null, + ), + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Column( + children: [ + SettingPartComponent( + icon: JustMusicIcon.profile, + label: 'Compte', + action: _openDetail, + ), + const SettingPartComponent( + icon: JustMusicIcon.history, + label: 'Historiques des capsules', + action: null, + ), + const SettingPartComponent( + icon: JustMusicIcon.spotify, + label: 'Lier un compte Spotify', + action: null, + ), + const SettingPartComponent( + icon: JustMusicIcon.trash, + label: 'Supprimer mon compte', + action: null, + ), + SettingPartComponent( + icon: JustMusicIcon.cross, + label: 'Déconnexion', + important: true, + action: logout, + ), + ], ), - const SettingPartComponent( - icon: JustMusicIcon.trash, - label: 'Supprimer mon compte', - action: null, + ), + Padding( + padding: const EdgeInsets.only(bottom: 12, left: defaultPadding, top: 40), + child: Text( + "Préférences", + style: GoogleFonts.plusJakartaSans(color: grayText, fontWeight: FontWeight.w800, fontSize: 16), ), - SettingPartComponent( - icon: JustMusicIcon.cross, - label: 'Déconnexion', - important: true, - action: logout, + ), + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: const Column( + children: [ + SettingPartComponent( + icon: JustMusicIcon.theme, + label: 'Thême de l\'application', + action: null, + ), + SettingPartComponent( + icon: JustMusicIcon.notification, + label: 'Notifications', + action: null, + ), + ], ), - ], - ), + ) + ], ), - Padding( - padding: const EdgeInsets.only(bottom: 12, left: defaultPadding, top: 40), - child: Text( - "Préférences", - style: GoogleFonts.plusJakartaSans(color: grayText, fontWeight: FontWeight.w800, fontSize: 16), - ), - ), - ClipRRect( - borderRadius: BorderRadius.circular(8), - child: const Column( - children: [ - SettingPartComponent( - icon: JustMusicIcon.theme, - label: 'Thême de l\'application', - action: null, - ), - SettingPartComponent( - icon: JustMusicIcon.notification, - label: 'Notifications', - action: null, - ), - ], - ), - ) - ], + ), ), ), - ), - ), - ); + )); + } + + Future _refresh() async { + setState(() {}); } } diff --git a/Sources/justMUSIC/lib/screens/user_screen.dart b/Sources/justMUSIC/lib/screens/user_screen.dart index c81851d..4ee6494 100644 --- a/Sources/justMUSIC/lib/screens/user_screen.dart +++ b/Sources/justMUSIC/lib/screens/user_screen.dart @@ -1,6 +1,11 @@ +import 'dart:io'; + import 'package:flutter/Material.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'package:image_picker/image_picker.dart'; import '../components/profile_component.dart'; import '../components/recap_component.dart'; @@ -18,6 +23,78 @@ class UserScreen extends StatefulWidget { class _UserScreenState extends State { late bool isClicked; + File? image; + + Future pickImage(ImageSource source) async { + try { + final image = await ImagePicker().pickImage(source: source, imageQuality: 20); + if (image == null) return; + final imageTemp = File(image.path); + await MyApp.userViewModel.updateImage(imageTemp); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + "Votre photo de profile a bien été mise à jour", + style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w400, fontSize: 15.h), + ), + backgroundColor: primaryColor, + closeIconColor: Colors.white, + ), + ); + } on PlatformException catch (e) { + print('Failed to pick image: $e'); + } + } + + void manageImage() { + if (image != null) { + setState(() { + image = null; + }); + } else { + _showActionSheet(context); + } + } + + void _showActionSheet(BuildContext context) { + showCupertinoModalPopup( + context: context, + barrierColor: Colors.black.withOpacity(0.5), + builder: (BuildContext context) => Container( + color: Colors.black, + child: CupertinoActionSheet( + title: Text( + 'Ajouter une photo', + style: GoogleFonts.plusJakartaSans(fontWeight: FontWeight.bold), + ), + actions: [ + CupertinoActionSheetAction( + onPressed: () { + pickImage(ImageSource.gallery); + Navigator.pop(context); + }, + child: const Text('Galerie'), + ), + CupertinoActionSheetAction( + onPressed: () { + pickImage(ImageSource.camera); + Navigator.pop(context); + }, + child: const Text('Prendre un selfie'), + ), + ], + cancelButton: CupertinoActionSheetAction( + isDestructiveAction: true, + onPressed: () { + Navigator.pop(context); + }, + child: const Text('Annuler'), + ), + ), + ), + ); + } + @override Widget build(BuildContext context) { isClicked = MyApp.userViewModel.isFriend(widget.user.id); @@ -71,7 +148,34 @@ class _UserScreenState extends State { children: [ Padding( padding: EdgeInsets.only(top: 68.h, bottom: 40), - child: ProfileComponent(user: widget.user), + child: Stack( + alignment: Alignment.center, + children: [ + ProfileComponent(user: widget.user), + MyApp.userViewModel.userCurrent.id == widget.user.id + ? Padding( + padding: const EdgeInsets.only(left: 70, bottom: 10), + child: GestureDetector( + onTap: () { + _showActionSheet(context); + }, + child: ClipOval( + child: Container( + width: 30, + height: 30, + color: grayColor, + child: Icon( + Icons.edit, + color: Colors.white, + size: 16, + ), + ), + ), + ), + ) + : Container(), + ], + ), ), MyApp.userViewModel.userCurrent.id != widget.user.id ? Align( diff --git a/Sources/justMUSIC/lib/services/UserService.dart b/Sources/justMUSIC/lib/services/UserService.dart index c5753b6..29060ee 100644 --- a/Sources/justMUSIC/lib/services/UserService.dart +++ b/Sources/justMUSIC/lib/services/UserService.dart @@ -1,4 +1,4 @@ - import 'dart:io'; +import 'dart:io'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_storage/firebase_storage.dart'; @@ -6,14 +6,11 @@ import 'package:firebase_storage/firebase_storage.dart'; import '../main.dart'; class UserService { - Future>>> getUsersByIdUnique( - String uniqueId) async { - QuerySnapshot> response = await FirebaseFirestore - .instance + Future>>> getUsersByIdUnique(String uniqueId) async { + QuerySnapshot> response = await FirebaseFirestore.instance .collection("users") .where("unique_id", isGreaterThanOrEqualTo: uniqueId) - .where("unique_id", - isLessThanOrEqualTo: uniqueId + "zzzzzzzzzzzzzzzzzzzzzzzzzzzz") + .where("unique_id", isLessThanOrEqualTo: uniqueId + "zzzzzzzzzzzzzzzzzzzzzzzzzzzz") .limit(20) .get(); var users = response.docs.where((doc) { @@ -25,10 +22,7 @@ class UserService { } updateTokenNotify(String idUser, String token) { - FirebaseFirestore.instance - .collection('users') - .doc(idUser) - .update({'token_notify': token}).then((_) { + FirebaseFirestore.instance.collection('users').doc(idUser).update({'token_notify': token}).then((_) { print("Mise à jour réussie !"); }).catchError((error) { print("Erreur lors de la mise à jour : $error"); @@ -36,8 +30,7 @@ class UserService { } addOrDeleteFriend(String id) async { - var userRef = - MyApp.db.collection("users").doc(MyApp.userViewModel.userCurrent.id); + var userRef = MyApp.db.collection("users").doc(MyApp.userViewModel.userCurrent.id); var actionUserRef = MyApp.db.collection("users").doc(id); if (MyApp.userViewModel.isFriend(id)) { @@ -65,7 +58,7 @@ class UserService { updateImage(File image) async { var id = MyApp.userViewModel.userCurrent.id; - var userRef = await MyApp.db.collection("posts").doc(MyApp.userViewModel.userCurrent.id); + var userRef = await MyApp.db.collection("users").doc(MyApp.userViewModel.userCurrent.id); var imageRef = FirebaseStorage.instance.ref('$id.jpg'); await imageRef.putFile(image); var imageUrl = await imageRef.getDownloadURL(); @@ -82,5 +75,4 @@ class UserService { print("Erreur lors de la mise à jour : $error"); }); } - } diff --git a/Sources/justMUSIC/lib/view_model/UserViewModel.dart b/Sources/justMUSIC/lib/view_model/UserViewModel.dart index 6bc8452..62bd83b 100644 --- a/Sources/justMUSIC/lib/view_model/UserViewModel.dart +++ b/Sources/justMUSIC/lib/view_model/UserViewModel.dart @@ -59,10 +59,7 @@ class UserViewModel { updateUserCurrent() async { try { - final user = await MyApp.db - .collection("users") - .doc(firebase_auth.FirebaseAuth.instance.currentUser?.uid) - .get(); + final user = await MyApp.db.collection("users").doc(firebase_auth.FirebaseAuth.instance.currentUser?.uid).get(); User data = UserMapper.toModel(user); _userCurrent = data; } catch (e) { @@ -85,8 +82,7 @@ class UserViewModel { Future> getUsersByUniqueId(String uniqueId) async { try { - var response = - await _userService.getUsersByIdUnique(uniqueId.toLowerCase()); + var response = await _userService.getUsersByIdUnique(uniqueId.toLowerCase()); var users = response.map((value) { return UserMapper.toModel(value); }).toList(); @@ -120,7 +116,8 @@ class UserViewModel { updateImage(File pp) async { try { await _userService.updateImage(pp); - } catch(e) { + await updateUserCurrent(); + } catch (e) { print(e.toString()); rethrow; } @@ -129,7 +126,7 @@ class UserViewModel { updatePseudo(String pseudo) async { try { await _userService.updatePseudo(pseudo); - } catch(e) { + } catch (e) { print(e.toString()); rethrow; }