Merge with 'SAVE_SONG_LDE'
continuous-integration/drone/push Build is passing Details

LIKES_POST_LDE-EKA
Emre KARTAL 2 years ago
commit 6d6da9f2e1

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

@ -29,6 +29,7 @@ import 'package:timezone/data/latest.dart' as tz;
Future<void> main() async { Future<void> main() async {
tz.initializeTimeZones(); tz.initializeTimeZones();
Paint.enableDithering = true;
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp( await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform, options: DefaultFirebaseOptions.currentPlatform,

@ -14,11 +14,11 @@ class Music {
List<Artist> _artists; List<Artist> _artists;
// Constructor // Constructor
Music(this._id, this._title, this._cover, this._previewUrl, this._date, Music(
this._duration, this._explicit, this._artists); this._id, this._title, this._cover, this._previewUrl, this._date, this._duration, this._explicit, this._artists);
//Getters and setters //Getters and setters
String? get id => _id; String get id => _id;
String? get title => _title; String? get title => _title;

@ -6,12 +6,13 @@ class User {
String _pp; String _pp;
String _token; String _token;
List<String> _followers; List<String> _followers;
List<String> _musics_likes;
int _capsules; int _capsules;
List<String> _followed; List<String> _followed;
// Constructor // Constructor
User(this._id, this._pseudo, this._uniquePseudo, this._mail, this._pp, User(this._id, this._pseudo, this._uniquePseudo, this._mail, this._pp, this._token, this._followers,
this._token, this._followers, this._capsules, this._followed); this._musics_likes, this._capsules, this._followed);
//Getters and setters //Getters and setters
String get id => _id; String get id => _id;
@ -22,6 +23,12 @@ class User {
_pseudo = value; _pseudo = value;
} }
List<String> get musics_likes => _musics_likes;
set musics_likes(List<String> value) {
_musics_likes = value;
}
String get uniquePseudo => _uniquePseudo; String get uniquePseudo => _uniquePseudo;
set uniquePseudo(String value) { set uniquePseudo(String value) {

@ -12,6 +12,7 @@ class UserMapper {
data?["picture"], data?["picture"],
data?["token_notify"], data?["token_notify"],
List<String>.from(data?["followers"] as List), List<String>.from(data?["followers"] as List),
List<String>.from(data?["musics_likes"] as List),
data?["nbCapsules"] ?? 0, data?["nbCapsules"] ?? 0,
List<String>.from(data?["followed"] as List)); List<String>.from(data?["followed"] as List));
} }

@ -5,6 +5,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:pinch_zoom/pinch_zoom.dart';
import 'package:text_scroll/text_scroll.dart'; import 'package:text_scroll/text_scroll.dart';
import 'package:zoom_tap_animation/zoom_tap_animation.dart'; import 'package:zoom_tap_animation/zoom_tap_animation.dart';
import '../components/button_play_component.dart'; import '../components/button_play_component.dart';
@ -44,6 +45,10 @@ class _DetailPostScreenState extends State<DetailPostScreen> {
}); });
} }
bool isSaved() {
return MyApp.userViewModel.userCurrent.musics_likes.contains(widget.post.music.id);
}
@override @override
void dispose() { void dispose() {
MyApp.audioPlayer.release(); MyApp.audioPlayer.release();
@ -89,154 +94,164 @@ class _DetailPostScreenState extends State<DetailPostScreen> {
child: Container( child: Container(
height: 400, height: 400,
width: double.infinity, width: double.infinity,
child: FadeInImage.assetNetwork( child: PinchZoom(
fit: BoxFit.cover, resetDuration: const Duration(milliseconds: 400),
image: choice ? widget.post.selfie! : widget.post.music.cover!, maxScale: 2.5,
fadeInDuration: const Duration(milliseconds: 100), child: FadeInImage.assetNetwork(
placeholder: "assets/images/loadingPlaceholder.gif", placeholder: "assets/images/loadingPlaceholder.gif",
), image: choice ? widget.post.selfie! : widget.post.music.cover!,
width: double.infinity,
fit: BoxFit.cover,
)),
), ),
), ),
Column( Column(
children: [ children: [
Container( IgnorePointer(
height: 200, child: Container(
margin: EdgeInsets.only(top: 230), height: 200,
width: double.infinity, margin: EdgeInsets.only(top: 230),
decoration: const BoxDecoration( width: double.infinity,
gradient: LinearGradient( decoration: BoxDecoration(
begin: Alignment.topCenter, gradient: LinearGradient(
end: Alignment.bottomCenter, begin: Alignment.topCenter,
colors: [Colors.transparent, bgModal], end: Alignment.bottomCenter,
stops: [0, 0.8], colors: [
Colors.transparent,
bgModal.withOpacity(0.5),
bgModal.withOpacity(0.75),
bgModal
],
stops: [0, 0.2, 0.4, 0.8],
),
), ),
), child: Padding(
child: Padding( padding: const EdgeInsets.fromLTRB(20, 0, 20, 10),
padding: const EdgeInsets.fromLTRB(20, 0, 20, 10), child: Row(
child: Row( crossAxisAlignment: CrossAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end, children: [
children: [ Padding(
Padding( padding: const EdgeInsets.only(right: 10),
padding: const EdgeInsets.only(right: 10), child: choice
child: choice ? Padding(
? Padding( padding: const EdgeInsets.all(4),
padding: const EdgeInsets.all(4), child: ClipOval(
child: ClipOval( child: SizedBox.fromSize(
child: SizedBox.fromSize( // Image radius
// Image radius child: ProfilPictureComponent(user: widget.post.user),
child: ProfilPictureComponent(user: widget.post.user), ),
), ),
)
: 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,
),
),
),
],
), ),
) ),
: widget.post.music.previewUrl != null choice
? ButtonPlayComponent(music: widget.post.music) ? widget.post.location.item2 != null
: Container(), ? Text(
), "${widget.post.location.item1}, ${widget.post.location.item2}",
Flexible( style: GoogleFonts.plusJakartaSans(
child: Column( color: Colors.white.withOpacity(0.5),
mainAxisAlignment: MainAxisAlignment.end, fontWeight: FontWeight.w400,
crossAxisAlignment: CrossAxisAlignment.start, fontSize: 15,
children: [ ),
Flexible( )
child: Row( : Text(
crossAxisAlignment: CrossAxisAlignment.end, "",
children: [ style: GoogleFonts.plusJakartaSans(
Expanded( color: Colors.white.withOpacity(0.4),
child: ScrollConfiguration( fontWeight: FontWeight.w300,
fontSize: 13,
),
)
: ScrollConfiguration(
behavior: ScrollBehavior().copyWith(scrollbars: false), behavior: ScrollBehavior().copyWith(scrollbars: false),
child: TextScroll( child: TextScroll(
choice ? widget.post.user.pseudo : widget.post.music.title!, widget.post.music.artists.first.name!,
style: GoogleFonts.plusJakartaSans( style: GoogleFonts.plusJakartaSans(
height: 1, height: 1,
color: Colors.white, color: Colors.white,
fontWeight: FontWeight.w800, fontWeight: FontWeight.w500,
fontSize: 22, fontSize: 17,
), ),
mode: TextScrollMode.endless, mode: TextScrollMode.endless,
pauseBetween: Duration(milliseconds: 500), pauseBetween: Duration(milliseconds: 500),
velocity: Velocity(pixelsPerSecond: Offset(20, 0)), 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)),
),
),
],
), ),
), ],
], ),
), ),
), ),
), ),
@ -274,21 +289,108 @@ class _DetailPostScreenState extends State<DetailPostScreen> {
child: Column( child: Column(
children: [ children: [
Padding( Padding(
padding: EdgeInsets.symmetric(vertical: 20), padding: EdgeInsets.only(top: 30, bottom: 20),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SvgPicture.asset("assets/images/heart.svg", semanticsLabel: 'Like Logo'), SvgPicture.asset("assets/images/heart.svg", semanticsLabel: 'Like Logo'),
GestureDetector( Column(
onTap: () { children: [
myFocusNode.requestFocus(); GestureDetector(
}, onTap: () {
child: SvgPicture.asset("assets/images/chat.svg", myFocusNode.requestFocus();
semanticsLabel: 'Chat Logo'), },
child: SvgPicture.asset("assets/images/chat.svg",
semanticsLabel: 'Chat Logo'),
),
Container(
padding: EdgeInsets.only(top: 8),
height: 30,
child: FutureBuilder<List<Comment>>(
future: MyApp.commentViewModel.getCommentsByPostId(widget.post.id),
builder:
(BuildContext context, AsyncSnapshot<List<Comment>> snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.length.toString(),
style: GoogleFonts.plusJakartaSans(
color: Colors.white,
fontWeight: FontWeight.w800,
));
} else {
return Container(
child: Center(
child: CupertinoActivityIndicator(),
),
);
}
},
),
)
],
), ),
SvgPicture.asset("assets/images/add.svg", SvgPicture.asset("assets/images/add.svg",
semanticsLabel: 'Add playlist Logo'), semanticsLabel: 'Add playlist Logo'),
SvgPicture.asset("assets/images/save.svg", semanticsLabel: 'Save Logo'), GestureDetector(
onTap: () async {
var bool = await MyApp.musicViewModel
.addOrDeleteFavoriteMusic(widget.post.music.id);
!bool
? ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: RichText(
textAlign: TextAlign.center,
maxLines: 1,
overflow: TextOverflow.ellipsis,
text: TextSpan(
style: GoogleFonts.plusJakartaSans(
color: Colors.white,
fontWeight: FontWeight.w400,
fontSize: 15,
),
children: <TextSpan>[
TextSpan(
text: "${widget.post.music.title}",
style: TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: " ajouté à votre collection"),
],
),
),
backgroundColor: primaryColor,
closeIconColor: Colors.white,
),
)
: ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: RichText(
textAlign: TextAlign.center,
maxLines: 1,
overflow: TextOverflow.ellipsis,
text: TextSpan(
style: GoogleFonts.plusJakartaSans(
color: Colors.white,
fontWeight: FontWeight.w400,
fontSize: 15,
),
children: <TextSpan>[
TextSpan(
text: "${widget.post.music.title}",
style: TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: " retiré de votre collection"),
],
),
),
backgroundColor: Colors.red,
closeIconColor: Colors.white,
),
);
setState(() {});
},
child: SvgPicture.asset(
"assets/images/save.svg",
semanticsLabel: 'Save Logo',
color: isSaved() ? primaryColor : Colors.white,
)),
SvgPicture.asset("assets/images/report.svg", semanticsLabel: 'Report Logo'), SvgPicture.asset("assets/images/report.svg", semanticsLabel: 'Report Logo'),
], ],
), ),
@ -299,31 +401,6 @@ class _DetailPostScreenState extends State<DetailPostScreen> {
if (snapshot.hasData) { if (snapshot.hasData) {
return Column( return Column(
children: [ children: [
snapshot.data!.length > 0
? Padding(
padding: const EdgeInsets.all(15.0),
child: RichText(
text: TextSpan(
text: snapshot.data!.length.toString(),
style: GoogleFonts.plusJakartaSans(
color: Colors.white,
fontWeight: FontWeight.w800,
),
children: [
TextSpan(
text: snapshot.data!.length > 1
? " commentaires"
: " commentaire",
style: GoogleFonts.plusJakartaSans(
color: Colors.white,
fontWeight: FontWeight.w400,
),
),
],
),
),
)
: Container(),
snapshot.data!.length > 0 snapshot.data!.length > 0
? Padding( ? Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 20), padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),

@ -91,7 +91,14 @@ class _FeedScreenState extends State<FeedScreen> with SingleTickerProviderStateM
builder: ((BuildContext context) { builder: ((BuildContext context) {
return ClipRRect( return ClipRRect(
borderRadius: BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)), borderRadius: BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)),
child: DetailPostScreen(post: post)); child: SizedBox(
height: 760.h,
child: Scaffold(
primary: false,
extendBody: false,
backgroundColor: Colors.transparent,
body: DetailPostScreen(post: post)),
));
}), }),
); );
} }

@ -11,7 +11,6 @@ import '../components/editable_post_component.dart';
import '../components/post_button_component.dart'; import '../components/post_button_component.dart';
import '../main.dart'; import '../main.dart';
import '../model/Music.dart'; import '../model/Music.dart';
import '../model/Post.dart';
import '../values/constants.dart'; import '../values/constants.dart';
class PostScreen extends StatefulWidget { class PostScreen extends StatefulWidget {
@ -93,7 +92,7 @@ class _PostScreenState extends State<PostScreen> with SingleTickerProviderStateM
} }
handleSubmit() async { handleSubmit() async {
MyApp.postViewModel.addPost(description, (selectedMusic?.id)!, selectedImage, selectedCity); MyApp.postViewModel.addPost(description, selectedMusic!.id, selectedImage, selectedCity);
quit(); quit();
} }

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/Material.dart'; import 'package:flutter/Material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:justmusic/model/Music.dart'; import 'package:justmusic/model/Music.dart';
@ -21,6 +22,7 @@ class SearchSongScreen extends StatefulWidget {
class _SearchSongScreenState extends State<SearchSongScreen> { class _SearchSongScreenState extends State<SearchSongScreen> {
final ScrollController _scrollController = ScrollController(); final ScrollController _scrollController = ScrollController();
final TextEditingController _textEditingController = TextEditingController(); final TextEditingController _textEditingController = TextEditingController();
PageController controller = PageController();
int? playingIndex; int? playingIndex;
@ -81,6 +83,10 @@ class _SearchSongScreenState extends State<SearchSongScreen> {
} }
} }
Future<List<Music>> _fetchSavedSong() async {
return await MyApp.musicViewModel.getFavoriteMusicsByUserId(MyApp.userViewModel.userCurrent.id);
}
@override @override
void dispose() { void dispose() {
MyApp.audioPlayer.pause(); MyApp.audioPlayer.pause();
@ -124,7 +130,6 @@ class _SearchSongScreenState extends State<SearchSongScreen> {
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: TextField( child: TextField(
autofocus: true,
controller: _textEditingController, controller: _textEditingController,
keyboardAppearance: Brightness.dark, keyboardAppearance: Brightness.dark,
onEditingComplete: resetFullScreen, onEditingComplete: resetFullScreen,
@ -132,11 +137,15 @@ class _SearchSongScreenState extends State<SearchSongScreen> {
if (_textEditingController.text.isEmpty) { if (_textEditingController.text.isEmpty) {
fetchTrendingMusic(); fetchTrendingMusic();
} else { } else {
setState(() {
filteredData = [];
});
filteredData = await MyApp.musicViewModel.getMusicsWithNameOrArtistName(value); filteredData = await MyApp.musicViewModel.getMusicsWithNameOrArtistName(value);
setState(() { setState(() {
filteredData = filteredData; filteredData = filteredData;
}); });
} }
controller.animateTo(0, duration: Duration(milliseconds: 200), curve: Curves.easeIn);
}, },
cursorColor: Colors.white, cursorColor: Colors.white,
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
@ -163,42 +172,94 @@ class _SearchSongScreenState extends State<SearchSongScreen> {
), ),
), ),
Flexible( Flexible(
child: ScrollConfiguration( child: PageView(
behavior: ScrollBehavior().copyWith(scrollbars: true), controller: controller,
child: ListView.builder( physics: BouncingScrollPhysics(),
physics: const BouncingScrollPhysics(decelerationRate: ScrollDecelerationRate.fast), children: [
controller: _scrollController, ScrollConfiguration(
itemCount: filteredData.length, behavior: ScrollBehavior().copyWith(scrollbars: true),
itemBuilder: (context, index) { child: ListView.builder(
if (playingIndex == index) { physics: const BouncingScrollPhysics(decelerationRate: ScrollDecelerationRate.fast),
return InkWell( controller: _scrollController,
onTap: () { itemCount: filteredData.length,
widget.callback(filteredData[index]); itemBuilder: (context, index) {
}, if (playingIndex == index) {
child: Padding( return InkWell(
padding: const EdgeInsets.symmetric(horizontal: 20), onTap: () {
child: MusicListComponent( widget.callback(filteredData[index]);
music: filteredData[index], },
playing: true, child: Padding(
callback: playMusic, padding: const EdgeInsets.symmetric(horizontal: 20),
index: index, child: MusicListComponent(
), music: filteredData[index],
)); playing: true,
} callback: playMusic,
return InkWell( index: index,
onTap: () { ),
widget.callback(filteredData[index]); ));
}, }
child: Padding( return InkWell(
padding: const EdgeInsets.symmetric(horizontal: 20), onTap: () {
child: MusicListComponent( widget.callback(filteredData[index]);
music: filteredData[index], },
playing: false, child: Padding(
callback: playMusic, padding: const EdgeInsets.symmetric(horizontal: 20),
index: index, child: MusicListComponent(
), music: filteredData[index],
)); playing: false,
}), callback: playMusic,
index: index,
),
));
}),
),
ScrollConfiguration(
behavior: ScrollBehavior().copyWith(scrollbars: true),
child: FutureBuilder(
future: _fetchSavedSong(),
builder: (BuildContext context, AsyncSnapshot<List<Music>> snapshot) {
if (snapshot.hasData) {
return ListView.builder(
physics: const BouncingScrollPhysics(decelerationRate: ScrollDecelerationRate.fast),
controller: _scrollController,
itemCount: snapshot.data?.length,
itemBuilder: (context, index) {
if (playingIndex == index) {
return InkWell(
onTap: () {
widget.callback(filteredData[index]);
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: MusicListComponent(
music: (snapshot.data?[index])!,
playing: true,
callback: playMusic,
index: index,
),
));
}
return InkWell(
onTap: () {
widget.callback((snapshot.data?[index])!);
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: MusicListComponent(
music: (snapshot.data?[index])!,
playing: false,
callback: playMusic,
index: index,
),
));
});
} else {
return CupertinoActivityIndicator();
}
},
),
)
],
)) ))
], ],
), ),

