nouvelle page de swipe plus propre avec bouton 'infos' implementation des boutons

Vues_lucas
Lucas Delanier 3 years ago
parent 1b8299b8f8
commit 6127ec88db

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -97,6 +97,8 @@ class _MainHomePage extends State<MainHomePage> {
onTap: (){
Navigator.of(context).push(
PageTransition(
duration: Duration(milliseconds: 300),
reverseDuration: Duration(milliseconds: 300),
type: PageTransitionType.rightToLeftJoined,
childCurrent: widget,
child: MainSignInPage()),

@ -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<String> _urlImages = [];
bool _isDragging = false;
double _angle = 0;
Offset _position = Offset.zero;
Size _screenSize = Size.zero;
List<String> get urlImages => _urlImages;
bool get isDragging => _isDragging;
Offset get position => _position;
double get angle => _angle;
CardProvider() {
resetUsers();
}
void resetUsers() {
_urlImages = <String>[
'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();
}
}

@ -27,6 +27,7 @@ class _MainMainPageState extends State<MainMainPage> {
];
@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<MainMainPage> {
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,),),
],
),
),
),
);
}

@ -238,6 +238,8 @@ class _MainSignUpPageState extends State<MainSignUpPage> {
});
Navigator.of(context).push(
PageTransition(
duration: Duration(milliseconds: 300),
reverseDuration: Duration(milliseconds: 300),
type: PageTransitionType.leftToRightJoined,
childCurrent: widget,
child: MainHomePage()),

@ -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<DaflCard> createState() => _DaflCardState();
}
class _DaflCardState extends State<DaflCard>{
@override
void initState() {
super.initState();
WidgetsBinding.instance!.addPostFrameCallback((_) {
final size = MediaQuery.of(context).size;
final provider = Provider.of<CardProvider>(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<CardProvider>(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<CardProvider>(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<CardProvider>(context, listen: false);
provider.startPosition(details);
},
onPanUpdate: (details) {
final provider = Provider.of<CardProvider>(context, listen: false);
provider.updatePosition(details);
},
onPanEnd: (details) {
final provider = Provider.of<CardProvider>(context, listen: false);
provider.endPosition();
},
);
}

@ -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<Spots> {
List<Widget> pileCarte = <Widget>[
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<CardProvider>(context);
return Scaffold(
resizeToAvoidBottomInset: false,
@ -35,129 +38,149 @@ class _SpotsState extends State<Spots> {
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<CardProvider>(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<CardProvider>(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<CardProvider>(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<CardProvider>(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)),

Loading…
Cancel
Save