diff --git a/Sources/justMUSIC/lib/components/buttonPostComponent.dart b/Sources/justMUSIC/lib/components/buttonPostComponent.dart index 10be7f9..166f426 100644 --- a/Sources/justMUSIC/lib/components/buttonPostComponent.dart +++ b/Sources/justMUSIC/lib/components/buttonPostComponent.dart @@ -1,15 +1,120 @@ import 'package:flutter/Material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:ionicons/ionicons.dart'; import '../values/constants.dart'; -class ButtonPostComponent extends StatelessWidget { - const ButtonPostComponent({Key? key}) : super(key: key); +class PhotoPostComponent extends StatelessWidget { + final bool empty; + const PhotoPostComponent({Key? key, required this.empty}) : super(key: key); @override Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.fromLTRB(20, 5, 20, 5), - color: postbutton, - ); + return empty + ? Container( + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: postbutton, borderRadius: BorderRadius.circular(8)), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Ionicons.camera, + size: 15, + color: Colors.white, + ), + SizedBox( + width: 10, + ), + Text( + 'Prendre un selfie', + style: GoogleFonts.plusJakartaSans( + color: Colors.white, fontSize: 12), + ) + ]), + ) + : Container( + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: fillButton, borderRadius: BorderRadius.circular(8)), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Selfie enregistré", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, fontSize: 12), + ), + SizedBox( + width: 10, + ), + Icon( + Icons.close, + size: 12, + color: Colors.white, + ), + ]), + ); + } +} + +class LocationPostComponent extends StatelessWidget { + final bool empty; + const LocationPostComponent({Key? key, required this.empty}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return empty + ? Container( + width: double.infinity, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: postbutton, borderRadius: BorderRadius.circular(8)), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.location_on, + size: 15, + color: Colors.white, + ), + SizedBox( + width: 10, + ), + Text( + 'Ajouter un lieu', + style: GoogleFonts.plusJakartaSans( + color: Colors.white, fontSize: 12), + ) + ]), + ) + : Container( + width: double.infinity, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: fillButton, borderRadius: BorderRadius.circular(8)), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Lieu enregistré", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, fontSize: 12), + ), + SizedBox( + width: 10, + ), + Icon( + Icons.close, + size: 12, + color: Colors.white, + ), + ]), + ); } } diff --git a/Sources/justMUSIC/lib/components/editable_post_component.dart b/Sources/justMUSIC/lib/components/editable_post_component.dart index 234974a..dda4c74 100644 --- a/Sources/justMUSIC/lib/components/editable_post_component.dart +++ b/Sources/justMUSIC/lib/components/editable_post_component.dart @@ -1,24 +1,33 @@ import 'dart:io'; +import 'package:animated_appear/animated_appear.dart'; import 'package:auto_size_text/auto_size_text.dart'; +import 'package:circular_reveal_animation/circular_reveal_animation.dart'; import 'package:flutter/Material.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 'package:insta_image_viewer/insta_image_viewer.dart'; import 'package:justmusic/values/constants.dart'; +import 'package:text_scroll/text_scroll.dart'; + +import '../model/Music.dart'; +import 'buttonPostComponent.dart'; class EditablePostComponent extends StatefulWidget { - final Function callback; - const EditablePostComponent({Key? key, required this.callback}) - : super(key: key); + final Music? music; + const EditablePostComponent({Key? key, this.music}) : super(key: key); @override State createState() => _EditablePostComponentState(); } -class _EditablePostComponentState extends State { +class _EditablePostComponentState extends State + with TickerProviderStateMixin { final ImagePicker picker = ImagePicker(); + late Animation animation; + late AnimationController animationController; File? image; Future pickImage() async { @@ -34,6 +43,20 @@ class _EditablePostComponentState extends State { } } + @override + void initState() { + animationController = AnimationController( + vsync: this, + duration: Duration(milliseconds: 400), + ); + animation = CurvedAnimation( + parent: animationController, + curve: Curves.easeInOutSine, + ); + animationController.forward(); + super.initState(); + } + @override Widget build(BuildContext context) { return ClipRRect( @@ -42,73 +65,165 @@ class _EditablePostComponentState extends State { constraints: BoxConstraints(maxWidth: 400, minHeight: 500), width: double.infinity, color: warningBttnColor, - child: Stack( - alignment: Alignment.topCenter, + child: Column( children: [ - AspectRatio( - aspectRatio: 1 / 1, - child: GestureDetector( - onTap: () { - print("cc"); - widget.callback; - }, - child: Container( - decoration: BoxDecoration( - // add border - border: Border.all(width: 3.0, color: grayColor), - // set border radius - borderRadius: BorderRadius.circular(20), - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(18), - // implement image - child: const Image( - image: AssetImage("assets/images/exemple_cover.png"), - fit: BoxFit.cover, - width: double.infinity, + CircularRevealAnimation( + animation: animation, + centerOffset: Offset(30.w, -100), + child: Stack( + children: [ + AspectRatio( + aspectRatio: 1 / 1, + child: Container( + decoration: BoxDecoration( + // add border + border: Border.all(width: 3.0, color: grayColor), + // set border radius + borderRadius: BorderRadius.circular(20), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(18), + // implement image + child: widget.music == null + ? Container( + color: grayColor, + width: double.infinity, + ) + : Image( + image: + NetworkImage(widget.music?.cover ?? ""), + fit: BoxFit.cover, + width: double.infinity, + ), + ), ), ), - ), + image != null + ? Positioned( + top: 10, + right: 10, + child: AnimatedAppear( + delay: Duration(milliseconds: 500), + duration: Duration(milliseconds: 400), + child: Container( + width: 110, + height: 110, + decoration: BoxDecoration( + image: DecorationImage( + image: FileImage(image!), + fit: BoxFit.cover, + ), + color: grayColor, + borderRadius: BorderRadius.circular(20), + border: Border.all( + style: BorderStyle.solid, + color: Colors.white, + width: 4)), + child: ClipRRect( + borderRadius: BorderRadius.circular(20), + child: InstaImageViewer( + backgroundIsTransparent: true, + child: Image( + image: FileImage(image!), + fit: BoxFit.cover, + ), + ), + ), + ), + )) + : Container() + ], )), - Positioned( - bottom: 40, - child: Padding( - padding: EdgeInsets.fromLTRB(15, 25, 15, 25), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - AutoSizeText( - "France, Lyon", - style: GoogleFonts.plusJakartaSans( - color: Colors.white, fontSize: 13.sp), - maxFontSize: 20, - ), - image == null - ? GestureDetector( - child: Image( - image: - AssetImage("assets/images/camera_icon.png"), - width: 30, + widget.music != null + ? Padding( + padding: const EdgeInsets.all(10), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + flex: 8, + child: TextScroll( + (widget.music?.title)!, + style: GoogleFonts.plusJakartaSans( + height: 1, + color: Colors.white, + fontWeight: FontWeight.w600, + fontSize: 26.h), + mode: TextScrollMode.endless, + pauseBetween: Duration(milliseconds: 500), + velocity: + Velocity(pixelsPerSecond: Offset(20, 0)), + )), + Padding( + padding: EdgeInsets.only( + bottom: 10.h, right: 5.w, left: 5.w), + child: ClipOval( + child: Container( + width: 5.h, + height: 5.h, + color: Colors.white, ), - onTap: () { - print("cc2"); - - pickImage(); - }, - ) - : Container( - height: 80, - width: 80, - child: Image.file(image!), ), - AutoSizeText( - "10 Juil. 2023", - style: GoogleFonts.plusJakartaSans( - color: Colors.white, fontSize: 13.sp), - maxFontSize: 20, + ), + Flexible( + flex: 6, + child: Padding( + padding: EdgeInsets.only(bottom: 2), + child: TextScroll( + (widget.music?.artists[0].name)!, + style: GoogleFonts.plusJakartaSans( + height: 1, + color: Colors.white, + fontWeight: FontWeight.w300, + fontSize: 16.h), + mode: TextScrollMode.endless, + velocity: + Velocity(pixelsPerSecond: Offset(50, 20)), + pauseBetween: Duration(milliseconds: 500), + ), + )), + Container(width: 10), + AutoSizeText( + "2013", + style: GoogleFonts.plusJakartaSans( + color: Colors.white.withOpacity(0.5), + fontWeight: FontWeight.w300, + fontSize: 16.h), + textAlign: TextAlign.end, + maxFontSize: 20, + ), + ], ), - ], - ), + ) + : Container(), + Container( + padding: EdgeInsets.fromLTRB(15, 15, 15, 25), + width: double.infinity, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + flex: 5, + child: GestureDetector( + onTap: () { + manageImage(); + }, + child: PhotoPostComponent( + empty: image == null, + ), + ), + ), + SizedBox( + width: 15, + ), + Expanded( + flex: 5, + child: LocationPostComponent( + empty: true, + ), + ), + ], ), ), Padding( @@ -155,4 +270,14 @@ class _EditablePostComponentState extends State { ), )); } + + void manageImage() { + if (image != null) { + setState(() { + image = null; + }); + } else { + pickImage(); + } + } } diff --git a/Sources/justMUSIC/lib/components/music_list_component.dart b/Sources/justMUSIC/lib/components/music_list_component.dart index 1cbc516..93c5c42 100644 --- a/Sources/justMUSIC/lib/components/music_list_component.dart +++ b/Sources/justMUSIC/lib/components/music_list_component.dart @@ -9,7 +9,7 @@ class MusicListComponent extends StatelessWidget { final bool playing; final int index; final Function(int) callback; - const MusicListComponent({ + MusicListComponent({ Key? key, required this.music, required this.playing, diff --git a/Sources/justMUSIC/lib/components/play_button_component.dart b/Sources/justMUSIC/lib/components/play_button_component.dart index 9c4ebb0..237881d 100644 --- a/Sources/justMUSIC/lib/components/play_button_component.dart +++ b/Sources/justMUSIC/lib/components/play_button_component.dart @@ -10,8 +10,8 @@ class PlayButtonComponent extends StatefulWidget { final Music music; final Function callback; final int index; - bool playing; - PlayButtonComponent( + final bool playing; + const PlayButtonComponent( {Key? key, required this.music, required this.callback, @@ -63,7 +63,9 @@ class _PlayButtonComponentState extends State { child: AnimatedPlayButton( stopped: false, color: Colors.grey.withOpacity(0.3), - onPressed: () {}, + onPressed: () { + print("cc"); + }, ), )); } diff --git a/Sources/justMUSIC/lib/screens/post_screen.dart b/Sources/justMUSIC/lib/screens/post_screen.dart index 51b2a27..ecc1051 100644 --- a/Sources/justMUSIC/lib/screens/post_screen.dart +++ b/Sources/justMUSIC/lib/screens/post_screen.dart @@ -5,6 +5,7 @@ import 'package:justmusic/components/back_button.dart'; import 'package:justmusic/screens/search_song_screen.dart'; import '../components/editable_post_component.dart'; import '../components/post_button_component.dart'; +import '../model/Music.dart'; import '../values/constants.dart'; class PostScreen extends StatefulWidget { @@ -18,7 +19,8 @@ class _PostScreenState extends State with SingleTickerProviderStateMixin { final scrollController = ScrollController(); late AnimationController _controller; - late Animation _animation; + + Music? selectedMusic; @override void initState() { @@ -27,15 +29,16 @@ class _PostScreenState extends State duration: const Duration(milliseconds: 400), ); - _animation = Tween(begin: 0.0, end: 400.0).animate( - CurvedAnimation( - parent: _controller, - curve: Curves.easeOut, - ), - ); super.initState(); } + void _selectMusic(Music music) { + Navigator.pop(context); + setState(() { + selectedMusic = music; + }); + } + void openDetailPost() { showModalBottomSheet( transitionAnimationController: _controller, @@ -51,10 +54,10 @@ class _PostScreenState extends State borderRadius: BorderRadius.only( topLeft: Radius.circular(20), topRight: Radius.circular(20))), builder: ((context) { - return const ClipRRect( + return ClipRRect( borderRadius: BorderRadius.only( topLeft: Radius.circular(20), topRight: Radius.circular(20)), - child: SearchSongScreen()); + child: SearchSongScreen(callback: _selectMusic)); }), ); } @@ -90,32 +93,29 @@ class _PostScreenState extends State fit: BoxFit.cover, ), ), - child: Stack( - alignment: Alignment.topCenter, - children: [ - ScrollConfiguration( - behavior: ScrollBehavior().copyWith(scrollbars: false), - child: SingleChildScrollView( - controller: scrollController, - child: Column( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - SizedBox( - height: 100.h, - ), - EditablePostComponent(callback: openDetailPost), - SizedBox( - height: 40.h, - ), - PostButtonComponent(), - SizedBox( - height: 40.h, - ), - ], + child: ScrollConfiguration( + behavior: ScrollBehavior().copyWith(scrollbars: false), + child: SingleChildScrollView( + controller: scrollController, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SizedBox( + height: 100.h, + ), + GestureDetector( + onTap: openDetailPost, + child: EditablePostComponent(music: selectedMusic)), + SizedBox( + height: 40.h, ), - ), + PostButtonComponent(), + SizedBox( + height: 40.h, + ), + ], ), - ], + ), ), ), ); diff --git a/Sources/justMUSIC/lib/screens/search_song_screen.dart b/Sources/justMUSIC/lib/screens/search_song_screen.dart index 1042b6a..8ef2ecc 100644 --- a/Sources/justMUSIC/lib/screens/search_song_screen.dart +++ b/Sources/justMUSIC/lib/screens/search_song_screen.dart @@ -11,7 +11,8 @@ import '../values/constants.dart'; import '../main.dart'; class SearchSongScreen extends StatefulWidget { - const SearchSongScreen({Key? key}) : super(key: key); + final Function callback; + const SearchSongScreen({Key? key, required this.callback}) : super(key: key); @override State createState() => _SearchSongScreenState(); @@ -169,25 +170,35 @@ class _SearchSongScreenState extends State { itemCount: filteredData.length, itemBuilder: (context, index) { if (playingIndex == index) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: MusicListComponent( - music: filteredData[index], - playing: true, - callback: playMusic, - index: index, - ), - ); + return InkWell( + onTap: () { + widget.callback(filteredData[index]); + }, + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 20), + child: MusicListComponent( + music: filteredData[index], + playing: true, + callback: playMusic, + index: index, + ), + )); } - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: MusicListComponent( - music: filteredData[index], - playing: false, - callback: playMusic, - index: index, - ), - ); + return InkWell( + onTap: () { + widget.callback(filteredData[index]); + }, + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 20), + child: MusicListComponent( + music: filteredData[index], + playing: false, + callback: playMusic, + index: index, + ), + )); }), )) ], diff --git a/Sources/justMUSIC/lib/values/constants.dart b/Sources/justMUSIC/lib/values/constants.dart index e3512f9..db5a300 100644 --- a/Sources/justMUSIC/lib/values/constants.dart +++ b/Sources/justMUSIC/lib/values/constants.dart @@ -21,6 +21,7 @@ const grayText = Color(0xFF898989); const settingColor = Color(0xFF232323); const searchBarColor = Color(0xFF161616); const postbutton = Color(0xFF1B1B1B); +const fillButton = Color(0xFF633AF4); // All constants important too us const defaultPadding = 30.0; diff --git a/Sources/justMUSIC/pubspec.lock b/Sources/justMUSIC/pubspec.lock index afce498..dfbd0a1 100644 --- a/Sources/justMUSIC/pubspec.lock +++ b/Sources/justMUSIC/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + animated_appear: + dependency: "direct main" + description: + name: animated_appear + sha256: "53097d7bb6d5e4a1a3a74c8f3028c47c87101c6ec8903f2002372d1eb5aee991" + url: "https://pub.dev" + source: hosted + version: "0.0.4" async: dependency: transitive description: @@ -368,6 +376,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.1" + insta_image_viewer: + dependency: "direct main" + description: + name: insta_image_viewer + sha256: "9a81432b1ab907ea91c255ec079440afe43f999533422badffaa482dfb7fdfbb" + url: "https://pub.dev" + source: hosted + version: "1.0.2" ionicons: dependency: "direct main" description: @@ -488,6 +504,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.7" + pinch_zoom: + dependency: "direct main" + description: + name: pinch_zoom + sha256: ad12872281742726afaf03438d99a4572c584a612630768953beb6dfd6f9389a + url: "https://pub.dev" + source: hosted + version: "1.0.0" platform: dependency: transitive description: @@ -517,6 +541,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + smooth_list_view: + dependency: "direct main" + description: + name: smooth_list_view + sha256: d6eb3bed78881c50d4574b0dd466ed3321972477688c1c021178f3132155112a + url: "https://pub.dev" + source: hosted + version: "1.0.4" source_span: dependency: transitive description: diff --git a/Sources/justMUSIC/pubspec.yaml b/Sources/justMUSIC/pubspec.yaml index 13380a9..67c874a 100644 --- a/Sources/justMUSIC/pubspec.yaml +++ b/Sources/justMUSIC/pubspec.yaml @@ -54,6 +54,10 @@ dependencies: ionicons: ^0.2.2 top_snackbar_flutter: ^3.1.0 image_picker: ^1.0.1 + insta_image_viewer: ^1.0.2 + pinch_zoom: ^1.0.0 + smooth_list_view: ^1.0.4 + animated_appear: ^0.0.4 dev_dependencies: flutter_test: