diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 72fa842..db02f0e 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -37,6 +37,13 @@ + + + + + + @@ -359,6 +366,13 @@ + + + + + + @@ -597,6 +611,13 @@ + + + + + + @@ -639,6 +660,13 @@ + + + + + + @@ -772,6 +800,27 @@ + + + + + + + + + + + + + + + + + + @@ -793,6 +842,13 @@ + + + + + + @@ -808,6 +864,7 @@ + @@ -853,6 +910,7 @@ + @@ -885,12 +943,14 @@ + + @@ -909,9 +969,13 @@ + + + + diff --git a/Sources/justMUSIC/assets/images/add.svg b/Sources/justMUSIC/assets/images/add.svg new file mode 100644 index 0000000..9736b5e --- /dev/null +++ b/Sources/justMUSIC/assets/images/add.svg @@ -0,0 +1,3 @@ + + + diff --git a/Sources/justMUSIC/assets/images/chat.svg b/Sources/justMUSIC/assets/images/chat.svg new file mode 100644 index 0000000..5174563 --- /dev/null +++ b/Sources/justMUSIC/assets/images/chat.svg @@ -0,0 +1,4 @@ + + + + diff --git a/Sources/justMUSIC/assets/images/heart.svg b/Sources/justMUSIC/assets/images/heart.svg new file mode 100644 index 0000000..f673b81 --- /dev/null +++ b/Sources/justMUSIC/assets/images/heart.svg @@ -0,0 +1,3 @@ + + + diff --git a/Sources/justMUSIC/assets/images/report.svg b/Sources/justMUSIC/assets/images/report.svg new file mode 100644 index 0000000..02b113a --- /dev/null +++ b/Sources/justMUSIC/assets/images/report.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Sources/justMUSIC/assets/images/save.svg b/Sources/justMUSIC/assets/images/save.svg new file mode 100644 index 0000000..e9169e8 --- /dev/null +++ b/Sources/justMUSIC/assets/images/save.svg @@ -0,0 +1,4 @@ + + + + diff --git a/Sources/justMUSIC/lib/components/button_play_component.dart b/Sources/justMUSIC/lib/components/button_play_component.dart new file mode 100644 index 0000000..2b252de --- /dev/null +++ b/Sources/justMUSIC/lib/components/button_play_component.dart @@ -0,0 +1,51 @@ +import 'package:flutter/Material.dart'; + +import '../main.dart'; +import '../model/Music.dart'; + +class ButtonPlayComponent extends StatefulWidget { + final Music music; + const ButtonPlayComponent({super.key, required this.music}); + + @override + State createState() => _ButtonPlayComponentState(); +} + +class _ButtonPlayComponentState extends State { + bool isPlaying = false; + + @override + void initState() { + MyApp.audioPlayer.onPlayerComplete.listen((event) { + setState(() { + isPlaying = false; + }); + }); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + child: GestureDetector( + onTap: () { + if (isPlaying) { + widget.music.stopSong(); + setState(() { + isPlaying = !isPlaying; + }); + } else { + widget.music.playSong(); + setState(() { + isPlaying = !isPlaying; + }); + } + }, + child: Icon( + isPlaying ? Icons.pause_circle : Icons.play_circle, + color: Colors.white, + size: 53, + ), + )); + } +} diff --git a/Sources/justMUSIC/lib/components/comment_component.dart b/Sources/justMUSIC/lib/components/comment_component.dart index 641f2f1..2f86d14 100644 --- a/Sources/justMUSIC/lib/components/comment_component.dart +++ b/Sources/justMUSIC/lib/components/comment_component.dart @@ -11,54 +11,56 @@ class CommentComponent extends StatelessWidget { Widget build(BuildContext context) { return Container( width: double.infinity, - decoration: BoxDecoration( - color: bgComment, borderRadius: BorderRadius.circular(10)), + decoration: BoxDecoration(color: bgComment, borderRadius: BorderRadius.circular(20)), padding: EdgeInsets.all(20), - child: Column( + child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - ClipOval( - child: SizedBox.fromSize( - // Image radius - child: Image( - image: AssetImage("assets/images/exemple_profile.png"), - width: 40, - ), - ), - ), - SizedBox( - width: 10, - ), - Text( - "Melina", - style: GoogleFonts.plusJakartaSans( - color: Colors.white, fontWeight: FontWeight.w600), - ), - Padding( - padding: EdgeInsets.only(top: 6, left: 10), - child: Text( - "Il y a 2 min(s)", - style: GoogleFonts.plusJakartaSans( - color: Colors.white.withOpacity(0.6), - fontWeight: FontWeight.w200, - fontSize: 10), - ), + ClipOval( + child: SizedBox.fromSize( + // Image radius + child: Image( + image: AssetImage("assets/images/exemple_profile.png"), + width: 40, ), - ], - ), - SizedBox( - height: 10, - ), - Text( - "J’adore ce son auss je trouve qu’il a vraiment une plume de fou le rap c’est trop bien jknei rhozi ugzeor gzhjkev huz vhzbejlh zouebvfiyzv fi hzejkfb zjf ouzebfjzebihf b zuib fiuzebfihzbejfbzejkbf hzbfiébiu zegiu fzieu iuzy giuzeg iuzg eiu zg ", - style: GoogleFonts.plusJakartaSans( - color: Colors.white.withOpacity(0.4), - fontWeight: FontWeight.w300, - fontSize: 13), + ), ), + Expanded( + child: Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + width: 10, + ), + Text( + "Melina", + style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w600), + ), + Padding( + padding: EdgeInsets.only(top: 6, left: 10), + child: Text( + "Il y a 2 min(s)", + style: GoogleFonts.plusJakartaSans( + color: Colors.white.withOpacity(0.6), fontWeight: FontWeight.w400, fontSize: 10), + ), + ), + ], + ), + SizedBox( + height: 8, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Text( + "J’adore ce son aussi, je trouve qu’il avait vraiment une plume de fou.", + style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w300, fontSize: 11), + ), + ), + ], + ), + ) ], ), ); diff --git a/Sources/justMUSIC/lib/components/play_button_component.dart b/Sources/justMUSIC/lib/components/play_button_component.dart index 237881d..9f4b21d 100644 --- a/Sources/justMUSIC/lib/components/play_button_component.dart +++ b/Sources/justMUSIC/lib/components/play_button_component.dart @@ -1,4 +1,3 @@ -import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/Material.dart'; import 'package:flutter_animated_play_button/flutter_animated_play_button.dart'; import 'package:ionicons/ionicons.dart'; @@ -12,11 +11,7 @@ class PlayButtonComponent extends StatefulWidget { final int index; final bool playing; const PlayButtonComponent( - {Key? key, - required this.music, - required this.callback, - required this.playing, - required this.index}) + {Key? key, required this.music, required this.callback, required this.playing, required this.index}) : super(key: key); @override @@ -24,8 +19,6 @@ class PlayButtonComponent extends StatefulWidget { } class _PlayButtonComponentState extends State { - final player = AudioPlayer(); - @override void initState() { MyApp.audioPlayer.onPlayerComplete.listen((event) { diff --git a/Sources/justMUSIC/lib/components/post_component.dart b/Sources/justMUSIC/lib/components/post_component.dart index 4d1de01..c6c0c13 100644 --- a/Sources/justMUSIC/lib/components/post_component.dart +++ b/Sources/justMUSIC/lib/components/post_component.dart @@ -259,7 +259,7 @@ class _PostComponentState extends State with TickerProviderStateM ), widget.post.location.item2 != null ? Text( - "${widget.post.location?.item1}, ${widget.post.location?.item2}", + "${widget.post.location.item1}, ${widget.post.location.item2}", style: GoogleFonts.plusJakartaSans( color: Colors.white.withOpacity(0.4), fontWeight: FontWeight.w300, @@ -284,7 +284,7 @@ class _PostComponentState extends State with TickerProviderStateM color: Colors.white.withOpacity(0.4), fontWeight: FontWeight.w300, fontSize: 13), ) : Text( - "${widget.post.date.day}/${widget.post.date.month}/${widget.post.date.year}-${widget.post.date.hour}:${widget.post.date.minute}", + "hier, ${widget.post.date.hour}:${widget.post.date.minute}", style: GoogleFonts.plusJakartaSans( color: Colors.white.withOpacity(0.4), fontWeight: FontWeight.w300, fontSize: 13), ), diff --git a/Sources/justMUSIC/lib/screens/detail_post_screen.dart b/Sources/justMUSIC/lib/screens/detail_post_screen.dart new file mode 100644 index 0000000..700e061 --- /dev/null +++ b/Sources/justMUSIC/lib/screens/detail_post_screen.dart @@ -0,0 +1,532 @@ +import 'package:flutter/Material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:google_fonts/google_fonts.dart'; + +import 'package:text_scroll/text_scroll.dart'; +import 'package:zoom_tap_animation/zoom_tap_animation.dart'; + +import '../components/button_play_component.dart'; +import '../components/comment_component.dart'; + +import '../main.dart'; +import '../model/Post.dart'; +import '../values/constants.dart'; + +class DetailPostScreen extends StatefulWidget { + final Post post; + const DetailPostScreen({super.key, required this.post}); + + @override + State createState() => _DetailPostScreenState(); +} + +class _DetailPostScreenState extends State { + Future resetFullScreen() async { + await SystemChannels.platform.invokeMethod( + 'SystemChrome.restoreSystemUIOverlays', + ); + } + + bool choice = false; + DateTime today = DateTime.now(); + + void switchChoice() { + setState(() { + choice = !choice; + }); + } + + @override + void dispose() { + MyApp.audioPlayer.release(); + super.dispose(); + } + + @override + void initState() { + print("post: ${widget.post.date.toString()}"); + print("ajrd: ${DateTime.now().toString()}"); + super.initState(); + } + + /*void test() { + return Column( + children: [ + Align( + child: Container( + width: 60, + height: 5, + decoration: BoxDecoration(color: Colors.white.withOpacity(0.3), borderRadius: BorderRadius.circular(20))), + ), + const SizedBox( + height: 20, + ), + Expanded( + child: ClipRRect( + borderRadius: BorderRadius.only(topRight: Radius.circular(15), topLeft: Radius.circular(15)), + child: Padding( + padding: EdgeInsets.only(left: defaultPadding, right: defaultPadding), + child: SingleChildScrollView( + physics: BouncingScrollPhysics(decelerationRate: ScrollDecelerationRate.fast), + child: Wrap( + // to apply margin in the main axis of the wrap + runSpacing: 10, + children: [ + Container(height: 5), + Align( + child: RichText( + text: TextSpan( + text: "3", + style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w600), + children: [ + TextSpan( + text: " commentaires", + style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w300), + ) + ])), + ), + SizedBox(height: 20), + CommentComponent(), + CommentComponent(), + CommentComponent(), + Container(height: 10), + ], + ), + ), + ), + ), + ), + Padding( + padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + child: Container( + height: 70, + width: double.infinity, + decoration: + BoxDecoration(border: Border(top: BorderSide(color: grayColor, width: 2)), color: textFieldMessage), + child: Center( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Row( + children: [ + ClipOval( + child: SizedBox.fromSize( + // Image radius + child: const Image( + image: AssetImage("assets/images/exemple_profile.png"), + width: 45, + ), + ), + ), + SizedBox( + width: 10, + ), + Expanded( + child: TextField( + keyboardAppearance: Brightness.dark, + cursorColor: primaryColor, + keyboardType: TextInputType.emailAddress, + style: GoogleFonts.plusJakartaSans(color: Colors.white), + decoration: InputDecoration( + suffixIcon: Icon( + Icons.send, + color: grayText, + size: 20, + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(width: 1, color: grayText), + borderRadius: BorderRadius.all(Radius.circular(100))), + contentPadding: EdgeInsets.only(top: 0, bottom: 0, left: 20, right: 20), + fillColor: bgModal, + filled: true, + focusColor: Color.fromRGBO(255, 255, 255, 0.30), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 1, color: grayText), + borderRadius: BorderRadius.all(Radius.circular(100))), + hintText: 'Ajoutez une réponse...', + hintStyle: GoogleFonts.plusJakartaSans(color: grayText)), + ), + ) + ], + ), + ), + )), + ), + ], + ); + }*/ + final ScrollController _scrollController = ScrollController(); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + FocusScopeNode currentFocus = FocusScope.of(context); + if (!currentFocus.hasPrimaryFocus) { + currentFocus.unfocus(); + resetFullScreen(); + } + }, + child: Container( + height: 760.h, + child: Column( + children: [ + Expanded( + child: Stack( + children: [ + ScrollConfiguration( + behavior: MyBehavior(), + child: SingleChildScrollView( + controller: _scrollController, + physics: AlwaysScrollableScrollPhysics(), + child: Stack( + clipBehavior: Clip.hardEdge, + children: [ + Align( + alignment: Alignment.topCenter, + child: Container( + height: 400, + width: double.infinity, + child: FadeInImage.assetNetwork( + placeholder: "assets/images/loadingPlaceholder.gif", + image: choice ? widget.post.selfie! : widget.post.music.cover!, + width: double.infinity, + fit: BoxFit.cover, + ), + )), + Column( + children: [ + Container( + height: 200, + margin: EdgeInsets.only(top: 230), + width: double.infinity, + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [Colors.transparent, bgModal], + stops: [0, 0.8]), + ), + child: Padding( + padding: const EdgeInsets.fromLTRB(20, 0, 20, 10), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Padding( + padding: const EdgeInsets.only(right: 10), + child: choice + ? Padding( + padding: const EdgeInsets.all(4), + child: ClipOval( + child: SizedBox.fromSize( + // Image radius + child: Image( + image: NetworkImage(widget.post.user.pp), + width: 45, + ), + ), + ), + ) + : widget.post.music.previewUrl != null + ? ButtonPlayComponent(music: widget.post.music) + : Container(), + ), + Flexible( + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Flexible( + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: ScrollConfiguration( + behavior: ScrollBehavior().copyWith(scrollbars: false), + child: TextScroll( + choice + ? widget.post.user.pseudo + : widget.post.music.title!, + style: GoogleFonts.plusJakartaSans( + height: 1, + color: Colors.white, + fontWeight: FontWeight.w800, + fontSize: 22), + mode: TextScrollMode.endless, + pauseBetween: Duration(milliseconds: 500), + velocity: Velocity(pixelsPerSecond: Offset(20, 0)), + ))), + Padding( + padding: const EdgeInsets.only(left: 20.0), + child: choice + ? DateTime(today.year, today.month, today.day) + .isAtSameMomentAs(DateTime(widget.post.date.year, + widget.post.date.month, widget.post.date.day)) + ? Text( + "Aujourd'hui, ${widget.post.date.hour}:${widget.post.date.minute}", + style: GoogleFonts.plusJakartaSans( + height: 1, + color: Colors.white, + fontWeight: FontWeight.w900, + fontSize: 18), + ) + : Text( + "hier, ${widget.post.date.hour}:${widget.post.date.minute}", + style: GoogleFonts.plusJakartaSans( + height: 1, + color: Colors.white, + fontWeight: FontWeight.w900, + fontSize: 18), + ) + : Text( + widget.post.music.date.toString(), + style: GoogleFonts.plusJakartaSans( + height: 1, + color: Colors.white, + fontWeight: FontWeight.w900, + fontSize: 18), + ), + ) + ], + ), + ), + choice + ? widget.post.location.item2 != null + ? Text( + "${widget.post.location.item1}, ${widget.post.location.item2}", + style: GoogleFonts.plusJakartaSans( + color: Colors.white.withOpacity(0.5), + fontWeight: FontWeight.w400, + fontSize: 15), + ) + : Text( + "", + style: GoogleFonts.plusJakartaSans( + color: Colors.white.withOpacity(0.4), + fontWeight: FontWeight.w300, + fontSize: 13), + ) + : ScrollConfiguration( + behavior: ScrollBehavior().copyWith(scrollbars: false), + child: TextScroll(widget.post.music.artists.first.name!, + style: GoogleFonts.plusJakartaSans( + height: 1, + color: Colors.white, + fontWeight: FontWeight.w500, + fontSize: 17), + mode: TextScrollMode.endless, + pauseBetween: Duration(milliseconds: 500), + velocity: Velocity(pixelsPerSecond: Offset(20, 0))), + ) + ], + ), + ), + ], + ), + ), + ), + widget.post.description != null + ? Align( + alignment: Alignment.bottomLeft, + child: Padding( + padding: const EdgeInsets.fromLTRB(50, 35, 50, 35), + child: Text( + widget.post.description!, + textAlign: TextAlign.left, + style: GoogleFonts.plusJakartaSans( + height: 1, + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 14), + ), + ), + ) + : Container( + height: 30, + ), + Container( + width: double.infinity, + decoration: const BoxDecoration( + color: bgAppBar, + border: Border( + top: BorderSide( + color: Color(0xFF262626), // Couleur de la bordure + width: 1.0, // Épaisseur de la bordure + ), + ), + ), + child: Column( + children: [ + Padding( + padding: EdgeInsets.symmetric(vertical: 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + SvgPicture.asset("assets/images/heart.svg", semanticsLabel: 'Like Logo'), + SvgPicture.asset("assets/images/chat.svg", semanticsLabel: 'Chat Logo'), + SvgPicture.asset("assets/images/add.svg", + semanticsLabel: 'Add playlist Logo'), + SvgPicture.asset("assets/images/save.svg", semanticsLabel: 'Save Logo'), + SvgPicture.asset("assets/images/report.svg", + semanticsLabel: 'Report Logo'), + ], + ), + ), + Padding( + padding: const EdgeInsets.all(15.0), + child: RichText( + text: TextSpan( + text: "3", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, fontWeight: FontWeight.w800), + children: [ + TextSpan( + text: " commentaires", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, fontWeight: FontWeight.w400), + ) + ])), + ), + Padding( + padding: EdgeInsets.fromLTRB(20, 0, 20, 20), + child: Wrap( + runSpacing: 13, + children: [ + CommentComponent(), + CommentComponent(), + CommentComponent(), + ], + ), + ) + ], + ), + ), + ], + ), + widget.post.selfie != null + ? Align( + alignment: Alignment.topRight, + child: ZoomTapAnimation( + onTap: () { + if (widget.post.selfie != null) { + switchChoice(); + } + }, + enableLongTapRepeatEvent: false, + longTapRepeatDuration: const Duration(milliseconds: 100), + begin: 1.0, + end: 0.96, + beginDuration: const Duration(milliseconds: 70), + endDuration: const Duration(milliseconds: 100), + beginCurve: Curves.decelerate, + endCurve: Curves.easeInOutSine, + child: Container( + margin: EdgeInsets.all(20), + width: 120, + height: 120, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + border: Border.all(width: 4, color: Colors.white)), + child: ClipRRect( + borderRadius: BorderRadius.circular(15), + // implement image + child: Image( + image: NetworkImage( + choice ? widget.post.music.cover! : widget.post.selfie!), + fit: BoxFit.cover, + )), + ), + ), + ) + : Container() + ], + ), + )), + Align( + alignment: Alignment.topCenter, + child: Container( + height: 50, + width: double.infinity, + color: Colors.transparent, + child: Align( + alignment: Alignment.topCenter, + child: Container( + margin: EdgeInsets.only(top: 10), + width: 60, + height: 5, + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.6), borderRadius: BorderRadius.circular(20))), + ), + ), + ), + ], + ), + ), + Padding( + padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + child: Container( + height: 70, + width: double.infinity, + decoration: BoxDecoration( + border: Border(top: BorderSide(color: grayColor, width: 2)), color: textFieldMessage), + child: Center( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Row( + children: [ + ClipOval( + child: SizedBox.fromSize( + // Image radius + child: Image.network( + MyApp.userViewModel.userCurrent.pp, + width: 45, + ), + ), + ), + SizedBox( + width: 10, + ), + Expanded( + child: TextField( + keyboardAppearance: Brightness.dark, + cursorColor: primaryColor, + keyboardType: TextInputType.emailAddress, + style: GoogleFonts.plusJakartaSans(color: Colors.white), + decoration: InputDecoration( + suffixIcon: Icon( + Icons.send, + color: grayText, + size: 20, + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(width: 1, color: grayText), + borderRadius: BorderRadius.all(Radius.circular(100))), + contentPadding: EdgeInsets.only(top: 0, bottom: 0, left: 20, right: 20), + fillColor: bgModal, + filled: true, + focusColor: Color.fromRGBO(255, 255, 255, 0.30), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(width: 1, color: grayText), + borderRadius: BorderRadius.all(Radius.circular(100))), + hintText: 'Ajoutez une réponse...', + hintStyle: GoogleFonts.plusJakartaSans(color: grayText)), + ), + ) + ], + ), + ), + )), + ), + ], + ), + )); + } +} + +class MyBehavior extends ScrollBehavior { + @override + Widget buildOverscrollIndicator(BuildContext context, Widget child, ScrollableDetails details) { + return child; + } +} diff --git a/Sources/justMUSIC/lib/screens/feed_screen.dart b/Sources/justMUSIC/lib/screens/feed_screen.dart index 7670d92..0324f71 100644 --- a/Sources/justMUSIC/lib/screens/feed_screen.dart +++ b/Sources/justMUSIC/lib/screens/feed_screen.dart @@ -1,14 +1,21 @@ +import 'dart:async'; + +import 'package:another_flushbar/flushbar.dart'; import 'package:circular_reveal_animation/circular_reveal_animation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_countdown_timer/flutter_countdown_timer.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'package:ionicons/ionicons.dart'; import 'package:justmusic/main.dart'; -import '../components/comment_component.dart'; +import 'package:lottie/lottie.dart'; + import '../components/post_component.dart'; import '../components/top_nav_bar_component.dart'; import '../model/Post.dart'; import '../values/constants.dart'; +import 'detail_post_screen.dart'; class FeedScreen extends StatefulWidget { const FeedScreen({Key? key}) : super(key: key); @@ -17,17 +24,21 @@ class FeedScreen extends StatefulWidget { State createState() => _FeedScreenState(); } -class _FeedScreenState extends State - with SingleTickerProviderStateMixin { +class _FeedScreenState extends State with SingleTickerProviderStateMixin { late AnimationController animationController; late Animation animation; late List friendFeed; + Timer? timer; + late List discoveryFeed; late List displayFeed; + final DateTime midnight = DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day + 1); + bool isDismissed = true; @override void initState() { super.initState(); + MyApp.postViewModel.getPostsFriends(); friendFeed = MyApp.postViewModel.postsFriends; MyApp.postViewModel.getBestPosts(); @@ -44,10 +55,90 @@ class _FeedScreenState extends State animationController.forward(); } - Future resetFullScreen() async { - await SystemChannels.platform.invokeMethod( - 'SystemChrome.restoreSystemUIOverlays', - ); + Future showCapsuleDot() async { + bool res = await MyApp.postViewModel.getAvailable(); + if (isDismissed) { + if (res) { + setState(() { + isDismissed = !isDismissed; + }); + Flushbar( + maxWidth: 210, + animationDuration: Duration(seconds: 1), + forwardAnimationCurve: Curves.easeOutCirc, + margin: EdgeInsets.fromLTRB(0, 0, 0, 0), + icon: Icon( + Ionicons.sparkles, + color: Colors.white, + size: 18, + ), + padding: EdgeInsets.fromLTRB(8, 8, 8, 8), + messageText: Align( + alignment: Alignment.centerLeft, + child: Text( + "Capsule disponible", + style: GoogleFonts.plusJakartaSans(color: Colors.grey, fontSize: 15), + ), + ), + flushbarStyle: FlushbarStyle.FLOATING, + flushbarPosition: FlushbarPosition.BOTTOM, + textDirection: Directionality.of(context), + borderRadius: BorderRadius.circular(1000), + borderWidth: 1, + isDismissible: false, + borderColor: Colors.white.withOpacity(0.04), + duration: const Duration(minutes: 100), + leftBarIndicatorColor: Colors.transparent, + positionOffset: 20, + onTap: (_) { + Navigator.pop(context); + Navigator.pushNamed(context, '/post'); + }, + ).show(context).then((value) { + isDismissed = !isDismissed; + }); + } else { + setState(() { + isDismissed = !isDismissed; + }); + Flushbar( + maxWidth: 155, + animationDuration: Duration(seconds: 1), + isDismissible: false, + forwardAnimationCurve: Curves.easeOutCirc, + margin: EdgeInsets.fromLTRB(0, 0, 0, 0), + icon: Lottie.asset( + 'assets/animations/LottieHourGlass.json', + width: 26, + fit: BoxFit.fill, + ), + padding: EdgeInsets.fromLTRB(8, 8, 8, 8), + messageText: Align( + alignment: Alignment.centerLeft, + child: CountdownTimer( + endTime: midnight.millisecondsSinceEpoch - 2 * 60 * 60 * 1000, + textStyle: GoogleFonts.plusJakartaSans(color: Colors.grey, fontSize: 15), + ), + ), + flushbarStyle: FlushbarStyle.FLOATING, + flushbarPosition: FlushbarPosition.BOTTOM, + textDirection: Directionality.of(context), + borderRadius: BorderRadius.circular(1000), + borderWidth: 1, + borderColor: Colors.white.withOpacity(0.04), + duration: const Duration(minutes: 100), + leftBarIndicatorColor: Colors.transparent, + positionOffset: 20, + onTap: (_) {}, + ).show(context).then((value) { + { + setState(() { + isDismissed = !isDismissed; + }); + } + }); + } + } } Future _refresh() async { @@ -87,171 +178,18 @@ class _FeedScreenState extends State isScrollControlled: true, context: context, shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(20), topRight: Radius.circular(20))), + borderRadius: BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20))), builder: ((BuildContext context) { - return GestureDetector( - onTap: () { - FocusScopeNode currentFocus = FocusScope.of(context); - if (!currentFocus.hasPrimaryFocus) { - currentFocus.unfocus(); - resetFullScreen(); - } - }, - child: Container( - height: 720.h, - margin: const EdgeInsets.only(top: 10), - child: Column( - children: [ - Align( - child: Container( - width: 60, - height: 5, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.3), - borderRadius: BorderRadius.circular(20))), - ), - const SizedBox( - height: 20, - ), - Expanded( - child: ClipRRect( - borderRadius: BorderRadius.only( - topRight: Radius.circular(15), - topLeft: Radius.circular(15)), - child: Padding( - padding: EdgeInsets.only( - left: defaultPadding, right: defaultPadding), - child: SingleChildScrollView( - physics: BouncingScrollPhysics( - decelerationRate: ScrollDecelerationRate.fast), - child: Wrap( - // to apply margin in the main axis of the wrap - runSpacing: 10, - children: [ - PostComponent( - callback: null, - post: displayFeed[index], - index: index, - ), - Container(height: 5), - displayFeed[index].description == null - ? Container() - : Padding( - padding: const EdgeInsets.only(bottom: 20), - child: Text( - '${displayFeed[index].description ?? ""}', - style: GoogleFonts.plusJakartaSans( - color: Colors.white, - fontWeight: FontWeight.w200)), - ), - Align( - child: RichText( - text: TextSpan( - text: "3", - style: GoogleFonts.plusJakartaSans( - color: Colors.white, - fontWeight: FontWeight.w600), - children: [ - TextSpan( - text: " commentaires", - style: GoogleFonts.plusJakartaSans( - color: Colors.white, - fontWeight: FontWeight.w300), - ) - ])), - ), - SizedBox(height: 20), - CommentComponent(), - CommentComponent(), - CommentComponent(), - Container(height: 10), - ], - ), - ), - ), - ), - ), - Padding( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).viewInsets.bottom), - child: Container( - height: 70, - width: double.infinity, - decoration: BoxDecoration( - border: Border( - top: BorderSide(color: grayColor, width: 2)), - color: textFieldMessage), - child: Center( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Row( - children: [ - ClipOval( - child: SizedBox.fromSize( - // Image radius - child: const Image( - image: AssetImage( - "assets/images/exemple_profile.png"), - width: 45, - ), - ), - ), - SizedBox( - width: 10, - ), - Expanded( - child: TextField( - keyboardAppearance: Brightness.dark, - cursorColor: primaryColor, - keyboardType: TextInputType.emailAddress, - style: GoogleFonts.plusJakartaSans( - color: Colors.white), - decoration: InputDecoration( - suffixIcon: Icon( - Icons.send, - color: grayText, - size: 20, - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - width: 1, color: grayText), - borderRadius: BorderRadius.all( - Radius.circular(100))), - contentPadding: EdgeInsets.only( - top: 0, - bottom: 0, - left: 20, - right: 20), - fillColor: bgModal, - filled: true, - focusColor: - Color.fromRGBO(255, 255, 255, 0.30), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - width: 1, color: grayText), - borderRadius: BorderRadius.all( - Radius.circular(100))), - hintText: 'Ajoutez une réponse...', - hintStyle: GoogleFonts.plusJakartaSans( - color: grayText)), - ), - ) - ], - ), - ), - )), - ), - ], - ), - ), - ); + return ClipRRect( + borderRadius: BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)), + child: DetailPostScreen(post: displayFeed[index])); }), ); } @override Widget build(BuildContext context) { + showCapsuleDot(); return Scaffold( resizeToAvoidBottomInset: true, backgroundColor: bgColor, @@ -265,21 +203,16 @@ class _FeedScreenState extends State Container( decoration: const BoxDecoration( image: DecorationImage( - image: AssetImage("assets/images/empty_bg.png"), - fit: BoxFit.cover, - opacity: 0.3), + image: AssetImage("assets/images/empty_bg.png"), fit: BoxFit.cover, opacity: 0.3), ), child: Padding( - padding: - EdgeInsets.only(top: 140.h, left: defaultPadding), + padding: EdgeInsets.only(top: 140.h, left: defaultPadding), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Suis tes amis pour voir leurs capsules", style: GoogleFonts.plusJakartaSans( - color: Colors.white, - fontSize: 23, - fontWeight: FontWeight.w800)) + color: Colors.white, fontSize: 23, fontWeight: FontWeight.w800)) ], ), ), @@ -292,14 +225,8 @@ class _FeedScreenState extends State decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topRight, - stops: [ - 0.3, - 1 - ], - colors: [ - bgColor.withOpacity(0.9), - bgColor.withOpacity(0) - ])), + stops: [0.3, 1], + colors: [bgColor.withOpacity(0.9), bgColor.withOpacity(0)])), ), ), ), @@ -325,26 +252,21 @@ class _FeedScreenState extends State centerOffset: Offset(30.w, -100), child: Container( constraints: BoxConstraints(maxWidth: 600), - padding: EdgeInsets.fromLTRB( - defaultPadding, 100.h, defaultPadding, 0), + padding: EdgeInsets.fromLTRB(defaultPadding, 100.h, defaultPadding, 0), child: RefreshIndicator( displacement: 20, triggerMode: RefreshIndicatorTriggerMode.onEdge, onRefresh: _refresh, child: ListView.builder( - physics: const BouncingScrollPhysics( - decelerationRate: - ScrollDecelerationRate.fast), + physics: const BouncingScrollPhysics(decelerationRate: ScrollDecelerationRate.fast), clipBehavior: Clip.none, shrinkWrap: true, itemCount: displayFeed.length, itemBuilder: (BuildContext context, int index) { return Padding( padding: const EdgeInsets.only(bottom: 40), - child: PostComponent( - callback: openDetailPost, - post: displayFeed[index], - index: index), + child: + PostComponent(callback: openDetailPost, post: displayFeed[index], index: index), ); }, ), @@ -359,14 +281,8 @@ class _FeedScreenState extends State decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topRight, - stops: [ - 0.3, - 1 - ], - colors: [ - bgColor.withOpacity(0.9), - bgColor.withOpacity(0) - ])), + stops: [0.3, 1], + colors: [bgColor.withOpacity(0.9), bgColor.withOpacity(0)])), ), ), ), diff --git a/Sources/justMUSIC/pubspec.lock b/Sources/justMUSIC/pubspec.lock index b0be0a1..a63a241 100644 --- a/Sources/justMUSIC/pubspec.lock +++ b/Sources/justMUSIC/pubspec.lock @@ -41,6 +41,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.3.7" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" async: dependency: transitive description: @@ -406,6 +414,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "8c5d68a82add3ca76d792f058b186a0599414f279f00ece4830b9b231b570338" + url: "https://pub.dev" + source: hosted + version: "2.0.7" flutter_test: dependency: "direct dev" description: flutter @@ -672,6 +688,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.8.3" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" path_provider: dependency: transitive description: @@ -720,6 +744,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.7" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 + url: "https://pub.dev" + source: hosted + version: "5.4.0" pinch_zoom: dependency: "direct main" description: @@ -869,6 +901,30 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.7" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "670f6e07aca990b4a2bcdc08a784193c4ccdd1932620244c3a86bb72a0eac67f" + url: "https://pub.dev" + source: hosted + version: "1.1.7" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "7451721781d967db9933b63f5733b1c4533022c0ba373a01bdd79d1a5457f69f" + url: "https://pub.dev" + source: hosted + version: "1.1.7" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "80a13c613c8bde758b1464a1755a7b3a8f2b6cec61fbf0f5a53c94c30f03ba2e" + url: "https://pub.dev" + source: hosted + version: "1.1.7" vector_math: dependency: transitive description: @@ -893,6 +949,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" + xml: + dependency: transitive + description: + name: xml + sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" + url: "https://pub.dev" + source: hosted + version: "6.3.0" zoom_tap_animation: dependency: "direct main" description: diff --git a/Sources/justMUSIC/pubspec.yaml b/Sources/justMUSIC/pubspec.yaml index f3ad4f0..bc11957 100644 --- a/Sources/justMUSIC/pubspec.yaml +++ b/Sources/justMUSIC/pubspec.yaml @@ -70,6 +70,7 @@ dependencies: lottie: ^2.5.0 custom_refresh_indicator: ^2.2.1 animations: ^2.0.7 + flutter_svg: ^2.0.7 dev_dependencies: flutter_test: