diff --git a/daflmusic/assets/images/default_background.png b/daflmusic/assets/images/default_background.png new file mode 100644 index 0000000..c27ecce Binary files /dev/null and b/daflmusic/assets/images/default_background.png differ diff --git a/daflmusic/assets/images/icon_discovery.png b/daflmusic/assets/images/icon_discovery.png new file mode 100644 index 0000000..d3dc70c Binary files /dev/null and b/daflmusic/assets/images/icon_discovery.png differ diff --git a/daflmusic/assets/images/icon_dislike.png b/daflmusic/assets/images/icon_dislike.png new file mode 100644 index 0000000..7196a46 Binary files /dev/null and b/daflmusic/assets/images/icon_dislike.png differ diff --git a/daflmusic/assets/images/icon_like.png b/daflmusic/assets/images/icon_like.png new file mode 100644 index 0000000..d5297d9 Binary files /dev/null and b/daflmusic/assets/images/icon_like.png differ diff --git a/daflmusic/lib/homePage/main_homepage.dart b/daflmusic/lib/homePage/main_homepage.dart index 1779a50..d17bc80 100644 --- a/daflmusic/lib/homePage/main_homepage.dart +++ b/daflmusic/lib/homePage/main_homepage.dart @@ -97,6 +97,8 @@ class _MainHomePage extends State { onTap: (){ Navigator.of(context).push( PageTransition( + duration: Duration(milliseconds: 300), + reverseDuration: Duration(milliseconds: 300), type: PageTransitionType.rightToLeftJoined, childCurrent: widget, child: MainSignInPage()), diff --git a/daflmusic/lib/main.dart b/daflmusic/lib/main.dart index 22445f2..d8746bf 100644 --- a/daflmusic/lib/main.dart +++ b/daflmusic/lib/main.dart @@ -1,40 +1,194 @@ +import 'dart:math'; + import 'package:daflmusic/mainPage/main_mainpage.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:daflmusic/signInPage/main_signIn_page.dart'; import 'package:daflmusic/homePage/main_homepage.dart'; import 'package:daflmusic/signUpPage/main_signUp_page.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:provider/provider.dart'; void main() { - runApp(const MyApp()); + runApp(MyApp()); } class MyApp extends StatelessWidget { - const MyApp({super.key}); // This widget is the root of your application. @override - Widget build(BuildContext context) { - SystemChrome.setEnabledSystemUIMode( - SystemUiMode.immersiveSticky - ); - return MaterialApp( - debugShowCheckedModeBanner: false, - title: 'Flutter Demo', - theme: ThemeData( - // This is the theme of your application. - // - // Try running your application with "flutter run". You'll see the - // application has a blue toolbar. Then, without quitting the app, try - // changing the primarySwatch below to Colors.green and then invoke - // "hot reload" (press "r" in the console where you ran "flutter run", - // or simply save your changes to "hot reload" in a Flutter IDE). - // Notice that the counter didn't reset back to zero; the application - // is not restarted. - primarySwatch: Colors.blue, + Widget build(BuildContext context){ + SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); + return ChangeNotifierProvider( + create: (context) => CardProvider(), + child: MaterialApp( + debugShowCheckedModeBanner: false, + title: 'Flutter Demo', + home: MainHomePage(), ), - home: MainHomePage(), ); } +} + +enum CardStatus { like, disLike, discovery} + +class CardProvider extends ChangeNotifier{ + List _urlImages = []; + bool _isDragging = false; + double _angle = 0; + Offset _position = Offset.zero; + Size _screenSize = Size.zero; + + List get urlImages => _urlImages; + bool get isDragging => _isDragging; + Offset get position => _position; + double get angle => _angle; + + CardProvider() { + resetUsers(); + } + + void resetUsers() { + _urlImages = [ + 'https://khaligidilit.com/assets/images/cover-LAI%CC%88LA-Khali.jpeg', + 'https://m.media-amazon.com/images/I/61aUOMzwS8L._SL1440_.jpg', + 'https://pbs.twimg.com/media/ExJ-My-XMAE3Ko2.jpg', + 'https://cdns-images.dzcdn.net/images/cover/2818a661c6d533155ce6dffc256b1f51/500x500.jpg', + 'https://cdns-images.dzcdn.net/images/cover/b351f0e935c9c3901f8d893b92ab952a/500x500.jpg', + 'https://cdns-images.dzcdn.net/images/cover/65147b581f2ace9e0f0723ee76e70fda/500x500.jpg', + 'https://images.genius.com/a8b6d39d8b10d7441527e2f5cf6b6ca5.1000x1000x1.jpg', + 'https://cdns-images.dzcdn.net/images/cover/17a9747927ac3e5ea56f92f635d9180c/500x500.jpg', + ].reversed.toList(); + + notifyListeners(); + } + + void setScreenSize(Size screenSize) => _screenSize = screenSize; + + void startPosition(DragStartDetails details) { + _isDragging = true; + + notifyListeners(); + } + + void updatePosition(DragUpdateDetails details) { + _position += details.delta; + + final x = _position.dx; + _angle = 45 * x / _screenSize.width; + notifyListeners(); + } + + void endPosition() { + _isDragging = false; + notifyListeners(); + + final status = getStatus(force: true); + + + switch (status) { + case CardStatus.like: + like(); + break; + case CardStatus.disLike: + dislike(); + break; + case CardStatus.discovery: + discovery(); + break; + default: + resetPosition(); + } + } + void resetPosition() { + _isDragging = false; + _position = Offset.zero; + _angle = 0; + + notifyListeners(); + } + + double getStatusOpacity() { + final delta = 100; + final pos = max(_position.dx.abs(), _position.dy.abs()); + final opacity = pos / delta; + + return min(opacity, 1); + } + + CardStatus? getStatus({bool force = false}) { + final x = _position.dx; + final y = _position.dy; + final forceDiscovery = x.abs() < 20; + + if(force) { + final delta = 100; + + if (x >= delta) { + return CardStatus.like; + } else if ( x <= -delta){ + return CardStatus.disLike; + } else if ( y <= -delta / 2 && forceDiscovery){ + return CardStatus.discovery; + } + } else{ + final delta = 20; + + if(y <= -delta * 2 && forceDiscovery) { + return CardStatus.discovery; + } else if ( x >= delta) { + return CardStatus.like; + } else if ( x <= -delta) { + return CardStatus.disLike; + } + } + } + void dislike() { + print("dislike"); + _angle = -20; + _position -= Offset(2 * _screenSize.width, 0); + _nextCard(); + + notifyListeners(); + } + + void discovery() { + print("discovery"); + _angle = 0; + _position -= Offset(0, _screenSize.height); + _discovery_card(); + Fluttertoast.showToast( + msg: 'Ajouté', + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.TOP, + timeInSecForIosWeb: 2, + backgroundColor: Colors.deepPurple, + textColor: Colors.white + ); + + notifyListeners(); + } + + void like() { + print("like"); + _angle = 20; + _position += Offset(2 * _screenSize.width, 0); + _nextCard(); + + notifyListeners(); + } + + Future _nextCard() async { + if ( _urlImages.isEmpty) return; + + await Future.delayed(Duration(milliseconds: 200)); + _urlImages.removeLast(); + resetPosition(); + } + + Future _discovery_card() async { + await Future.delayed(Duration(milliseconds: 200)); + resetPosition(); + } } \ No newline at end of file diff --git a/daflmusic/lib/mainPage/main_mainpage.dart b/daflmusic/lib/mainPage/main_mainpage.dart index b22bd17..a47dbb9 100644 --- a/daflmusic/lib/mainPage/main_mainpage.dart +++ b/daflmusic/lib/mainPage/main_mainpage.dart @@ -27,6 +27,7 @@ class _MainMainPageState extends State { ]; @override Widget build(BuildContext context) { + double height = MediaQuery.of(context).size.height; return Scaffold( body: screens[index], bottomNavigationBar: NavigationBarTheme( @@ -36,20 +37,27 @@ class _MainMainPageState extends State { TextStyle(fontSize: 12, fontWeight: FontWeight.w400, color: Colors.grey) ), ), - child: NavigationBar( - animationDuration: Duration(seconds: 1), - selectedIndex: index, - onDestinationSelected: (index) => - setState(() => this.index = index), - backgroundColor: Color(0xFF232123), - destinations: [ - NavigationDestination(icon: Icon(Icons.person_outline, color: Colors.grey,), label: 'Profil', selectedIcon: Icon(Icons.person, color: Colors.white,),), - NavigationDestination(icon: Icon(Icons.bookmark_border, color: Colors.grey,), selectedIcon: Icon(Icons.bookmark, color: Colors.white,), label: 'Discovery'), - NavigationDestination(icon: Icon(MyFlutterApp.Spots_outline, color: Colors.grey), selectedIcon: Icon(MyFlutterApp.Spots, color: Colors.white), label: 'Spots',), - NavigationDestination(icon: Icon(MyFlutterApp.podium_outine, color: Colors.grey,), label: 'Tops', selectedIcon: Icon(MyFlutterApp.podium, color: Colors.white,),), - NavigationDestination(icon: Icon(Icons.mail_outline, color: Colors.grey,), label: 'Messages', selectedIcon: Icon(Icons.email, color: Colors.white,),), - ], - ), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: height*0.1, + maxHeight: 100, + ), + child: NavigationBar( + animationDuration: Duration(seconds: 1), + selectedIndex: index, + height: height*0.1, + onDestinationSelected: (index) => + setState(() => this.index = index), + backgroundColor: Color(0xFF232123), + destinations: [ + NavigationDestination(icon: Icon(Icons.person_outline, color: Colors.grey,), label: 'Profil', selectedIcon: Icon(Icons.person, color: Colors.white,),), + NavigationDestination(icon: Icon(Icons.bookmark_border, color: Colors.grey,), selectedIcon: Icon(Icons.bookmark, color: Colors.white,), label: 'Discovery'), + NavigationDestination(icon: Icon(MyFlutterApp.Spots_outline, color: Colors.grey), selectedIcon: Icon(MyFlutterApp.Spots, color: Colors.white), label: 'Spots',), + NavigationDestination(icon: Icon(MyFlutterApp.podium_outine, color: Colors.grey,), label: 'Tops', selectedIcon: Icon(MyFlutterApp.podium, color: Colors.white,),), + NavigationDestination(icon: Icon(Icons.mail_outline, color: Colors.grey,), label: 'Messages', selectedIcon: Icon(Icons.email, color: Colors.white,),), + ], + ), + ), ), ); } diff --git a/daflmusic/lib/signUpPage/main_signUp_page.dart b/daflmusic/lib/signUpPage/main_signUp_page.dart index 526ed87..bcd641c 100644 --- a/daflmusic/lib/signUpPage/main_signUp_page.dart +++ b/daflmusic/lib/signUpPage/main_signUp_page.dart @@ -238,6 +238,8 @@ class _MainSignUpPageState extends State { }); Navigator.of(context).push( PageTransition( + duration: Duration(milliseconds: 300), + reverseDuration: Duration(milliseconds: 300), type: PageTransitionType.leftToRightJoined, childCurrent: widget, child: MainHomePage()), diff --git a/daflmusic/lib/widgets/DaflCard.dart b/daflmusic/lib/widgets/DaflCard.dart new file mode 100644 index 0000000..2d3b914 --- /dev/null +++ b/daflmusic/lib/widgets/DaflCard.dart @@ -0,0 +1,159 @@ +import 'dart:math'; + +import 'package:daflmusic/dafl_card.dart'; +import 'package:daflmusic/main.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +class User{ + final String chanteur; + final String titre; + final String urlImage; + + const User({ + required this.chanteur, + required this.titre, + required this.urlImage, +}); +} + + + +class DaflCard extends StatefulWidget { + final String urlImage; + final bool isFront; + + const DaflCard({ + Key? key, + required this.urlImage, + required this.isFront, + }) : super(key: key); + + @override + State createState() => _DaflCardState(); +} +class _DaflCardState extends State{ + @override + void initState() { + super.initState(); + + WidgetsBinding.instance!.addPostFrameCallback((_) { + final size = MediaQuery.of(context).size; + + final provider = Provider.of(context, listen: false); + provider.setScreenSize(size); + }); + } + @override + Widget build(BuildContext context) => SizedBox.expand( + child: widget.isFront ? buildFrontCard() : buildCard(), + ); + + Widget buildCard() => ClipRRect( + borderRadius: BorderRadius.circular(20), + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: NetworkImage(widget.urlImage), + fit: BoxFit.cover, + alignment: Alignment(0,0), + ), + + borderRadius: BorderRadius.all(Radius.circular(20)) + ), + ), + ); + + Widget buildStamps() { + final provider = Provider.of(context); + final status = provider.getStatus(); + final opacity = provider.getStatusOpacity(); + + switch (status) { + case CardStatus.like: + final child = buildStamp(image: 'assets/images/icon_like.png', opacity: opacity); + return child; + case CardStatus.disLike: + final child = buildStamp(image: 'assets/images/icon_dislike.png', opacity: opacity); + return child; + case CardStatus.discovery: + final child = buildStamp(image: 'assets/images/icon_discovery.png', opacity: opacity); + return child; + default: + return Container(); + + } + } + + Widget buildStamp({ + double angle = 0, + required String image, + required double opacity, +}) { + return Opacity(opacity: opacity, + child: ClipRRect( + borderRadius: BorderRadius.circular(20), + child: Container( + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.7), + border: Border.all(color: Color(0xFF3F1DC3), width: 6), + + borderRadius: BorderRadius.all(Radius.circular(20)) + ), + child: Center( + child: Image.asset( + image, + width: 100, + ), + + ), + ), + ),); + } + + Widget buildFrontCard() => GestureDetector( + child: LayoutBuilder( + builder: (context, constraints) { + final provider = Provider.of(context); + final position = provider.position; + final milliseconds = provider.isDragging ? 0 : 400; + + final center = constraints.smallest.center(Offset.zero); + final angle = provider.angle * pi / 180; + final rotatedMatrix = Matrix4.identity() + ..translate(center.dx, center.dy) + ..rotateZ(angle) + ..translate(-center.dx, -center.dy); + + return AnimatedContainer( + curve: Curves.easeInOut, + duration: Duration(milliseconds: milliseconds), + transform: rotatedMatrix..translate(position.dx, position.dy), + child: Stack( + children: [ + buildCard(), + buildStamps(), + ], + ), + ); + }, + ), + onPanStart: (details) { + final provider = Provider.of(context, listen: false); + + provider.startPosition(details); + }, + onPanUpdate: (details) { + final provider = Provider.of(context, listen: false); + + provider.updatePosition(details); + }, + onPanEnd: (details) { + final provider = Provider.of(context, listen: false); + + provider.endPosition(); + }, + + + + ); +} \ No newline at end of file diff --git a/daflmusic/lib/widgets/spots.dart b/daflmusic/lib/widgets/spots.dart index ba73bf3..79f373c 100644 --- a/daflmusic/lib/widgets/spots.dart +++ b/daflmusic/lib/widgets/spots.dart @@ -1,8 +1,15 @@ +import 'dart:ui'; + import 'package:animations/animations.dart'; -import 'package:daflmusic/dafl_card.dart'; +import 'package:daflmusic/homePage/main_homepage.dart'; +import 'package:daflmusic/main.dart'; +import 'package:daflmusic/mainPage/main_mainpage.dart'; +import 'package:daflmusic/widgets/DaflCard.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_swipable/flutter_swipable.dart'; +import 'package:provider/provider.dart'; +import 'package:fluttertoast/fluttertoast.dart'; + class Spots extends StatefulWidget { const Spots({Key? key}) : super(key: key); @@ -13,20 +20,16 @@ class Spots extends StatefulWidget { class _SpotsState extends State { - List pileCarte = [ - DaflCard(color: Colors.red), - DaflCard(color: Colors.red), - DaflCard(color: Colors.red), - DaflCard(color: Colors.red), - DaflCard(color: Colors.red), - DaflCard(color: Colors.red), - DaflCard(color: Colors.red), - DaflCard(color: Colors.red), - ]; + final user = User( + chanteur: 'Khali', + titre: 'COULEURS', + urlImage: 'https://khaligidilit.com/assets/images/cover-LAI%CC%88LA-Khali.jpeg', + ); @override Widget build(BuildContext context) { double height = MediaQuery.of(context).size.height; double width = MediaQuery.of(context).size.width; + final provider = Provider.of(context); return Scaffold( resizeToAvoidBottomInset: false, @@ -35,129 +38,149 @@ class _SpotsState extends State { height: double.maxFinite, child: Stack( children: [ - Image.asset( - 'assets/images/image_blur.png', - height: double.infinity, - width: double.infinity, - fit: BoxFit.cover, - ), - Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - - Stack( - children: [ - Center( - child: Container( - decoration: BoxDecoration( - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.25), - spreadRadius: 0, - blurRadius: 10, - offset: Offset(0, 3), // changes position of shadow - ), - ], - - borderRadius: BorderRadius.all(Radius.circular(20)) - ), - margin: EdgeInsets.fromLTRB(34, height*0.1, 34, 0), - height: height*0.66, - width: 565, - child: Stack(children: - pileCarte, - ), - ), - ), - IgnorePointer(child: Container(height: 200, - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [Colors.black, Colors.transparent], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ) - - ),),), - Padding(padding: EdgeInsets.fromLTRB(20, 60, 0, 0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('COULEURS',style: TextStyle(fontFamily: 'DMSans', color: Colors.white.withOpacity(1) ,fontSize: 20, fontWeight: FontWeight.w800),), - Text('Khali',style: TextStyle(fontFamily: 'DMSans', color: Colors.white.withOpacity(1) ,fontSize: 17, fontWeight: FontWeight.w200),), - ], - ),), - - ], - ), - Padding( - padding: EdgeInsets.fromLTRB(0, height*0.03, 0,0), - child: Align( - alignment: FractionalOffset.bottomCenter, - child: OpenContainer( - - closedColor: Colors.transparent, - closedElevation: 0, - transitionDuration: Duration(milliseconds: 400), - closedBuilder: (context, openWidget){ - return PreviewInfo(); - }, - openBuilder: (context, closeWidget){ - return Destination(); - }, - ), - ), - ), - - ], - ), - Positioned( - top: height*0.71, - width: width, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - GestureDetector( - onTap: () { - pileCarte.remove(0); - print("remove"); - }, - child: Image.asset( - 'assets/images/bouton_dislike.png', - height: 70, - width: 70, + Transform.scale(scale: 1.1, + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: NetworkImage(provider.urlImages.isEmpty != true + ?provider.urlImages.last + :"https://www.colorhexa.com/141414.png"), fit: BoxFit.cover, + ), ), - SizedBox( - width: width*0.1, - ), - GestureDetector( - child: Image.asset( - 'assets/images/bouton_discovery.png', - height: 70, - width: 70, - fit: BoxFit.cover, + child: BackdropFilter(filter: ImageFilter.blur(sigmaX: 20.0, sigmaY: 20.0), + child: Container( + decoration: BoxDecoration(color: Colors.black.withOpacity(0.4)), + ),), + ),), + Padding( + padding: EdgeInsets.fromLTRB(0, 0, 0,height*0.03), + child: Align( + alignment: FractionalOffset.bottomCenter, + child: OpenContainer( + + closedColor: Colors.transparent, + closedElevation: 0, + transitionDuration: Duration(milliseconds: 400), + closedBuilder: (context, openWidget){ + return PreviewInfo(); + }, + openBuilder: (context, closeWidget){ + return Destination(); + }, ), ), - SizedBox( - width: width*0.1, + ), + Positioned( + top: height*0.65, + width: width, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + onTap: () { + final provider = Provider.of(context, listen: false); + provider.dislike(); + }, + child: Image.asset( + 'assets/images/bouton_dislike.png', + height: 90, + width: 90, + fit: BoxFit.cover, + ), + ), + SizedBox( + width: width*0.1, + ), + GestureDetector( + onTap: () { + final provider = Provider.of(context, listen: false); + provider.discovery(); + }, + child: Image.asset( + 'assets/images/bouton_discovery.png', + height: 90, + width: 90, + fit: BoxFit.cover, + ), + ), + SizedBox( + width: width*0.1, + ), + GestureDetector( + onTap: () { + final provider = Provider.of(context, listen: false); + provider.like(); + }, + child: Image.asset( + 'assets/images/bouton_like.png', + height: 90, + width: 90, + fit: BoxFit.cover, + ), + ), + ], ), - GestureDetector( - child: Image.asset( - 'assets/images/bouton_like.png', - height: 70, - width: 70, - fit: BoxFit.cover, + ), + Align( + child:Container( + width: 400, + height: height*0.8, + margin: EdgeInsets.fromLTRB(width*0.09,height/5,width*0.09,height/3.7), + + child: Container( + decoration: BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.25), + spreadRadius: 2, + blurRadius: 10, + offset: Offset(0, 3), // changes position of shadow + ), + ], + ), + child: buildCards(), + ) + ) , ), - ), - ], - ), - ), + IgnorePointer(child: Container(height: 200, + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [Colors.black, Colors.transparent], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ) + + ),),), + Padding(padding: EdgeInsets.fromLTRB(20, 60, 0, 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('COULEURS',style: TextStyle(fontFamily: 'DMSans', color: Colors.white.withOpacity(1) ,fontSize: 20, fontWeight: FontWeight.w800),), + Text('Khali',style: TextStyle(fontFamily: 'DMSans', color: Colors.white.withOpacity(1) ,fontSize: 17, fontWeight: FontWeight.w200),), + ], + ),), ], ), ) ); } + + Widget buildCards() { + final provider = Provider.of(context); + final urlImages = provider.urlImages; + + return Stack( + children: urlImages + .map((urlImage) => DaflCard( + urlImage: urlImage, + isFront: urlImages.last == urlImage, + )) + .toList(), + ); + } + } class Destination extends StatelessWidget{ @@ -641,7 +664,7 @@ class PreviewInfo extends StatelessWidget{ double height = MediaQuery.of(context).size.height; return Container( width: 200, - height: height*0.10, + height: height*0.08, decoration: BoxDecoration( color: Color(0xFF24243A).withOpacity(0.24), border: Border.all(width: 0, color: Colors.grey.withOpacity(0)),