@ -88,10 +88,8 @@ class AuthService {
Future<String> generateUniqueId(String pseudo) async { Future<String> generateUniqueId(String pseudo) async {
String uniqueId = '$pseudo#0001'; String uniqueId = '$pseudo#0001';
int suffix = 1; int suffix = 1;
final CollectionReference usersCollection = final CollectionReference usersCollection = FirebaseFirestore.instance.collection("users");
FirebaseFirestore.instance.collection("users"); final QuerySnapshot querySnapshot = await usersCollection.where('pseudo', isEqualTo: pseudo).get();
final QuerySnapshot querySnapshot =
await usersCollection.where('pseudo', isEqualTo: pseudo).get();
querySnapshot.docs.forEach((snapshot) { querySnapshot.docs.forEach((snapshot) {
suffix++; suffix++;
@ -103,8 +101,7 @@ class AuthService {
login(String email, String password) async { login(String email, String password) async {
try { try {
await FirebaseAuth.instance await FirebaseAuth.instance.signInWithEmailAndPassword(email: email, password: password);
.signInWithEmailAndPassword(email: email, password: password);
} on FirebaseAuthException catch (e) { } on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') { if (e.code == 'user-not-found') {
throw ('Mail incorrect'); throw ('Mail incorrect');
@ -137,8 +134,7 @@ class AuthService {
.doc(currentUser?.uid) .doc(currentUser?.uid)
.delete() .delete()
.then((value) => print("Firestore deleted user")) .then((value) => print("Firestore deleted user"))
.catchError( .catchError((error) => print("Error deleting user from Firestore: $error"));
(error) => print("Error deleting user from Firestore: $error"));
await currentUser?.delete(); await currentUser?.delete();
await FirebaseAuth.instance.signOut(); await FirebaseAuth.instance.signOut();

@ -5,45 +5,30 @@ import '../main.dart';
class MusicService { class MusicService {
Future<dynamic> getFavoriteMusicsByUserId(String id) async { Future<dynamic> getFavoriteMusicsByUserId(String id) async {
var response = var response = await FirebaseFirestore.instance.collection("users").doc(id).get();
await FirebaseFirestore.instance.collection("users").doc(id).get();
if (response.exists) { if (response.exists) {
var musicFavorite = response.get("musics_likes"); var musicFavorite = response.get("saved_musics");
return List.from(musicFavorite); return List.from(musicFavorite);
} else { } else {
return []; return [];
} }
} }
deleteFavoriteMusic(String id) async {
var userRef = await FirebaseFirestore.instance
.collection("users")
.doc(MyApp.userViewModel.userCurrent.id);
var response = await userRef.get();
List<dynamic> musicFavorite = List.from(response.get("musics_likes"));
if (!musicFavorite.contains(id)) {
musicFavorite.remove(id);
await userRef.update({"musics_likes": musicFavorite});
} else {
print("Delete error: The music is not in the user's favorite music list");
}
}
Future<bool> addOrDeleteFavoriteMusic(String id) async { Future<bool> addOrDeleteFavoriteMusic(String id) async {
var userRef = await FirebaseFirestore.instance var userRef = await FirebaseFirestore.instance.collection("users").doc(MyApp.userViewModel.userCurrent.id);
.collection("users")
.doc(MyApp.userViewModel.userCurrent.id);
var response = await userRef.get(); var response = await userRef.get();
List<dynamic> musicFavorite = List.from(response.get("musics_likes")); List<String> musicFavorite = List.from(response.get("musics_likes"));
if (!musicFavorite.contains(id)) { if (!musicFavorite.contains(id)) {
musicFavorite.add(id); musicFavorite.add(id);
await userRef.update({"musics_likes": musicFavorite}); await userRef.update({"musics_likes": musicFavorite});
MyApp.userViewModel.userCurrent.musics_likes.add(id);
return false; return false;
} else { } else {
musicFavorite.remove(id); musicFavorite.remove(id);
await userRef.update({"musics_likes": musicFavorite}); await userRef.update({"musics_likes": musicFavorite});
MyApp.userViewModel.userCurrent.musics_likes.remove(id);
return true; return true;
} }
} }

@ -3,6 +3,7 @@ import 'dart:convert';
import 'package:justmusic/view_model/TokenSpotify.dart'; import 'package:justmusic/view_model/TokenSpotify.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
import '../main.dart';
import '../model/Artist.dart'; import '../model/Artist.dart';
import '../model/Music.dart'; import '../model/Music.dart';
import '../services/MusicService.dart'; import '../services/MusicService.dart';
@ -28,8 +29,7 @@ class MusicViewModel {
return _getMusicFromResponse(responseData); return _getMusicFromResponse(responseData);
} else { } else {
throw Exception( throw Exception('Error retrieving music information : ${response.statusCode} ${response.reasonPhrase}');
'Error retrieving music information : ${response.statusCode} ${response.reasonPhrase}');
} }
} }
@ -49,15 +49,12 @@ class MusicViewModel {
artists); artists);
} }
Future<List<Music>> getMusicsWithName(String name, Future<List<Music>> getMusicsWithName(String name, {int limit = 20, int offset = 0, String market = "FR"}) async {
{int limit = 20, int offset = 0, String market = "FR"}) async {
var accessToken = await _token.getAccessToken(); var accessToken = await _token.getAccessToken();
var response = await http.get( var response = await http
Uri.parse( .get(Uri.parse('$API_URL/search?q=track%3A$name&type=track&market=fr&limit=$limit&offset=$offset'), headers: {
'$API_URL/search?q=track%3A$name&type=track&market=fr&limit=$limit&offset=$offset'), 'Authorization': 'Bearer $accessToken',
headers: { });
'Authorization': 'Bearer $accessToken',
});
if (response.statusCode == 200) { if (response.statusCode == 200) {
Map<String, dynamic> responseData = jsonDecode(response.body); Map<String, dynamic> responseData = jsonDecode(response.body);
@ -65,20 +62,17 @@ class MusicViewModel {
return _getMusicFromResponse(track); return _getMusicFromResponse(track);
})); }));
} else { } else {
throw Exception( throw Exception('Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}');
'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}');
} }
} }
Future<List<Music>> getMusicsWithArtistName(String name, Future<List<Music>> getMusicsWithArtistName(String name,
{int limit = 20, int offset = 0, String market = "FR"}) async { {int limit = 20, int offset = 0, String market = "FR"}) async {
var accessToken = await _token.getAccessToken(); var accessToken = await _token.getAccessToken();
var response = await http.get( var response = await http
Uri.parse( .get(Uri.parse('$API_URL/search?q=artist%3A$name&type=track&market=fr&limit=$limit&offset=$offset'), headers: {
'$API_URL/search?q=artist%3A$name&type=track&market=fr&limit=$limit&offset=$offset'), 'Authorization': 'Bearer $accessToken',
headers: { });
'Authorization': 'Bearer $accessToken',
});
if (response.statusCode == 200) { if (response.statusCode == 200) {
Map<String, dynamic> responseData = jsonDecode(response.body); Map<String, dynamic> responseData = jsonDecode(response.body);
@ -86,24 +80,19 @@ class MusicViewModel {
return _getMusicFromResponse(track); return _getMusicFromResponse(track);
})); }));
} else { } else {
throw Exception( throw Exception('Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}');
'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}');
} }
} }
Future<Artist> getArtistWithName(String name, {String market = "FR"}) async { Future<Artist> getArtistWithName(String name, {String market = "FR"}) async {
var accessToken = await _token.getAccessToken(); var accessToken = await _token.getAccessToken();
var response = await http.get( var response = await http.get(Uri.parse('$API_URL/search?q=artist%3A$name&type=artist&market=$market'), headers: {
Uri.parse( 'Authorization': 'Bearer $accessToken',
'$API_URL/search?q=artist%3A$name&type=artist&market=$market'), });
headers: {
'Authorization': 'Bearer $accessToken',
});
if (response.statusCode == 200) { if (response.statusCode == 200) {
final responseData = jsonDecode(response.body); final responseData = jsonDecode(response.body);
List<Artist> artists = List<Artist> artists = List<Artist>.from(responseData['artists']['items'].map((artist) {
List<Artist>.from(responseData['artists']['items'].map((artist) {
String image = ''; String image = '';
if (!artist['images'].isEmpty) { if (!artist['images'].isEmpty) {
image = artist['images'][0]['url']; image = artist['images'][0]['url'];
@ -119,25 +108,21 @@ class MusicViewModel {
throw Exception('Artist not found : ${name}'); throw Exception('Artist not found : ${name}');
} else { } else {
throw Exception( throw Exception('Error retrieving artist information : ${response.statusCode} ${response.reasonPhrase}');
'Error retrieving artist information : ${response.statusCode} ${response.reasonPhrase}');
} }
} }
Future<List<Artist>> getArtistsWithName(String name, Future<List<Artist>> getArtistsWithName(String name, {int limit = 20, int offset = 0, String market = "FR"}) async {
{int limit = 20, int offset = 0, String market = "FR"}) async {
var accessToken = await _token.getAccessToken(); var accessToken = await _token.getAccessToken();
var response = await http.get( var response = await http.get(
Uri.parse( Uri.parse('$API_URL/search?q=artist%3A$name&type=artist&market=$market&limit=$limit&offset=$offset'),
'$API_URL/search?q=artist%3A$name&type=artist&market=$market&limit=$limit&offset=$offset'),
headers: { headers: {
'Authorization': 'Bearer $accessToken', 'Authorization': 'Bearer $accessToken',
}); });
if (response.statusCode == 200) { if (response.statusCode == 200) {
final responseData = jsonDecode(response.body); final responseData = jsonDecode(response.body);
List<Artist> artists = List<Artist> artists = List<Artist>.from(responseData['artists']['items'].map((artist) {
List<Artist>.from(responseData['artists']['items'].map((artist) {
String image = ''; String image = '';
if (!artist['images'].isEmpty) { if (!artist['images'].isEmpty) {
image = artist['images'][0]['url']; image = artist['images'][0]['url'];
@ -147,19 +132,15 @@ class MusicViewModel {
return artists; return artists;
} else { } else {
throw Exception( throw Exception('Error while retrieving artist : ${response.statusCode} ${response.reasonPhrase}');
'Error while retrieving artist : ${response.statusCode} ${response.reasonPhrase}');
} }
} }
Future<List<Music>> getTopMusicsWithArtistId(String id, Future<List<Music>> getTopMusicsWithArtistId(String id, {String market = "FR"}) async {
{String market = "FR"}) async {
var accessToken = await _token.getAccessToken(); var accessToken = await _token.getAccessToken();
var response = await http.get( var response = await http.get(Uri.parse('$API_URL/artists/$id/top-tracks?market=$market'), headers: {
Uri.parse('$API_URL/artists/$id/top-tracks?market=$market'), 'Authorization': 'Bearer $accessToken',
headers: { });
'Authorization': 'Bearer $accessToken',
});
if (response.statusCode == 200) { if (response.statusCode == 200) {
Map<String, dynamic> responseData = jsonDecode(response.body); Map<String, dynamic> responseData = jsonDecode(response.body);
@ -167,16 +148,13 @@ class MusicViewModel {
return _getMusicFromResponse(track); return _getMusicFromResponse(track);
})); }));
} else { } else {
throw Exception( throw Exception('Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}');
'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}');
} }
} }
Future<List<Music>> getMusicsWithPlaylistId(String id, Future<List<Music>> getMusicsWithPlaylistId(String id, {String market = "FR"}) async {
{String market = "FR"}) async {
var accessToken = await _token.getAccessToken(); var accessToken = await _token.getAccessToken();
var response = await http var response = await http.get(Uri.parse('$API_URL/playlists/$id?market=$market'), headers: {
.get(Uri.parse('$API_URL/playlists/$id?market=$market'), headers: {
'Authorization': 'Bearer $accessToken', 'Authorization': 'Bearer $accessToken',
}); });
@ -192,13 +170,11 @@ class MusicViewModel {
return musics; return musics;
} else { } else {
throw Exception( throw Exception('Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}');
'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}');
} }
} }
Future<List<Music>> getMusicsWithIds(List<String> ids, Future<List<Music>> getMusicsWithIds(List<String> ids, {String market = "FR"}) async {
{String market = "FR"}) async {
var accessToken = await _token.getAccessToken(); var accessToken = await _token.getAccessToken();
String url = API_URL + '/tracks?market=$market&ids='; String url = API_URL + '/tracks?market=$market&ids=';
@ -216,8 +192,7 @@ class MusicViewModel {
return _getMusicFromResponse(track); return _getMusicFromResponse(track);
})); }));
} else { } else {
throw Exception( throw Exception('Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}');
'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}');
} }
} }
@ -227,18 +202,21 @@ class MusicViewModel {
List<Music> musics = []; List<Music> musics = [];
Artist artist = await getArtistWithName(name, market: market); Artist artist = await getArtistWithName(name, market: market);
musics.addAll(await getTopMusicsWithArtistId(artist.id)); musics.addAll(await getTopMusicsWithArtistId(artist.id));
musics.addAll(await getMusicsWithName(name, musics.addAll(await getMusicsWithName(name, limit: limit, offset: offset, market: market));
limit: limit, offset: offset, market: market));
return musics; return musics;
} catch (e) { } catch (e) {
return await getMusicsWithName(name, return await getMusicsWithName(name, limit: limit, offset: offset, market: market);
limit: limit, offset: offset, market: market);
} }
} }
Future<List<Music>> getFavoriteMusicsByUserId(String id) async { Future<List<Music>> getFavoriteMusicsByUserId(String id) async {
try { try {
var idMusics = await _musicService.getFavoriteMusicsByUserId(id); List<String> idMusics = [];
if (id == MyApp.userViewModel.userCurrent.id) {
idMusics = MyApp.userViewModel.userCurrent.musics_likes;
} else {
idMusics = await _musicService.getFavoriteMusicsByUserId(id);
}
return await getMusicsWithIds(idMusics); return await getMusicsWithIds(idMusics);
} catch (e) { } catch (e) {
print(e); print(e);

Loading…
Cancel
Save