diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 2795ffb..7f7c6f9 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -296,6 +296,27 @@ + + + + + + + + + + + + + + + + + + @@ -950,6 +971,9 @@ + + + diff --git a/Sources/justMUSIC/lib/components/little_post_recap_component.dart b/Sources/justMUSIC/lib/components/little_post_recap_component.dart new file mode 100644 index 0000000..2134adc --- /dev/null +++ b/Sources/justMUSIC/lib/components/little_post_recap_component.dart @@ -0,0 +1,52 @@ +import 'package:flutter/Material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +import '../values/constants.dart'; + +class LittleCapsule extends StatelessWidget { + final bool isEmpty; + final DateTime date; + const LittleCapsule({super.key, required this.isEmpty, required this.date}); + + @override + Widget build(BuildContext context) { + if (isEmpty) { + return Flexible( + child: Container( + constraints: BoxConstraints(maxWidth: 45, maxHeight: 45), + decoration: BoxDecoration( + color: searchBarColor, + borderRadius: BorderRadius.circular(5), + border: Border.all(color: Color(0xFF282828), width: 1), + ), + child: const Center( + child: Icon( + Icons.rocket_launch, + color: Color(0xFF464646), + size: 18, + ), + ), + ), + ); + } + return Flexible( + child: Container( + constraints: BoxConstraints(maxWidth: 45, maxHeight: 45), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [bgModal, bgModal.withOpacity(0)], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + stops: [0, 1]), + borderRadius: BorderRadius.circular(5), + ), + child: Center( + child: Text( + date.day.toString(), + style: GoogleFonts.plusJakartaSans(color: Color(0xFF464646), fontWeight: FontWeight.w800, fontSize: 17), + ), + ), + ), + ); + } +} diff --git a/Sources/justMUSIC/lib/components/post_component.dart b/Sources/justMUSIC/lib/components/post_component.dart index 2118eee..7d17d20 100644 --- a/Sources/justMUSIC/lib/components/post_component.dart +++ b/Sources/justMUSIC/lib/components/post_component.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:gradient_borders/box_borders/gradient_box_border.dart'; +import 'package:justmusic/components/profil_picture_component.dart'; import 'package:text_scroll/text_scroll.dart'; import 'package:zoom_tap_animation/zoom_tap_animation.dart'; @@ -50,15 +51,7 @@ class _PostComponentState extends State with TickerProviderStateM Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ - ClipOval( - child: SizedBox.fromSize( - // Image radius - child: Image( - image: NetworkImage(widget.post.user.pp), - width: 40, - ), - ), - ), + ProfilPictureComponent(user: widget.post.user), Expanded( flex: 8, child: Padding( @@ -237,15 +230,7 @@ class _PostComponentState extends State with TickerProviderStateM Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ - ClipOval( - child: SizedBox.fromSize( - // Image radius - child: Image( - image: NetworkImage(widget.post.user.pp), - width: 40, - ), - ), - ), + ProfilPictureComponent(user: widget.post.user), Expanded( flex: 8, child: Padding( diff --git a/Sources/justMUSIC/lib/components/profil_picture_component.dart b/Sources/justMUSIC/lib/components/profil_picture_component.dart new file mode 100644 index 0000000..cd0ad72 --- /dev/null +++ b/Sources/justMUSIC/lib/components/profil_picture_component.dart @@ -0,0 +1,33 @@ +import 'package:flutter/Material.dart'; +import 'package:justmusic/screens/user_screen.dart'; + +import '../config/routes.dart'; +import '../model/User.dart'; + +class ProfilPictureComponent extends StatelessWidget { + final User user; + const ProfilPictureComponent({super.key, required this.user}); + + void _openDetail(BuildContext context) { + print("cc"); + Navigator.of(context).push(routeUser(user)); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + _openDetail(context); + }, + child: ClipOval( + child: SizedBox.fromSize( + // Image radius + child: Image( + image: NetworkImage(user.pp), + width: 40, + ), + ), + ), + ); + } +} diff --git a/Sources/justMUSIC/lib/components/recap_component.dart b/Sources/justMUSIC/lib/components/recap_component.dart new file mode 100644 index 0000000..925734f --- /dev/null +++ b/Sources/justMUSIC/lib/components/recap_component.dart @@ -0,0 +1,111 @@ +import 'package:flutter/Material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +import '../values/constants.dart'; +import 'little_post_recap_component.dart'; +import 'package:intl/intl.dart'; + +class RecapComponent extends StatelessWidget { + const RecapComponent({super.key}); + + @override + Widget build(BuildContext context) { + List weekDays = ['L', 'M', 'M', 'J', 'V', 'S', 'D']; + DateTime currentDate = DateTime.now(); + + return Container( + decoration: BoxDecoration( + color: profileBttnColor, + borderRadius: BorderRadius.circular(10), + border: Border.all(color: grayColor, width: 1)), + height: 120, + clipBehavior: Clip.hardEdge, + child: Column( + children: [ + Expanded( + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10), + decoration: BoxDecoration( + color: postbutton, + borderRadius: BorderRadius.only(topRight: Radius.circular(10), topLeft: Radius.circular(10)), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Flexible( + child: Center( + child: Text( + weekDays[currentDate.subtract(Duration(days: 6)).weekday - 1].substring(0, 1), + style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w800, fontSize: 17), + ), + )), + Flexible( + child: Center( + child: Text( + weekDays[currentDate.subtract(Duration(days: 5)).weekday - 1].substring(0, 1), + style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w800, fontSize: 17), + ), + )), + Flexible( + child: Center( + child: Text( + weekDays[currentDate.subtract(Duration(days: 4)).weekday - 1].substring(0, 1), + style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w800, fontSize: 17), + ), + )), + Flexible( + child: Center( + child: Text( + weekDays[currentDate.subtract(Duration(days: 3)).weekday - 1].substring(0, 1), + style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w800, fontSize: 17), + ), + )), + Flexible( + child: Center( + child: Text( + weekDays[currentDate.subtract(Duration(days: 2)).weekday - 1].substring(0, 1), + style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w800, fontSize: 17), + ), + )), + Flexible( + child: Center( + child: Text( + weekDays[currentDate.subtract(Duration(days: 1)).weekday - 1].substring(0, 1), + style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w800, fontSize: 17), + ), + )), + Flexible( + child: Center( + child: Text( + weekDays[currentDate.subtract(Duration(days: 0)).weekday - 1].substring(0, 1), + style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w800, fontSize: 17), + ), + )), + ], + ), + )), + Padding( + padding: EdgeInsets.all(12), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + LittleCapsule( + isEmpty: false, + date: DateTime.now(), + ), + LittleCapsule(isEmpty: true, date: currentDate.subtract(const Duration(days: 5))), + LittleCapsule(isEmpty: false, date: currentDate.subtract(const Duration(days: 4))), + LittleCapsule(isEmpty: false, date: currentDate.subtract(const Duration(days: 3))), + LittleCapsule(isEmpty: false, date: currentDate.subtract(const Duration(days: 2))), + LittleCapsule(isEmpty: false, date: currentDate.subtract(const Duration(days: 1))), + LittleCapsule(isEmpty: false, date: currentDate.subtract(const Duration(days: 0))), + ], + ), + ) + ], + ), + ); + } +} diff --git a/Sources/justMUSIC/lib/components/top_nav_bar_component.dart b/Sources/justMUSIC/lib/components/top_nav_bar_component.dart index 39deb0d..d258f68 100644 --- a/Sources/justMUSIC/lib/components/top_nav_bar_component.dart +++ b/Sources/justMUSIC/lib/components/top_nav_bar_component.dart @@ -27,8 +27,7 @@ class _TopNavBarComponentState extends State with TickerProv bool isDismissed = true; - final DateTime midnight = DateTime( - DateTime.now().year, DateTime.now().month, DateTime.now().day + 1); + final DateTime midnight = DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day + 1); void actionSurBouton(bool choice) async { widget.callback(choice); @@ -47,8 +46,7 @@ class _TopNavBarComponentState extends State with TickerProv var now = tz.TZDateTime.now(franceTimeZone); // Calculate the midnight time for the next day in France timezone - var midnight = - tz.TZDateTime(franceTimeZone, now.year, now.month, now.day + 1); + var midnight = tz.TZDateTime(franceTimeZone, now.year, now.month, now.day + 1); bool res = await MyApp.postViewModel.getAvailable(); if (res) { @@ -67,8 +65,7 @@ class _TopNavBarComponentState extends State with TickerProv alignment: Alignment.centerLeft, child: Text( "Capsule disponible", - style: - GoogleFonts.plusJakartaSans(color: Colors.grey, fontSize: 15), + style: GoogleFonts.plusJakartaSans(color: Colors.grey, fontSize: 15), ), ), flushbarStyle: FlushbarStyle.FLOATING, @@ -105,8 +102,7 @@ class _TopNavBarComponentState extends State with TickerProv alignment: Alignment.centerLeft, child: CountdownTimer( endTime: midnight.millisecondsSinceEpoch, - textStyle: - GoogleFonts.plusJakartaSans(color: Colors.grey, fontSize: 15), + textStyle: GoogleFonts.plusJakartaSans(color: Colors.grey, fontSize: 15), ), ), flushbarStyle: FlushbarStyle.FLOATING, @@ -153,7 +149,7 @@ class _TopNavBarComponentState extends State with TickerProv flex: 1, child: GestureDetector( behavior: HitTestBehavior.translucent, - onTap: () async { + onTap: () { Navigator.of(context).push(routeAddFriend()); }, child: const Icon( @@ -199,30 +195,23 @@ class _TopNavBarComponentState extends State with TickerProv } }, child: LayoutBuilder( - builder: (BuildContext context, - BoxConstraints constraints) { + builder: (BuildContext context, BoxConstraints constraints) { if (choice) { return Padding( - padding: const EdgeInsets.only( - left: 8, top: 0, right: 8, bottom: 6), + padding: const EdgeInsets.only(left: 8, top: 0, right: 8, bottom: 6), child: AutoSizeText( "Mes amis", style: GoogleFonts.plusJakartaSans( - fontWeight: FontWeight.w500, - fontSize: 16, - color: Colors.white), + fontWeight: FontWeight.w500, fontSize: 16, color: Colors.white), ), ); } else { return Padding( - padding: const EdgeInsets.only( - left: 8, top: 0, right: 8, bottom: 6), + padding: const EdgeInsets.only(left: 8, top: 0, right: 8, bottom: 6), child: AutoSizeText( "Mes amis", style: GoogleFonts.plusJakartaSans( - fontWeight: FontWeight.w300, - fontSize: 16, - color: unactiveFeed), + fontWeight: FontWeight.w300, fontSize: 16, color: unactiveFeed), )); } }, @@ -239,29 +228,22 @@ class _TopNavBarComponentState extends State with TickerProv } }, child: LayoutBuilder( - builder: (BuildContext context, - BoxConstraints constraints) { + builder: (BuildContext context, BoxConstraints constraints) { if (choice) { return Padding( - padding: const EdgeInsets.only( - left: 8, top: 0, right: 8, bottom: 6), + padding: const EdgeInsets.only(left: 8, top: 0, right: 8, bottom: 6), child: AutoSizeText( "Discovery", style: GoogleFonts.plusJakartaSans( - fontWeight: FontWeight.w300, - fontSize: 16, - color: unactiveFeed), + fontWeight: FontWeight.w300, fontSize: 16, color: unactiveFeed), )); } else { return Padding( - padding: const EdgeInsets.only( - left: 8, top: 0, right: 8, bottom: 6), + padding: const EdgeInsets.only(left: 8, top: 0, right: 8, bottom: 6), child: AutoSizeText( "Discovery", style: GoogleFonts.plusJakartaSans( - fontWeight: FontWeight.w500, - fontSize: 16, - color: Colors.white), + fontWeight: FontWeight.w500, fontSize: 16, color: Colors.white), )); } }, diff --git a/Sources/justMUSIC/lib/config/routes.dart b/Sources/justMUSIC/lib/config/routes.dart index 5c6c7a6..1c4ed4b 100644 --- a/Sources/justMUSIC/lib/config/routes.dart +++ b/Sources/justMUSIC/lib/config/routes.dart @@ -2,6 +2,9 @@ import 'package:flutter/Material.dart'; import 'package:justmusic/screens/add_friend_screen.dart'; import 'package:justmusic/screens/feed_screen.dart'; import 'package:justmusic/screens/profile_screen.dart'; +import 'package:justmusic/screens/user_screen.dart'; + +import '../model/User.dart'; Route routeProfile() { return PageRouteBuilder( @@ -50,3 +53,21 @@ Route routeRocket() { }, ); } + +Route routeUser(User user) { + return PageRouteBuilder( + pageBuilder: (context, animation, secondaryAnimation) => UserScreen(user: user), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + const begin = Offset(1.0, 0.0); + const end = Offset.zero; + const curve = Curves.ease; + + var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve)); + + return SlideTransition( + position: animation.drive(tween), + child: child, + ); + }, + ); +} diff --git a/Sources/justMUSIC/lib/main.dart b/Sources/justMUSIC/lib/main.dart index 83fabcd..cfcdb8a 100644 --- a/Sources/justMUSIC/lib/main.dart +++ b/Sources/justMUSIC/lib/main.dart @@ -17,6 +17,7 @@ import 'package:justmusic/screens/launching_rocker_screen.dart'; import 'package:justmusic/screens/post_screen.dart'; import 'package:justmusic/screens/profile_screen.dart'; import 'package:justmusic/screens/registration_screen.dart'; +import 'package:justmusic/screens/user_screen.dart'; import 'package:justmusic/screens/welcome_screen.dart'; import 'package:justmusic/view_model/CommentViewModel.dart'; import 'package:justmusic/view_model/MusicViewModel.dart'; @@ -67,8 +68,7 @@ class _MyAppState extends State { print('User is currently signed out!'); return null; } else { - MyApp.userViewModel.userCurrent = - (await (MyApp.userViewModel.getUser(user.uid)))!; + MyApp.userViewModel.userCurrent = (await (MyApp.userViewModel.getUser(user.uid)))!; userCurrent = Stream.value(MyApp.userViewModel.userCurrent); print('User is signed in!'); } @@ -115,16 +115,14 @@ class _MyAppState extends State { return FutureBuilder( future: MyApp.userViewModel.getUser(snapshot.data!.uid), builder: (context, userSnapshot) { - if (userSnapshot.connectionState == - ConnectionState.waiting) { + if (userSnapshot.connectionState == ConnectionState.waiting) { return LoadingScreen(); } else if (userSnapshot.hasData) { MyApp.userViewModel.userCurrent = userSnapshot.data!; return AnimatedSwitcher( duration: Duration(milliseconds: 1000), transitionBuilder: (child, animation) { - return FadeTransition( - opacity: animation, child: child); + return FadeTransition(opacity: animation, child: child); }, child: FeedScreen(), ); diff --git a/Sources/justMUSIC/lib/screens/user_screen.dart b/Sources/justMUSIC/lib/screens/user_screen.dart new file mode 100644 index 0000000..20e5855 --- /dev/null +++ b/Sources/justMUSIC/lib/screens/user_screen.dart @@ -0,0 +1,155 @@ +import 'package:flutter/Material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:google_fonts/google_fonts.dart'; + +import '../components/profile_component.dart'; +import '../components/recap_component.dart'; +import '../main.dart'; +import '../model/User.dart'; +import '../values/constants.dart'; + +class UserScreen extends StatefulWidget { + final User user; + const UserScreen({super.key, required this.user}); + + @override + State createState() => _UserScreenState(); +} + +class _UserScreenState extends State { + late bool isClicked; + @override + Widget build(BuildContext context) { + isClicked = MyApp.userViewModel.isFriend(widget.user.id); + 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( + widget.user.pseudo, + 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: widget.user), + ), + Align( + alignment: Alignment.topCenter, + child: isClicked + ? SizedBox( + // Définir une largeur minimale pour le bouton "Ajouter" + width: 120, // Réglez cette valeur en fonction de vos besoins + child: Material( + borderRadius: BorderRadius.all(Radius.circular(5)), + color: selectedButton, + child: InkWell( + splashColor: Colors.white.withOpacity(0.3), + onTap: () async { + await MyApp.userViewModel.addOrDeleteFriend(widget.user.id); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + "Vous ne suivez plus ${widget.user.pseudo}", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, fontWeight: FontWeight.w400, fontSize: 20.h), + ), + backgroundColor: Colors.red, + closeIconColor: Colors.white, + ), + ); + setState(() {}); + }, + child: Container( + padding: EdgeInsets.fromLTRB(28, 7, 28, 7), + decoration: BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(7))), + child: Center( + child: Text("Ajouté", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, fontWeight: FontWeight.w600, fontSize: 13)), + ), + ))), + ) + : SizedBox( + // Définir une largeur minimale pour le bouton "Ajouter" + width: 120, // Réglez cette valeur en fonction de vos besoins + child: Material( + borderRadius: BorderRadius.all(Radius.circular(5)), + color: primaryColor, + child: InkWell( + splashColor: Colors.white.withOpacity(0.3), + onTap: () async { + await MyApp.userViewModel.addOrDeleteFriend(widget.user.id); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: primaryColor, + content: Text( + "Vous suivez à present ${widget.user.pseudo}", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, fontWeight: FontWeight.w400, fontSize: 20.h), + ), + ), + ); + setState(() {}); + }, + child: Container( + padding: EdgeInsets.fromLTRB(25, 7, 25, 7), + decoration: BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(7))), + child: Center( + child: Text("Ajouter", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, fontWeight: FontWeight.w600, fontSize: 13)), + ), + )))), + ), + SizedBox( + height: 40, + ), + RecapComponent() + ], + ), + ), + ), + ), + ); + } +}