From c0ce4dcc04b9288075007744c2cf52156fa69aa0 Mon Sep 17 00:00:00 2001 From: emkartal1 Date: Sat, 29 Jul 2023 20:32:02 +0200 Subject: [PATCH 01/16] add new functions --- .../lib/view_model/MusicViewModel.dart | 75 +++++++++++++++---- Sources/justMUSIC/test/Music_test.dart | 22 ++++++ 2 files changed, 83 insertions(+), 14 deletions(-) diff --git a/Sources/justMUSIC/lib/view_model/MusicViewModel.dart b/Sources/justMUSIC/lib/view_model/MusicViewModel.dart index 668526a..e50285e 100644 --- a/Sources/justMUSIC/lib/view_model/MusicViewModel.dart +++ b/Sources/justMUSIC/lib/view_model/MusicViewModel.dart @@ -42,21 +42,22 @@ class MusicViewModel { } } - List _getMusicsFromResponse(Map responseData) { + List _getMusicsFromResponse(List tracks) { List musics = []; - List tracks = responseData['tracks']['items']; for (var track in tracks) { List artists = List.from(track['artists'].map((artist) { return Artist(artist['id'], artist['name'], ''); })); + DateTime releaseDate = DateTime.parse(track['album']['release_date']); + musics.add(Music( track['id'], track['name'], track['album']['images'][0]['url'], track['preview_url'], - DateTime.now(), + releaseDate, track['duration_ms'] / 1000, track['explicit'], artists)); @@ -77,7 +78,7 @@ class MusicViewModel { if (response.statusCode == 200) { Map responseData = jsonDecode(response.body); - return _getMusicsFromResponse(responseData); + return _getMusicsFromResponse(responseData['tracks']['items']); } else { throw Exception( 'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}'); @@ -96,7 +97,7 @@ class MusicViewModel { if (response.statusCode == 200) { Map responseData = jsonDecode(response.body); - return _getMusicsFromResponse(responseData); + return _getMusicsFromResponse(responseData['tracks']['items']); } else { throw Exception( 'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}'); @@ -175,22 +176,42 @@ class MusicViewModel { if (response.statusCode == 200) { Map responseData = jsonDecode(response.body); + return _getMusicsFromResponse(responseData['tracks']); + } else { + throw Exception( + 'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}'); + } + } + + Future> getMusicsWithPlaylistId(String id, + {String market = "FR"}) async { + var accessToken = await _token.getAccessToken(); + var response = await http + .get(Uri.parse('$API_URL/playlists/$id?market=$market'), headers: { + 'Authorization': 'Bearer $accessToken', + }); + + if (response.statusCode == 200) { + Map responseData = jsonDecode(response.body); + List musics = []; - List tracks = responseData['tracks']; + List tracks = responseData['tracks']['items']; for (var track in tracks) { - List artists = List.from(track['artists'].map((artist) { + List artists = List.from(track['track']['artists'].map((artist) { return Artist(artist['id'], artist['name'], ''); })); + DateTime releaseDate = DateTime.parse(track['track']['album']['release_date']); + musics.add(Music( - track['id'], - track['name'], - track['album']['images'][0]['url'], - track['preview_url'], - DateTime.now(), - track['duration_ms'] / 1000, - track['explicit'], + track['track']['id'], + track['track']['name'], + track['track']['album']['images'][0]['url'], + track['track']['preview_url'], + releaseDate, + track['track']['duration_ms'] / 1000, + track['track']['explicit'], artists)); } @@ -200,4 +221,30 @@ class MusicViewModel { 'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}'); } } + + Future> getMusicsWithIds(List ids, + {String market = "FR"}) async { + var accessToken = await _token.getAccessToken(); + String url = API_URL+'/tracks?market=$market&ids='; + + if (ids.length == 0) return []; + + url += ids.join('%2C'); + + print(url); + + var response = await http + .get(Uri.parse(url), headers: { + 'Authorization': 'Bearer $accessToken', + }); + + if (response.statusCode == 200) { + Map responseData = jsonDecode(response.body); + return _getMusicsFromResponse(responseData['tracks']); + } else { + throw Exception( + 'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}'); + } + } + } diff --git a/Sources/justMUSIC/test/Music_test.dart b/Sources/justMUSIC/test/Music_test.dart index baf3aaa..f98529a 100644 --- a/Sources/justMUSIC/test/Music_test.dart +++ b/Sources/justMUSIC/test/Music_test.dart @@ -57,4 +57,26 @@ Future main() async { } } + print('\nPlaylist Musics :'); + + List playlistMusics = await musicVM.getMusicsWithPlaylistId('37i9dQZF1DX1X23oiQRTB5'); + for (Music m in playlistMusics) { + print("id : ${m.id.toString()}, cover : ${m.cover}, title : ${m.title}"); + print("date : ${m.date.toString()}, preview : ${m.previewUrl}, duration : ${m.duration}, explicit : ${m.explicit}"); + for (Artist a in m.artists) { + print("id : ${a.id}, name : ${a.name}"); + } + } + + print('\nMusics With Ids :'); + + List musicsIds = await musicVM.getMusicsWithIds(['6D1HiF2e3Z0F8FwQ5uLxwn','6IGg7qsBvA5xbrwz3MNHWK']); + for (Music m in musicsIds) { + print("id : ${m.id.toString()}, cover : ${m.cover}, title : ${m.title}"); + print("date : ${m.date.toString()}, preview : ${m.previewUrl}, duration : ${m.duration}, explicit : ${m.explicit}"); + for (Artist a in m.artists) { + print("id : ${a.id}, name : ${a.name}"); + } + } + } From 53c9f33c65ab8922bc52c1d1e78b5262ca8a0d1b Mon Sep 17 00:00:00 2001 From: Lucas Delanier Date: Sat, 29 Jul 2023 21:19:38 +0200 Subject: [PATCH 02/16] manage multiple song playing --- .../lib/components/music_list_component.dart | 17 ++++++-- .../lib/components/play_button_component.dart | 39 ++++++++++--------- Sources/justMUSIC/lib/main.dart | 2 + Sources/justMUSIC/lib/model/Music.dart | 13 +++++++ Sources/justMUSIC/pubspec.lock | 34 ++++++++-------- 5 files changed, 66 insertions(+), 39 deletions(-) diff --git a/Sources/justMUSIC/lib/components/music_list_component.dart b/Sources/justMUSIC/lib/components/music_list_component.dart index c92bba1..82cea64 100644 --- a/Sources/justMUSIC/lib/components/music_list_component.dart +++ b/Sources/justMUSIC/lib/components/music_list_component.dart @@ -6,9 +6,15 @@ import '../model/Music.dart'; class MusicListComponent extends StatelessWidget { final Music music; + final bool playing; + final int index; + final Function(int) selectMusic; const MusicListComponent({ Key? key, required this.music, + required this.playing, + required this.selectMusic, + required this.index, }) : super(key: key); @override @@ -90,9 +96,14 @@ class MusicListComponent extends StatelessWidget { ), ), Spacer(), - PlayButtonComponent( - urlPreview: music.previewUrl, - ) + music.previewUrl != null + ? PlayButtonComponent( + music: music, + callback: selectMusic, + playing: playing, + index: index, + ) + : Container() ], ), ); diff --git a/Sources/justMUSIC/lib/components/play_button_component.dart b/Sources/justMUSIC/lib/components/play_button_component.dart index 5c3c2e2..3b1f77a 100644 --- a/Sources/justMUSIC/lib/components/play_button_component.dart +++ b/Sources/justMUSIC/lib/components/play_button_component.dart @@ -3,9 +3,19 @@ import 'package:flutter/Material.dart'; import 'package:flutter_animated_play_button/flutter_animated_play_button.dart'; import 'package:ionicons/ionicons.dart'; +import '../model/Music.dart'; + class PlayButtonComponent extends StatefulWidget { - final String? urlPreview; - const PlayButtonComponent({Key? key, required this.urlPreview}) + final Music music; + final Function callback; + final int index; + bool playing; + PlayButtonComponent( + {Key? key, + required this.music, + required this.callback, + required this.playing, + required this.index}) : super(key: key); @override @@ -13,13 +23,12 @@ class PlayButtonComponent extends StatefulWidget { } class _PlayButtonComponentState extends State { - bool isPlaying = true; final player = AudioPlayer(); void switchStatePlaying() { setState(() { - isPlaying = !isPlaying; + widget.playing = !widget.playing; }); - stopSong(); + widget.music.stopSong(); } @override @@ -32,12 +41,14 @@ class _PlayButtonComponentState extends State { @override Widget build(BuildContext context) { - if (!isPlaying) { - playSong(); + if (widget.playing) { + widget.music.playSong(); } else {} - return isPlaying + return !widget.playing ? GestureDetector( - onTap: switchStatePlaying, + onTap: () { + widget.callback(widget.index); + }, child: Container( width: 30, height: 30, @@ -59,14 +70,4 @@ class _PlayButtonComponentState extends State { ), )); } - - Future playSong() async { - if (widget.urlPreview != null) { - await player.play(UrlSource(widget.urlPreview ?? "")); - } - } - - Future stopSong() async { - await player.stop(); - } } diff --git a/Sources/justMUSIC/lib/main.dart b/Sources/justMUSIC/lib/main.dart index 1203f32..e7d6cea 100644 --- a/Sources/justMUSIC/lib/main.dart +++ b/Sources/justMUSIC/lib/main.dart @@ -1,3 +1,4 @@ +import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; @@ -18,6 +19,7 @@ void main() { class MyApp extends StatelessWidget { static UserViewModel userViewModel = UserViewModel(); static MusicViewModel musicViewModel = MusicViewModel(); + static AudioPlayer audioPlayer = AudioPlayer(); const MyApp({super.key}); diff --git a/Sources/justMUSIC/lib/model/Music.dart b/Sources/justMUSIC/lib/model/Music.dart index 367d6a6..711b10a 100644 --- a/Sources/justMUSIC/lib/model/Music.dart +++ b/Sources/justMUSIC/lib/model/Music.dart @@ -1,4 +1,7 @@ +import 'package:audioplayers/audioplayers.dart'; + import 'Artist.dart'; +import '../main.dart'; class Music { final String _id; @@ -58,4 +61,14 @@ class Music { set artists(List value) { _artists = value; } + + Future playSong() async { + if (previewUrl != null) { + await MyApp.audioPlayer.play(UrlSource(previewUrl!)); + } + } + + Future stopSong() async { + await MyApp.audioPlayer.stop(); + } } diff --git a/Sources/justMUSIC/pubspec.lock b/Sources/justMUSIC/pubspec.lock index 685a4a9..706cf83 100644 --- a/Sources/justMUSIC/pubspec.lock +++ b/Sources/justMUSIC/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" audioplayers: dependency: "direct main" description: @@ -85,10 +85,10 @@ packages: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" circular_reveal_animation: dependency: "direct main" description: @@ -109,10 +109,10 @@ packages: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.17.1" crypto: dependency: transitive description: @@ -268,10 +268,10 @@ packages: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.7" lints: dependency: transitive description: @@ -284,10 +284,10 @@ packages: dependency: transitive description: name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.13" + version: "0.12.15" material_color_utilities: dependency: transitive description: @@ -300,10 +300,10 @@ packages: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" modal_bottom_sheet: dependency: "direct main" description: @@ -316,10 +316,10 @@ packages: dependency: transitive description: name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.8.3" path_provider: dependency: transitive description: @@ -449,10 +449,10 @@ packages: dependency: transitive description: name: test_api - sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "0.5.1" text_scroll: dependency: "direct main" description: @@ -518,5 +518,5 @@ packages: source: hosted version: "1.1.0" sdks: - dart: ">=2.18.2 <3.0.0" + dart: ">=3.0.0-0 <4.0.0" flutter: ">=3.3.0" From 03ac2c1d78a818610d3ac6d15cf1b8aa5b624ae0 Mon Sep 17 00:00:00 2001 From: Lucas Delanier Date: Sat, 29 Jul 2023 22:56:51 +0200 Subject: [PATCH 03/16] fix comment --- .idea/libraries/Dart_Packages.xml | 268 +++++++++++++------------ Sources/justMUSIC/android/build.gradle | 2 +- Sources/justMUSIC/lib/main.dart | 1 + Sources/justMUSIC/pubspec.lock | 34 ++-- 4 files changed, 157 insertions(+), 148 deletions(-) diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 2e78728..12381d1 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -5,526 +5,534 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Sources/justMUSIC/android/build.gradle b/Sources/justMUSIC/android/build.gradle index 83ae220..3cdaac9 100644 --- a/Sources/justMUSIC/android/build.gradle +++ b/Sources/justMUSIC/android/build.gradle @@ -26,6 +26,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/Sources/justMUSIC/lib/main.dart b/Sources/justMUSIC/lib/main.dart index 1203f32..c5adc55 100644 --- a/Sources/justMUSIC/lib/main.dart +++ b/Sources/justMUSIC/lib/main.dart @@ -27,6 +27,7 @@ class MyApp extends StatelessWidget { SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); Paint.enableDithering = true; return ScreenUtilInit( + useInheritedMediaQuery: true, builder: (context, child) { return MaterialApp( routes: { diff --git a/Sources/justMUSIC/pubspec.lock b/Sources/justMUSIC/pubspec.lock index 685a4a9..706cf83 100644 --- a/Sources/justMUSIC/pubspec.lock +++ b/Sources/justMUSIC/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" audioplayers: dependency: "direct main" description: @@ -85,10 +85,10 @@ packages: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" circular_reveal_animation: dependency: "direct main" description: @@ -109,10 +109,10 @@ packages: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.17.1" crypto: dependency: transitive description: @@ -268,10 +268,10 @@ packages: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.7" lints: dependency: transitive description: @@ -284,10 +284,10 @@ packages: dependency: transitive description: name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.13" + version: "0.12.15" material_color_utilities: dependency: transitive description: @@ -300,10 +300,10 @@ packages: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" modal_bottom_sheet: dependency: "direct main" description: @@ -316,10 +316,10 @@ packages: dependency: transitive description: name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.8.3" path_provider: dependency: transitive description: @@ -449,10 +449,10 @@ packages: dependency: transitive description: name: test_api - sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "0.5.1" text_scroll: dependency: "direct main" description: @@ -518,5 +518,5 @@ packages: source: hosted version: "1.1.0" sdks: - dart: ">=2.18.2 <3.0.0" + dart: ">=3.0.0-0 <4.0.0" flutter: ">=3.3.0" From 1637aaadfbb8471fa8bb51b3ebf686459be5dfb9 Mon Sep 17 00:00:00 2001 From: Lucas Delanier Date: Sun, 30 Jul 2023 00:38:53 +0200 Subject: [PATCH 04/16] fix playing song --- Sources/justMUSIC/android/build.gradle | 2 +- .../lib/components/music_list_component.dart | 6 ++-- .../lib/components/play_button_component.dart | 21 +++++------- .../lib/screens/search_song_screen.dart | 33 +++++++++++++++++-- 4 files changed, 44 insertions(+), 18 deletions(-) diff --git a/Sources/justMUSIC/android/build.gradle b/Sources/justMUSIC/android/build.gradle index 83ae220..3cdaac9 100644 --- a/Sources/justMUSIC/android/build.gradle +++ b/Sources/justMUSIC/android/build.gradle @@ -26,6 +26,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/Sources/justMUSIC/lib/components/music_list_component.dart b/Sources/justMUSIC/lib/components/music_list_component.dart index 82cea64..9a777da 100644 --- a/Sources/justMUSIC/lib/components/music_list_component.dart +++ b/Sources/justMUSIC/lib/components/music_list_component.dart @@ -8,12 +8,12 @@ class MusicListComponent extends StatelessWidget { final Music music; final bool playing; final int index; - final Function(int) selectMusic; + final Function(int) callback; const MusicListComponent({ Key? key, required this.music, required this.playing, - required this.selectMusic, + required this.callback, required this.index, }) : super(key: key); @@ -99,7 +99,7 @@ class MusicListComponent extends StatelessWidget { music.previewUrl != null ? PlayButtonComponent( music: music, - callback: selectMusic, + callback: callback, playing: playing, index: index, ) diff --git a/Sources/justMUSIC/lib/components/play_button_component.dart b/Sources/justMUSIC/lib/components/play_button_component.dart index 3b1f77a..9c4ebb0 100644 --- a/Sources/justMUSIC/lib/components/play_button_component.dart +++ b/Sources/justMUSIC/lib/components/play_button_component.dart @@ -3,6 +3,7 @@ import 'package:flutter/Material.dart'; import 'package:flutter_animated_play_button/flutter_animated_play_button.dart'; import 'package:ionicons/ionicons.dart'; +import '../main.dart'; import '../model/Music.dart'; class PlayButtonComponent extends StatefulWidget { @@ -24,29 +25,21 @@ class PlayButtonComponent extends StatefulWidget { class _PlayButtonComponentState extends State { final player = AudioPlayer(); - void switchStatePlaying() { - setState(() { - widget.playing = !widget.playing; - }); - widget.music.stopSong(); - } @override void initState() { - player.onPlayerComplete.listen((event) { - switchStatePlaying(); + MyApp.audioPlayer.onPlayerComplete.listen((event) { + widget.callback(widget.index); }); super.initState(); } @override Widget build(BuildContext context) { - if (widget.playing) { - widget.music.playSong(); - } else {} return !widget.playing ? GestureDetector( onTap: () { + widget.music.playSong(); widget.callback(widget.index); }, child: Container( @@ -59,7 +52,11 @@ class _PlayButtonComponentState extends State { )), ) : GestureDetector( - onTap: switchStatePlaying, + onTap: () { + widget.music.stopSong(); + + widget.callback(widget.index); + }, child: Container( width: 30, height: 30, diff --git a/Sources/justMUSIC/lib/screens/search_song_screen.dart b/Sources/justMUSIC/lib/screens/search_song_screen.dart index 30b1757..1042b6a 100644 --- a/Sources/justMUSIC/lib/screens/search_song_screen.dart +++ b/Sources/justMUSIC/lib/screens/search_song_screen.dart @@ -20,6 +20,7 @@ class SearchSongScreen extends StatefulWidget { class _SearchSongScreenState extends State { final ScrollController _scrollController = ScrollController(); final TextEditingController _textEditingController = TextEditingController(); + int? playingIndex; Future resetFullScreen() async { await SystemChannels.platform.invokeMethod( @@ -62,6 +63,18 @@ class _SearchSongScreenState extends State { List filteredData = []; + void playMusic(int index) { + if (playingIndex == index) { + setState(() { + playingIndex = null; + }); + } else { + setState(() { + playingIndex = index; + }); + } + } + @override Widget build(BuildContext context) { double screenHeight = MediaQuery.of(context).size.height; @@ -104,7 +117,7 @@ class _SearchSongScreenState extends State { controller: _textEditingController, keyboardAppearance: Brightness.dark, onEditingComplete: resetFullScreen, - onChanged: (value) async { + onSubmitted: (value) async { if (_textEditingController.text.isEmpty) { } else if (value == " ") { print("popular"); @@ -155,9 +168,25 @@ class _SearchSongScreenState extends State { controller: _scrollController, 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 Padding( padding: const EdgeInsets.symmetric(horizontal: 20), - child: MusicListComponent(music: filteredData[index]), + child: MusicListComponent( + music: filteredData[index], + playing: false, + callback: playMusic, + index: index, + ), ); }), )) From a03decc7d9acf522b5e646e531b44eb85dcc2bf7 Mon Sep 17 00:00:00 2001 From: Lucas Delanier Date: Sun, 30 Jul 2023 01:37:46 +0200 Subject: [PATCH 05/16] fix playing song --- .../lib/components/music_list_component.dart | 12 ++++++---- Sources/justMUSIC/lib/model/Music.dart | 6 ++--- .../justMUSIC/lib/screens/feed_screen.dart | 7 +++++- .../lib/view_model/MusicViewModel.dart | 23 ++++++++++--------- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/Sources/justMUSIC/lib/components/music_list_component.dart b/Sources/justMUSIC/lib/components/music_list_component.dart index 9a777da..1cbc516 100644 --- a/Sources/justMUSIC/lib/components/music_list_component.dart +++ b/Sources/justMUSIC/lib/components/music_list_component.dart @@ -77,11 +77,13 @@ class MusicListComponent extends StatelessWidget { intervalSpaces: 10, ), )), - Icon( - Icons.explicit, - color: Colors.grey.withOpacity(0.7), - size: 17, - ), + music.explicit + ? Icon( + Icons.explicit, + color: Colors.grey.withOpacity(0.7), + size: 17, + ) + : Container(), ], ), ScrollConfiguration( diff --git a/Sources/justMUSIC/lib/model/Music.dart b/Sources/justMUSIC/lib/model/Music.dart index 711b10a..ed9d9f4 100644 --- a/Sources/justMUSIC/lib/model/Music.dart +++ b/Sources/justMUSIC/lib/model/Music.dart @@ -8,7 +8,7 @@ class Music { String? _title; String? _cover; String? _previewUrl; - DateTime? _date; + int? _date; double? _duration; bool _explicit = false; List _artists; @@ -38,9 +38,9 @@ class Music { _previewUrl = value; } - DateTime? get date => _date; + int? get date => _date; - set date(DateTime? value) { + set date(int? value) { _date = value; } diff --git a/Sources/justMUSIC/lib/screens/feed_screen.dart b/Sources/justMUSIC/lib/screens/feed_screen.dart index 3e2c6ea..afc113e 100644 --- a/Sources/justMUSIC/lib/screens/feed_screen.dart +++ b/Sources/justMUSIC/lib/screens/feed_screen.dart @@ -7,6 +7,7 @@ import 'package:google_fonts/google_fonts.dart'; import '../components/comment_component.dart'; import '../components/post_component.dart'; import '../components/top_nav_bar_component.dart'; +import '../main.dart'; import '../values/constants.dart'; class FeedScreen extends StatefulWidget { @@ -88,7 +89,7 @@ class _FeedScreenState extends State shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(20), topRight: Radius.circular(20))), - builder: ((context) { + builder: ((BuildContext context) { return GestureDetector( onTap: () { FocusScopeNode currentFocus = FocusScope.of(context); @@ -235,6 +236,10 @@ class _FeedScreenState extends State ); } + void _onModalClosed() { + print("modal closed"); + } + @override Widget build(BuildContext context) { return Scaffold( diff --git a/Sources/justMUSIC/lib/view_model/MusicViewModel.dart b/Sources/justMUSIC/lib/view_model/MusicViewModel.dart index e50285e..8b5dc4a 100644 --- a/Sources/justMUSIC/lib/view_model/MusicViewModel.dart +++ b/Sources/justMUSIC/lib/view_model/MusicViewModel.dart @@ -32,7 +32,7 @@ class MusicViewModel { responseData['name'], responseData['album']['images'][0]['url'], responseData['preview_url'], - DateTime.parse(responseData['album']['release_date']), + int.parse(responseData['album']['release_date'].split('-')[0]), responseData['duration_ms'] / 1000, responseData['explicit'], artists); @@ -50,14 +50,12 @@ class MusicViewModel { return Artist(artist['id'], artist['name'], ''); })); - DateTime releaseDate = DateTime.parse(track['album']['release_date']); - musics.add(Music( track['id'], track['name'], track['album']['images'][0]['url'], track['preview_url'], - releaseDate, + int.parse(track['album']['release_date'].split('-')[0]), track['duration_ms'] / 1000, track['explicit'], artists)); @@ -198,22 +196,27 @@ class MusicViewModel { List tracks = responseData['tracks']['items']; for (var track in tracks) { - List artists = List.from(track['track']['artists'].map((artist) { + List artists = + List.from(track['track']['artists'].map((artist) { return Artist(artist['id'], artist['name'], ''); })); - DateTime releaseDate = DateTime.parse(track['track']['album']['release_date']); + DateTime releaseDate = + DateTime.parse(track['track']['album']['release_date']); musics.add(Music( track['track']['id'], track['track']['name'], track['track']['album']['images'][0]['url'], track['track']['preview_url'], - releaseDate, + int.parse(responseData['album']['release_date'].split('-')[0]), track['track']['duration_ms'] / 1000, track['track']['explicit'], artists)); } + /* + List musics = _getMusicsFromResponse(responseData['tracks']['items']); + }*/ return musics; } else { @@ -225,7 +228,7 @@ class MusicViewModel { Future> getMusicsWithIds(List ids, {String market = "FR"}) async { var accessToken = await _token.getAccessToken(); - String url = API_URL+'/tracks?market=$market&ids='; + String url = API_URL + '/tracks?market=$market&ids='; if (ids.length == 0) return []; @@ -233,8 +236,7 @@ class MusicViewModel { print(url); - var response = await http - .get(Uri.parse(url), headers: { + var response = await http.get(Uri.parse(url), headers: { 'Authorization': 'Bearer $accessToken', }); @@ -246,5 +248,4 @@ class MusicViewModel { 'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}'); } } - } From 1abcd1a5a9f51f87561564c93501e45bb06242ae Mon Sep 17 00:00:00 2001 From: Lucas Delanier Date: Sun, 30 Jul 2023 02:44:01 +0200 Subject: [PATCH 06/16] fix playing song --- Sources/justMUSIC/android/build.gradle | 2 +- .../lib/components/buttonPostComponent.dart | 15 ++ .../components/editable_post_component.dart | 129 +++++++++++----- .../justMUSIC/lib/screens/feed_screen.dart | 1 + .../justMUSIC/lib/screens/post_screen.dart | 5 +- Sources/justMUSIC/lib/values/constants.dart | 1 + Sources/justMUSIC/pubspec.lock | 144 ++++++++++++++++-- Sources/justMUSIC/pubspec.yaml | 1 + 8 files changed, 239 insertions(+), 59 deletions(-) create mode 100644 Sources/justMUSIC/lib/components/buttonPostComponent.dart diff --git a/Sources/justMUSIC/android/build.gradle b/Sources/justMUSIC/android/build.gradle index 3cdaac9..36cfe3f 100644 --- a/Sources/justMUSIC/android/build.gradle +++ b/Sources/justMUSIC/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.10' + ext.kotlin_version = '1.9.0' repositories { google() mavenCentral() diff --git a/Sources/justMUSIC/lib/components/buttonPostComponent.dart b/Sources/justMUSIC/lib/components/buttonPostComponent.dart new file mode 100644 index 0000000..10be7f9 --- /dev/null +++ b/Sources/justMUSIC/lib/components/buttonPostComponent.dart @@ -0,0 +1,15 @@ +import 'package:flutter/Material.dart'; + +import '../values/constants.dart'; + +class ButtonPostComponent extends StatelessWidget { + const ButtonPostComponent({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.fromLTRB(20, 5, 20, 5), + color: postbutton, + ); + } +} diff --git a/Sources/justMUSIC/lib/components/editable_post_component.dart b/Sources/justMUSIC/lib/components/editable_post_component.dart index b25b1c8..234974a 100644 --- a/Sources/justMUSIC/lib/components/editable_post_component.dart +++ b/Sources/justMUSIC/lib/components/editable_post_component.dart @@ -1,71 +1,116 @@ +import 'dart:io'; + import 'package:auto_size_text/auto_size_text.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:justmusic/values/constants.dart'; class EditablePostComponent extends StatefulWidget { - const EditablePostComponent({Key? key}) : super(key: key); + final Function callback; + const EditablePostComponent({Key? key, required this.callback}) + : super(key: key); @override State createState() => _EditablePostComponentState(); } class _EditablePostComponentState extends State { + final ImagePicker picker = ImagePicker(); + File? image; + + Future pickImage() async { + try { + final image = await ImagePicker().pickImage(source: ImageSource.gallery); + if (image == null) return; + final imageTemp = File(image.path); + setState(() { + this.image = imageTemp; + }); + } on PlatformException catch (e) { + print('Failed to pick image: $e'); + } + } + @override Widget build(BuildContext context) { return ClipRRect( borderRadius: BorderRadius.circular(25), child: Container( - constraints: BoxConstraints(maxWidth: 400), + constraints: BoxConstraints(maxWidth: 400, minHeight: 500), width: double.infinity, color: warningBttnColor, - child: Column( + child: Stack( + alignment: Alignment.topCenter, 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: const Image( - image: AssetImage("assets/images/exemple_cover.png"), - fit: BoxFit.cover, - width: double.infinity, + 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, + ), + ), ), + )), + 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, + ), + 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, + ), + ], ), ), ), - 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( - image: AssetImage("assets/images/camera_icon.png"), - width: 30, - ), - AutoSizeText( - "10 Juil. 2023", - style: GoogleFonts.plusJakartaSans( - color: Colors.white, fontSize: 13.sp), - maxFontSize: 20, - ), - ], - ), - ), Padding( padding: EdgeInsets.fromLTRB(15, 0, 10, 25), child: SizedBox( diff --git a/Sources/justMUSIC/lib/screens/feed_screen.dart b/Sources/justMUSIC/lib/screens/feed_screen.dart index afc113e..a369c4c 100644 --- a/Sources/justMUSIC/lib/screens/feed_screen.dart +++ b/Sources/justMUSIC/lib/screens/feed_screen.dart @@ -4,6 +4,7 @@ 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 '../components/comment_component.dart'; import '../components/post_component.dart'; import '../components/top_nav_bar_component.dart'; diff --git a/Sources/justMUSIC/lib/screens/post_screen.dart b/Sources/justMUSIC/lib/screens/post_screen.dart index e6a625b..51b2a27 100644 --- a/Sources/justMUSIC/lib/screens/post_screen.dart +++ b/Sources/justMUSIC/lib/screens/post_screen.dart @@ -103,10 +103,7 @@ class _PostScreenState extends State SizedBox( height: 100.h, ), - GestureDetector( - onTap: openDetailPost, - child: EditablePostComponent(), - ), + EditablePostComponent(callback: openDetailPost), SizedBox( height: 40.h, ), diff --git a/Sources/justMUSIC/lib/values/constants.dart b/Sources/justMUSIC/lib/values/constants.dart index f29ef36..e3512f9 100644 --- a/Sources/justMUSIC/lib/values/constants.dart +++ b/Sources/justMUSIC/lib/values/constants.dart @@ -20,6 +20,7 @@ const bgAppBar = Color(0xFF181818); const grayText = Color(0xFF898989); const settingColor = Color(0xFF232323); const searchBarColor = Color(0xFF161616); +const postbutton = Color(0xFF1B1B1B); // All constants important too us const defaultPadding = 30.0; diff --git a/Sources/justMUSIC/pubspec.lock b/Sources/justMUSIC/pubspec.lock index 706cf83..afce498 100644 --- a/Sources/justMUSIC/pubspec.lock +++ b/Sources/justMUSIC/pubspec.lock @@ -113,14 +113,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.17.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9" + url: "https://pub.dev" + source: hosted + version: "0.3.3+4" crypto: dependency: transitive description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" cupertino_icons: dependency: "direct main" description: @@ -161,6 +169,38 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.4" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "770eb1ab057b5ae4326d1c24cc57710758b9a46026349d021d6311bd27580046" + url: "https://pub.dev" + source: hosted + version: "0.9.2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "4ada532862917bf16e3adb3891fe3a5917a58bae03293e497082203a80909412" + url: "https://pub.dev" + source: hosted + version: "0.9.3+1" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: "412705a646a0ae90f33f37acfae6a0f7cbc02222d6cd34e479421c3e74d3853c" + url: "https://pub.dev" + source: hosted + version: "2.6.0" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "1372760c6b389842b77156203308940558a2817360154084368608413835fc26" + url: "https://pub.dev" + source: hosted + version: "0.9.3" flutter: dependency: "direct main" description: flutter @@ -182,14 +222,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.2" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "950e77c2bbe1692bc0874fc7fb491b96a4dc340457f4ea1641443d0a6c1ea360" + url: "https://pub.dev" + source: hosted + version: "2.0.15" flutter_screenutil: dependency: "direct main" description: name: flutter_screenutil - sha256: "0a122936b450324cbdfd51be0819cc6fcebb093eb65585e9cd92263f7a1a8a39" + sha256: "1b61f8c4cbf965104b6ca7160880ff1af6755aad7fec70b58444245132453745" url: "https://pub.dev" source: hosted - version: "5.7.0" + version: "5.8.4" flutter_signin_button: dependency: "direct main" description: @@ -244,10 +292,10 @@ packages: dependency: "direct main" description: name: http - sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" url: "https://pub.dev" source: hosted - version: "0.13.5" + version: "0.13.6" http_parser: dependency: transitive description: @@ -256,6 +304,70 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "6296e98782726d37f59663f0727d0e978eee1ced1ffed45ccaba591786a7f7b3" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "8179b54039b50eee561676232304f487602e2950ffb3e8995ed9034d6505ca34" + url: "https://pub.dev" + source: hosted + version: "0.8.7+4" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "869fe8a64771b7afbc99fc433a5f7be2fea4d1cb3d7c11a48b6b579eb9c797f0" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: b3e2f21feb28b24dd73a35d7ad6e83f568337c70afab5eabac876e23803f264b + url: "https://pub.dev" + source: hosted + version: "0.8.8" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "02cbc21fe1706b97942b575966e5fbbeaac535e76deef70d3a242e4afb857831" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: cee2aa86c56780c13af2c77b5f2f72973464db204569e1ba2dd744459a065af4 + url: "https://pub.dev" + source: hosted + version: "0.2.1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: c1134543ae2187e85299996d21c526b2f403854994026d575ae4cf30d7bb2a32 + url: "https://pub.dev" + source: hosted + version: "2.9.0" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: c3066601ea42113922232c7b7b3330a2d86f029f685bba99d82c30e799914952 + url: "https://pub.dev" + source: hosted + version: "0.2.1" ionicons: dependency: "direct main" description: @@ -276,10 +388,10 @@ packages: dependency: transitive description: name: lints - sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.1.1" matcher: dependency: transitive description: @@ -304,6 +416,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" modal_bottom_sheet: dependency: "direct main" description: @@ -497,10 +617,10 @@ packages: dependency: transitive description: name: win32 - sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c" + sha256: f2add6fa510d3ae152903412227bda57d0d5a8da61d2c39c1fb022c9429a41c0 url: "https://pub.dev" source: hosted - version: "4.1.4" + version: "5.0.6" xdg_directories: dependency: transitive description: @@ -518,5 +638,5 @@ packages: source: hosted version: "1.1.0" sdks: - dart: ">=3.0.0-0 <4.0.0" - flutter: ">=3.3.0" + dart: ">=3.0.0 <4.0.0" + flutter: ">=3.10.0" diff --git a/Sources/justMUSIC/pubspec.yaml b/Sources/justMUSIC/pubspec.yaml index 1a52f91..13380a9 100644 --- a/Sources/justMUSIC/pubspec.yaml +++ b/Sources/justMUSIC/pubspec.yaml @@ -53,6 +53,7 @@ dependencies: audioplayers: ^4.1.0 ionicons: ^0.2.2 top_snackbar_flutter: ^3.1.0 + image_picker: ^1.0.1 dev_dependencies: flutter_test: From b520ad520479258708e8a90358673a2c755bf96f Mon Sep 17 00:00:00 2001 From: Lucas Delanier Date: Sun, 30 Jul 2023 05:15:15 +0200 Subject: [PATCH 07/16] start select image --- .../lib/components/buttonPostComponent.dart | 117 +++++++- .../components/editable_post_component.dart | 253 +++++++++++++----- .../lib/components/music_list_component.dart | 2 +- .../lib/components/play_button_component.dart | 8 +- .../justMUSIC/lib/screens/post_screen.dart | 66 ++--- .../lib/screens/search_song_screen.dart | 49 ++-- Sources/justMUSIC/lib/values/constants.dart | 1 + Sources/justMUSIC/pubspec.lock | 32 +++ Sources/justMUSIC/pubspec.yaml | 4 + 9 files changed, 406 insertions(+), 126 deletions(-) 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: From 5b10bf3324cf7339a3947e433b151a06df125734 Mon Sep 17 00:00:00 2001 From: emkartal1 Date: Sun, 30 Jul 2023 14:31:16 +0200 Subject: [PATCH 08/16] Fix MusicViewModel error --- Sources/justMUSIC/lib/view_model/MusicViewModel.dart | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Sources/justMUSIC/lib/view_model/MusicViewModel.dart b/Sources/justMUSIC/lib/view_model/MusicViewModel.dart index 8b5dc4a..5d9570d 100644 --- a/Sources/justMUSIC/lib/view_model/MusicViewModel.dart +++ b/Sources/justMUSIC/lib/view_model/MusicViewModel.dart @@ -201,22 +201,16 @@ class MusicViewModel { return Artist(artist['id'], artist['name'], ''); })); - DateTime releaseDate = - DateTime.parse(track['track']['album']['release_date']); - musics.add(Music( track['track']['id'], track['track']['name'], track['track']['album']['images'][0]['url'], track['track']['preview_url'], - int.parse(responseData['album']['release_date'].split('-')[0]), + int.parse(track['track']['album']['release_date'].split('-')[0]), track['track']['duration_ms'] / 1000, track['track']['explicit'], artists)); } - /* - List musics = _getMusicsFromResponse(responseData['tracks']['items']); - }*/ return musics; } else { From f238c1cf0f95e233dded1cd136dbaaa825db433d Mon Sep 17 00:00:00 2001 From: Lucas Delanier Date: Sun, 30 Jul 2023 16:12:34 +0200 Subject: [PATCH 09/16] imitate IOS scroll on every plateform --- Sources/justMUSIC/lib/screens/feed_screen.dart | 10 ++++------ Sources/justMUSIC/lib/screens/profile_screen.dart | 2 ++ Sources/justMUSIC/lib/screens/search_song_screen.dart | 2 ++ 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Sources/justMUSIC/lib/screens/feed_screen.dart b/Sources/justMUSIC/lib/screens/feed_screen.dart index a369c4c..97c42e2 100644 --- a/Sources/justMUSIC/lib/screens/feed_screen.dart +++ b/Sources/justMUSIC/lib/screens/feed_screen.dart @@ -4,11 +4,9 @@ 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 '../components/comment_component.dart'; import '../components/post_component.dart'; import '../components/top_nav_bar_component.dart'; -import '../main.dart'; import '../values/constants.dart'; class FeedScreen extends StatefulWidget { @@ -124,6 +122,8 @@ class _FeedScreenState extends State padding: EdgeInsets.only( left: defaultPadding, right: defaultPadding), child: SingleChildScrollView( + physics: BouncingScrollPhysics( + decelerationRate: ScrollDecelerationRate.fast), child: Wrap( // to apply margin in the main axis of the wrap runSpacing: 10, @@ -237,10 +237,6 @@ class _FeedScreenState extends State ); } - void _onModalClosed() { - print("modal closed"); - } - @override Widget build(BuildContext context) { return Scaffold( @@ -252,6 +248,8 @@ class _FeedScreenState extends State animation: animation, centerOffset: Offset(30.w, -100), child: SingleChildScrollView( + physics: const BouncingScrollPhysics( + decelerationRate: ScrollDecelerationRate.fast), child: SizedBox( width: double.infinity, child: Align( diff --git a/Sources/justMUSIC/lib/screens/profile_screen.dart b/Sources/justMUSIC/lib/screens/profile_screen.dart index 896cd91..eead70d 100644 --- a/Sources/justMUSIC/lib/screens/profile_screen.dart +++ b/Sources/justMUSIC/lib/screens/profile_screen.dart @@ -60,6 +60,8 @@ class _ProfileScreenState extends State { height: double.infinity, color: bgColor, child: SingleChildScrollView( + physics: const BouncingScrollPhysics( + decelerationRate: ScrollDecelerationRate.fast), child: Padding( padding: const EdgeInsets.symmetric(horizontal: settingPadding), child: Column( diff --git a/Sources/justMUSIC/lib/screens/search_song_screen.dart b/Sources/justMUSIC/lib/screens/search_song_screen.dart index 8ef2ecc..02dc64a 100644 --- a/Sources/justMUSIC/lib/screens/search_song_screen.dart +++ b/Sources/justMUSIC/lib/screens/search_song_screen.dart @@ -166,6 +166,8 @@ class _SearchSongScreenState extends State { child: ScrollConfiguration( behavior: ScrollBehavior().copyWith(scrollbars: true), child: ListView.builder( + physics: const BouncingScrollPhysics( + decelerationRate: ScrollDecelerationRate.fast), controller: _scrollController, itemCount: filteredData.length, itemBuilder: (context, index) { From ddda7ab779de330abf8599202fcb108423f21181 Mon Sep 17 00:00:00 2001 From: Lucas Delanier Date: Sun, 30 Jul 2023 17:53:36 +0200 Subject: [PATCH 10/16] =?UTF-8?q?search=20location=20is=20live=20!?= =?UTF-8?q?=F0=9F=8E=89=F0=9F=8E=89=F0=9F=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../android/app/src/debug/AndroidManifest.xml | 1 + .../lib/components/buttonPostComponent.dart | 176 ++++++++++-------- .../lib/components/city_list_component.dart | 45 +++++ .../components/editable_post_component.dart | 80 ++++++-- .../justMUSIC/lib/screens/post_screen.dart | 10 +- .../lib/screens/search_location_screen.dart | 87 +++++++++ Sources/justMUSIC/lib/services/GeoApi.dart | 60 ++++++ Sources/justMUSIC/pubspec.lock | 56 ++++++ Sources/justMUSIC/pubspec.yaml | 2 + 9 files changed, 425 insertions(+), 92 deletions(-) create mode 100644 Sources/justMUSIC/lib/components/city_list_component.dart create mode 100644 Sources/justMUSIC/lib/screens/search_location_screen.dart create mode 100644 Sources/justMUSIC/lib/services/GeoApi.dart diff --git a/Sources/justMUSIC/android/app/src/debug/AndroidManifest.xml b/Sources/justMUSIC/android/app/src/debug/AndroidManifest.xml index 44a649b..04c234b 100644 --- a/Sources/justMUSIC/android/app/src/debug/AndroidManifest.xml +++ b/Sources/justMUSIC/android/app/src/debug/AndroidManifest.xml @@ -5,4 +5,5 @@ to allow setting breakpoints, to provide hot reload, etc. --> + diff --git a/Sources/justMUSIC/lib/components/buttonPostComponent.dart b/Sources/justMUSIC/lib/components/buttonPostComponent.dart index 166f426..28c4587 100644 --- a/Sources/justMUSIC/lib/components/buttonPostComponent.dart +++ b/Sources/justMUSIC/lib/components/buttonPostComponent.dart @@ -1,6 +1,7 @@ import 'package:flutter/Material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:ionicons/ionicons.dart'; +import 'package:tuple/tuple.dart'; import '../values/constants.dart'; @@ -15,54 +16,68 @@ class PhotoPostComponent extends StatelessWidget { 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), - ) - ]), - ) + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Icon( + Ionicons.camera, + size: 15, + color: Colors.white, + ), + SizedBox( + width: 10, + ), + Expanded( + child: Text( + 'Prendre un selfie', + style: GoogleFonts.plusJakartaSans( + color: Colors.white, fontSize: 12), + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), + ) + ]), + )) : 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, - ), - ]), - ); + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Expanded( + child: Text( + "Selfie enregistré", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, fontSize: 12), + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), + ), + 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}) + final Tuple2? location; + const LocationPostComponent( + {Key? key, required this.empty, required this.location}) : super(key: key); @override @@ -73,48 +88,59 @@ class LocationPostComponent extends StatelessWidget { 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), - ) - ]), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Icon( + Icons.location_on, + size: 15, + color: Colors.white, + ), + SizedBox( + width: 10, + ), + Expanded( + child: Text( + 'Ajouter un lieu', + style: GoogleFonts.plusJakartaSans( + color: Colors.white, fontSize: 12), + overflow: TextOverflow.ellipsis, + ), + ) + ])), ) : 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, - ), - ]), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Expanded( + child: Text( + '${location?.item1}, ${location?.item2}', + style: GoogleFonts.plusJakartaSans( + color: Colors.white, fontSize: 12), + overflow: TextOverflow.ellipsis, + ), + ), + SizedBox( + width: 10, + ), + Icon( + Icons.close, + size: 12, + color: Colors.white, + ), + ]), + ), ); } } diff --git a/Sources/justMUSIC/lib/components/city_list_component.dart b/Sources/justMUSIC/lib/components/city_list_component.dart new file mode 100644 index 0000000..a1ef958 --- /dev/null +++ b/Sources/justMUSIC/lib/components/city_list_component.dart @@ -0,0 +1,45 @@ +import 'package:flutter/Material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:justmusic/values/constants.dart'; +import 'package:tuple/tuple.dart'; + +class CityListComponent extends StatelessWidget { + final Tuple2 location; + const CityListComponent({Key? key, required this.location}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Flexible( + child: RichText( + overflow: TextOverflow.ellipsis, + maxLines: 1, + text: TextSpan(children: [ + TextSpan( + text: location.item2 + ", ", + style: GoogleFonts.plusJakartaSans( + color: grayText, + fontWeight: FontWeight.w400, + fontSize: 17), + ), + TextSpan( + text: location.item1, + style: GoogleFonts.plusJakartaSans( + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 17), + ), + ])), + ), + ], + ), + ), + ); + } +} diff --git a/Sources/justMUSIC/lib/components/editable_post_component.dart b/Sources/justMUSIC/lib/components/editable_post_component.dart index dda4c74..f66759f 100644 --- a/Sources/justMUSIC/lib/components/editable_post_component.dart +++ b/Sources/justMUSIC/lib/components/editable_post_component.dart @@ -11,8 +11,10 @@ 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 'package:tuple/tuple.dart'; import '../model/Music.dart'; +import '../screens/search_location_screen.dart'; import 'buttonPostComponent.dart'; class EditablePostComponent extends StatefulWidget { @@ -28,7 +30,27 @@ class _EditablePostComponentState extends State final ImagePicker picker = ImagePicker(); late Animation animation; late AnimationController animationController; + late AnimationController _controller; File? image; + Tuple2? selectedCity; + + @override + void initState() { + _controller = AnimationController( + vsync: this, + duration: const Duration(milliseconds: 400), + ); + animationController = AnimationController( + vsync: this, + duration: Duration(milliseconds: 400), + ); + animation = CurvedAnimation( + parent: animationController, + curve: Curves.easeInOutSine, + ); + animationController.forward(); + super.initState(); + } Future pickImage() async { try { @@ -43,18 +65,34 @@ class _EditablePostComponentState extends State } } - @override - void initState() { - animationController = AnimationController( - vsync: this, - duration: Duration(milliseconds: 400), - ); - animation = CurvedAnimation( - parent: animationController, - curve: Curves.easeInOutSine, + void _selectLocation(Tuple2 location) { + Navigator.pop(context); + setState(() { + selectedCity = location; + }); + } + + void searchLocation() { + showModalBottomSheet( + transitionAnimationController: _controller, + barrierColor: Colors.black.withOpacity(0.7), + backgroundColor: Colors.transparent, + elevation: 1, + constraints: const BoxConstraints( + maxWidth: 600, + ), + isScrollControlled: true, + context: context, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), topRight: Radius.circular(20))), + builder: ((context) { + return ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), topRight: Radius.circular(20)), + child: SearchCityScreen(callback: _selectLocation)); + }), ); - animationController.forward(); - super.initState(); } @override @@ -219,8 +257,14 @@ class _EditablePostComponentState extends State ), Expanded( flex: 5, - child: LocationPostComponent( - empty: true, + child: GestureDetector( + onTap: () { + manageLocation(); + }, + child: LocationPostComponent( + empty: selectedCity == null, + location: selectedCity, + ), ), ), ], @@ -280,4 +324,14 @@ class _EditablePostComponentState extends State pickImage(); } } + + void manageLocation() { + if (selectedCity != null) { + setState(() { + selectedCity = null; + }); + } else { + searchLocation(); + } + } } diff --git a/Sources/justMUSIC/lib/screens/post_screen.dart b/Sources/justMUSIC/lib/screens/post_screen.dart index ecc1051..1f53d8b 100644 --- a/Sources/justMUSIC/lib/screens/post_screen.dart +++ b/Sources/justMUSIC/lib/screens/post_screen.dart @@ -3,6 +3,7 @@ import 'package:flutter/Material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:justmusic/components/back_button.dart'; import 'package:justmusic/screens/search_song_screen.dart'; +import 'package:tuple/tuple.dart'; import '../components/editable_post_component.dart'; import '../components/post_button_component.dart'; import '../model/Music.dart'; @@ -21,6 +22,7 @@ class _PostScreenState extends State late AnimationController _controller; Music? selectedMusic; + Tuple2? selectedCity; @override void initState() { @@ -39,7 +41,7 @@ class _PostScreenState extends State }); } - void openDetailPost() { + void openSearchSong() { showModalBottomSheet( transitionAnimationController: _controller, barrierColor: Colors.black.withOpacity(0.7), @@ -68,11 +70,11 @@ class _PostScreenState extends State resizeToAvoidBottomInset: true, backgroundColor: bgColor, extendBodyBehindAppBar: true, - appBar: PreferredSize( + appBar: const PreferredSize( preferredSize: Size(double.infinity, 80), child: SafeArea( child: Padding( - padding: const EdgeInsets.only( + padding: EdgeInsets.only( left: defaultPadding, right: defaultPadding, top: defaultPadding), @@ -104,7 +106,7 @@ class _PostScreenState extends State height: 100.h, ), GestureDetector( - onTap: openDetailPost, + onTap: openSearchSong, child: EditablePostComponent(music: selectedMusic)), SizedBox( height: 40.h, diff --git a/Sources/justMUSIC/lib/screens/search_location_screen.dart b/Sources/justMUSIC/lib/screens/search_location_screen.dart new file mode 100644 index 0000000..73f6d1a --- /dev/null +++ b/Sources/justMUSIC/lib/screens/search_location_screen.dart @@ -0,0 +1,87 @@ +import 'dart:ui'; + +import 'package:flutter/Material.dart'; + +import '../components/city_list_component.dart'; +import '../services/GeoApi.dart'; +import '../values/constants.dart'; + +class SearchCityScreen extends StatefulWidget { + final Function callback; + const SearchCityScreen({Key? key, required this.callback}) : super(key: key); + + @override + State createState() => _SearchCityScreenState(); +} + +class _SearchCityScreenState extends State { + final ScrollController _scrollController = ScrollController(); + final GeoApi api = GeoApi(); + + @override + Widget build(BuildContext context) { + double screenHeight = MediaQuery.of(context).size.height; + return BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 60.0, + sigmaY: 60.0, + ), + child: Container( + color: bgAppBar.withOpacity(0.5), + height: screenHeight - 50, + padding: const EdgeInsets.only(top: 10), + child: Column( + children: [ + Align( + child: Container( + width: 60, + height: 5, + decoration: BoxDecoration( + color: Color(0xFF3A3A3A).withOpacity(0.6), + borderRadius: BorderRadius.circular(20))), + ), + const SizedBox( + height: 10, + ), + Flexible( + child: ScrollConfiguration( + behavior: ScrollBehavior().copyWith(scrollbars: true), + child: FutureBuilder( + future: api.getNearbyCities(), + builder: + (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + return ListView.builder( + physics: const BouncingScrollPhysics( + decelerationRate: ScrollDecelerationRate.fast), + controller: _scrollController, + itemCount: snapshot.data.length, + itemBuilder: (context, index) { + return InkWell( + onTap: () { + widget.callback(snapshot.data[index]); + }, + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 20), + child: CityListComponent( + location: snapshot.data[index], + ), + )); + }); + } else { + return Center( + child: CircularProgressIndicator( + color: grayColor, + ), + ); + } + }, + ), + )) + ], + ), + ), + ); + } +} diff --git a/Sources/justMUSIC/lib/services/GeoApi.dart b/Sources/justMUSIC/lib/services/GeoApi.dart new file mode 100644 index 0000000..7f203bc --- /dev/null +++ b/Sources/justMUSIC/lib/services/GeoApi.dart @@ -0,0 +1,60 @@ +import 'package:geolocator/geolocator.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; + +import 'package:tuple/tuple.dart'; + +class GeoApi { + final String apiKey = "85a2724ad38b3994c2b7ebe1d239bbff"; + Future>?> getNearbyCities() async { + try { + LocationPermission permission = await Geolocator.checkPermission(); + bool serviceEnabled; + + // Test if location services are enabled. + serviceEnabled = await Geolocator.isLocationServiceEnabled(); + if (!serviceEnabled) { + // Location services are not enabled don't continue + // accessing the position and request users of the + // App to enable the location services. + return Future.error('Location services are disabled.'); + } + + permission = await Geolocator.checkPermission(); + if (permission == LocationPermission.denied) { + permission = await Geolocator.requestPermission(); + if (permission == LocationPermission.denied) { + return Future.error('Location permissions are denied'); + } + } + + if (permission == LocationPermission.deniedForever) { + return Future.error( + 'Location permissions are permanently denied, we cannot request permissions.'); + } + + Position position = await Geolocator.getCurrentPosition( + desiredAccuracy: LocationAccuracy.high); + String apiUrl = + 'http://api.openweathermap.org/data/2.5/find?lat=${position.latitude}&lon=${position.longitude}&cnt=10&appid=$apiKey'; + var response = await http.get(Uri.parse(apiUrl)); + if (response.statusCode == 200) { + var data = json.decode(response.body); + List cities = data['list']; + List> cityInfo = cities.map((city) { + String cityName = city['name'] as String; + String countryName = city['sys']['country'] as String; + return Tuple2(cityName, countryName); + }).toList(); + return cityInfo; + } else { + print('Failed to fetch data'); + } + } catch (e) { + print('Error: $e'); + } + return null; + } +} + +class Tuple {} diff --git a/Sources/justMUSIC/pubspec.lock b/Sources/justMUSIC/pubspec.lock index dfbd0a1..7f77bef 100644 --- a/Sources/justMUSIC/pubspec.lock +++ b/Sources/justMUSIC/pubspec.lock @@ -272,6 +272,54 @@ packages: url: "https://pub.dev" source: hosted version: "9.2.0" + geolocator: + dependency: "direct main" + description: + name: geolocator + sha256: "5c23f3613f50586c0bbb2b8f970240ae66b3bd992088cf60dd5ee2e6f7dde3a8" + url: "https://pub.dev" + source: hosted + version: "9.0.2" + geolocator_android: + dependency: transitive + description: + name: geolocator_android + sha256: b06c72853c993ae533f482d81a12805d7a441f5231d9668718bc7131d7464082 + url: "https://pub.dev" + source: hosted + version: "4.2.0" + geolocator_apple: + dependency: transitive + description: + name: geolocator_apple + sha256: "36527c555f4c425f7d8fa8c7c07d67b78e3ff7590d40448051959e1860c1cfb4" + url: "https://pub.dev" + source: hosted + version: "2.2.7" + geolocator_platform_interface: + dependency: transitive + description: + name: geolocator_platform_interface + sha256: af4d69231452f9620718588f41acc4cb58312368716bfff2e92e770b46ce6386 + url: "https://pub.dev" + source: hosted + version: "4.0.7" + geolocator_web: + dependency: transitive + description: + name: geolocator_web + sha256: f68a122da48fcfff68bbc9846bb0b74ef651afe84a1b1f6ec20939de4d6860e1 + url: "https://pub.dev" + source: hosted + version: "2.1.6" + geolocator_windows: + dependency: transitive + description: + name: geolocator_windows + sha256: f5911c88e23f48b598dd506c7c19eff0e001645bdc03bb6fecb9f4549208354d + url: "https://pub.dev" + source: hosted + version: "0.1.1" google_fonts: dependency: "direct main" description: @@ -621,6 +669,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.0" + tuple: + dependency: "direct main" + description: + name: tuple + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 + url: "https://pub.dev" + source: hosted + version: "2.0.2" typed_data: dependency: transitive description: diff --git a/Sources/justMUSIC/pubspec.yaml b/Sources/justMUSIC/pubspec.yaml index 67c874a..4afb32a 100644 --- a/Sources/justMUSIC/pubspec.yaml +++ b/Sources/justMUSIC/pubspec.yaml @@ -58,6 +58,8 @@ dependencies: pinch_zoom: ^1.0.0 smooth_list_view: ^1.0.4 animated_appear: ^0.0.4 + geolocator: ^9.0.2 + tuple: ^2.0.2 dev_dependencies: flutter_test: From ea101103787dabe4ffafb0232df8824bd5569d19 Mon Sep 17 00:00:00 2001 From: emkartal1 Date: Sun, 30 Jul 2023 18:01:48 +0200 Subject: [PATCH 11/16] Cleaning the code :white_check_mark: --- .../lib/view_model/MusicViewModel.dart | 77 +++++++------------ Sources/justMUSIC/pubspec.lock | 34 ++++---- 2 files changed, 45 insertions(+), 66 deletions(-) diff --git a/Sources/justMUSIC/lib/view_model/MusicViewModel.dart b/Sources/justMUSIC/lib/view_model/MusicViewModel.dart index 5d9570d..d8cc9da 100644 --- a/Sources/justMUSIC/lib/view_model/MusicViewModel.dart +++ b/Sources/justMUSIC/lib/view_model/MusicViewModel.dart @@ -27,41 +27,27 @@ class MusicViewModel { return Artist(artist['id'], artist['name'], ''); })); - return Music( - responseData['id'], - responseData['name'], - responseData['album']['images'][0]['url'], - responseData['preview_url'], - int.parse(responseData['album']['release_date'].split('-')[0]), - responseData['duration_ms'] / 1000, - responseData['explicit'], - artists); + return _getMusicFromResponse(responseData); } else { throw Exception( 'Error retrieving music information : ${response.statusCode} ${response.reasonPhrase}'); } } - List _getMusicsFromResponse(List tracks) { - List musics = []; - - for (var track in tracks) { - List artists = List.from(track['artists'].map((artist) { - return Artist(artist['id'], artist['name'], ''); - })); - - musics.add(Music( - track['id'], - track['name'], - track['album']['images'][0]['url'], - track['preview_url'], - int.parse(track['album']['release_date'].split('-')[0]), - track['duration_ms'] / 1000, - track['explicit'], - artists)); - } - - return musics; + Music _getMusicFromResponse(dynamic track) { + List artists = List.from(track['artists'].map((artist) { + return Artist(artist['id'], artist['name'], ''); + })); + + return Music( + track['id'], + track['name'], + track['album']['images'][0]['url'], + track['preview_url'], + int.parse(track['album']['release_date'].split('-')[0]), + track['duration_ms'] / 1000, + track['explicit'], + artists); } Future> getMusicsWithName(String name, @@ -76,7 +62,9 @@ class MusicViewModel { if (response.statusCode == 200) { Map responseData = jsonDecode(response.body); - return _getMusicsFromResponse(responseData['tracks']['items']); + return List.from(responseData['tracks']['items'].map((track) { + return _getMusicFromResponse(track); + })); } else { throw Exception( 'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}'); @@ -95,7 +83,9 @@ class MusicViewModel { if (response.statusCode == 200) { Map responseData = jsonDecode(response.body); - return _getMusicsFromResponse(responseData['tracks']['items']); + return List.from(responseData['tracks']['items'].map((track) { + return _getMusicFromResponse(track); + })); } else { throw Exception( 'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}'); @@ -174,7 +164,9 @@ class MusicViewModel { if (response.statusCode == 200) { Map responseData = jsonDecode(response.body); - return _getMusicsFromResponse(responseData['tracks']); + return List.from(responseData['tracks'].map((track) { + return _getMusicFromResponse(track); + })); } else { throw Exception( 'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}'); @@ -196,20 +188,7 @@ class MusicViewModel { List tracks = responseData['tracks']['items']; for (var track in tracks) { - List artists = - List.from(track['track']['artists'].map((artist) { - return Artist(artist['id'], artist['name'], ''); - })); - - musics.add(Music( - track['track']['id'], - track['track']['name'], - track['track']['album']['images'][0]['url'], - track['track']['preview_url'], - int.parse(track['track']['album']['release_date'].split('-')[0]), - track['track']['duration_ms'] / 1000, - track['track']['explicit'], - artists)); + musics.add(_getMusicFromResponse(track['track'])); } return musics; @@ -228,15 +207,15 @@ class MusicViewModel { url += ids.join('%2C'); - print(url); - var response = await http.get(Uri.parse(url), headers: { 'Authorization': 'Bearer $accessToken', }); if (response.statusCode == 200) { Map responseData = jsonDecode(response.body); - return _getMusicsFromResponse(responseData['tracks']); + return List.from(responseData['tracks'].map((track) { + return _getMusicFromResponse(track); + })); } else { throw Exception( 'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}'); diff --git a/Sources/justMUSIC/pubspec.lock b/Sources/justMUSIC/pubspec.lock index 706cf83..685a4a9 100644 --- a/Sources/justMUSIC/pubspec.lock +++ b/Sources/justMUSIC/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.10.0" audioplayers: dependency: "direct main" description: @@ -85,10 +85,10 @@ packages: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.2.1" circular_reveal_animation: dependency: "direct main" description: @@ -109,10 +109,10 @@ packages: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.17.0" crypto: dependency: transitive description: @@ -268,10 +268,10 @@ packages: dependency: transitive description: name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" url: "https://pub.dev" source: hosted - version: "0.6.7" + version: "0.6.5" lints: dependency: transitive description: @@ -284,10 +284,10 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.13" material_color_utilities: dependency: transitive description: @@ -300,10 +300,10 @@ packages: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.8.0" modal_bottom_sheet: dependency: "direct main" description: @@ -316,10 +316,10 @@ packages: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.8.2" path_provider: dependency: transitive description: @@ -449,10 +449,10 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.4.16" text_scroll: dependency: "direct main" description: @@ -518,5 +518,5 @@ packages: source: hosted version: "1.1.0" sdks: - dart: ">=3.0.0-0 <4.0.0" + dart: ">=2.18.2 <3.0.0" flutter: ">=3.3.0" From b4645aed122220d929b7c604f6d4c180982b7b53 Mon Sep 17 00:00:00 2001 From: Lucas Delanier Date: Sun, 30 Jul 2023 19:08:44 +0200 Subject: [PATCH 12/16] button post when music renseigned --- .../justMUSIC/assets/images/rocket_button.png | Bin 0 -> 17515 bytes .../lib/components/city_list_component.dart | 2 +- .../lib/components/post_button_component.dart | 159 +++++++++++++++--- .../justMUSIC/lib/screens/post_screen.dart | 2 +- .../lib/screens/search_song_screen.dart | 1 + 5 files changed, 141 insertions(+), 23 deletions(-) create mode 100644 Sources/justMUSIC/assets/images/rocket_button.png diff --git a/Sources/justMUSIC/assets/images/rocket_button.png b/Sources/justMUSIC/assets/images/rocket_button.png new file mode 100644 index 0000000000000000000000000000000000000000..2b27406d3c976482854158c3053dbfb63b23affb GIT binary patch literal 17515 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 createState() => _PostButtonComponentState(); +} + +class _PostButtonComponentState extends State + with SingleTickerProviderStateMixin { + late AnimationController _controller; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + animationBehavior: AnimationBehavior.normal, + vsync: this, + duration: Duration(milliseconds: 1500), + ); + + _controller.addStatusListener((status) { + if (status == AnimationStatus.completed) { + _controller.reverse(); + } else if (status == AnimationStatus.dismissed) { + _controller.forward(); + } + }); + + _controller.forward(); + } @override Widget build(BuildContext context) { + if (widget.empty) { + return Container( + constraints: BoxConstraints(maxWidth: 400), + decoration: BoxDecoration( + gradient: LinearGradient(colors: [ + Color(0xFF141414), + Color(0xFF272727), + Color(0xFF141414) + ]), + borderRadius: BorderRadius.circular(10000)), + padding: EdgeInsets.symmetric(vertical: 25), + width: double.infinity, + child: Align( + child: Text( + "Publier la capsule", + style: GoogleFonts.plusJakartaSans( + color: Color(0xFF474747), + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + fontSize: 24), + ), + ), + ); + } return Container( - constraints: BoxConstraints(maxWidth: 400), - decoration: BoxDecoration( - gradient: LinearGradient(colors: [ - Color(0xFF141414), - Color(0xFF272727), - Color(0xFF141414) - ]), - borderRadius: BorderRadius.circular(10000)), - padding: EdgeInsets.symmetric(vertical: 25), width: double.infinity, - child: Align( - child: Text( - "Publier la capsule", - style: GoogleFonts.plusJakartaSans( - color: Color(0xFF474747), - fontWeight: FontWeight.w800, - fontStyle: FontStyle.italic, - fontSize: 24), - ), + height: 90, + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: Colors.transparent, borderRadius: BorderRadius.circular(1000)), + child: Stack( + children: [ + AnimatedBuilder( + animation: _controller, + builder: (context, child) { + return Transform.translate( + offset: Offset( + _controller.value * (MediaQuery.of(context).size.width - 200), + 0, + ), + child: child, + ); + }, + child: Container( + width: 120, + height: 80, + alignment: Alignment.center, + decoration: BoxDecoration( + gradient: LinearGradient(colors: [ + Color(0xFF9E78FF).withOpacity(0.0), + Color(0xFFFDFDFF), + Color(0xFFFFFFFF), + Color(0xFF9E78FF).withOpacity(0.0) + ], stops: const [ + 0, + 0.4, + 0.5, + 1 + ]), + ), + ), + ), + BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 10.0, + sigmaY: 10.0, + ), + child: Opacity( + opacity: 0.9, + child: Container( + constraints: BoxConstraints(maxWidth: 400), + decoration: BoxDecoration( + gradient: LinearGradient(colors: [ + Color(0xFF633AF4), + Color(0xFF9367FF), + Color(0xFF633AF4) + ]), + border: Border.all(width: 5, color: Color(0xFF1C1C1C)), + borderRadius: BorderRadius.circular(10000)), + padding: EdgeInsets.symmetric(vertical: 25), + width: double.infinity, + child: Padding( + padding: EdgeInsets.only(left: 100), + child: Text( + "Publier la capsule", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + fontSize: 22), + ), + ), + ), + )), + ClipOval( + child: Positioned( + left: -15, + child: Padding( + padding: const EdgeInsets.only(left: 5, top: 5), + child: Image( + image: AssetImage("assets/images/rocket_button.png"), + height: 65, + ), + ), + ), + ) + ], ), ); } diff --git a/Sources/justMUSIC/lib/screens/post_screen.dart b/Sources/justMUSIC/lib/screens/post_screen.dart index 1f53d8b..65cc130 100644 --- a/Sources/justMUSIC/lib/screens/post_screen.dart +++ b/Sources/justMUSIC/lib/screens/post_screen.dart @@ -111,7 +111,7 @@ class _PostScreenState extends State SizedBox( height: 40.h, ), - PostButtonComponent(), + PostButtonComponent(empty: selectedMusic == null), 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 02dc64a..ae104a6 100644 --- a/Sources/justMUSIC/lib/screens/search_song_screen.dart +++ b/Sources/justMUSIC/lib/screens/search_song_screen.dart @@ -115,6 +115,7 @@ class _SearchSongScreenState extends State { child: SizedBox( height: 40, child: TextField( + autofocus: true, controller: _textEditingController, keyboardAppearance: Brightness.dark, onEditingComplete: resetFullScreen, From 759a650992232a447e625ba3f069c505a9aa0851 Mon Sep 17 00:00:00 2001 From: Lucas Delanier Date: Sun, 30 Jul 2023 19:15:34 +0200 Subject: [PATCH 13/16] button post when music renseigned --- Sources/justMUSIC/lib/services/GeoApi.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/justMUSIC/lib/services/GeoApi.dart b/Sources/justMUSIC/lib/services/GeoApi.dart index 7f203bc..1f5e55e 100644 --- a/Sources/justMUSIC/lib/services/GeoApi.dart +++ b/Sources/justMUSIC/lib/services/GeoApi.dart @@ -4,8 +4,10 @@ import 'dart:convert'; import 'package:tuple/tuple.dart'; +import '../values/keys.dart'; + class GeoApi { - final String apiKey = "85a2724ad38b3994c2b7ebe1d239bbff"; + final String apiKey = geoKey; Future>?> getNearbyCities() async { try { LocationPermission permission = await Geolocator.checkPermission(); From e97ee2d25dc2cfa6dfadf5f8487bbc0884bfbc5d Mon Sep 17 00:00:00 2001 From: Lucas Delanier Date: Sun, 30 Jul 2023 19:17:12 +0200 Subject: [PATCH 14/16] button post when music renseigned --- Sources/justMUSIC/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/justMUSIC/.gitignore b/Sources/justMUSIC/.gitignore index 24476c5..7995c36 100644 --- a/Sources/justMUSIC/.gitignore +++ b/Sources/justMUSIC/.gitignore @@ -30,6 +30,7 @@ migrate_working_dir/ .packages .pub-cache/ .pub/ +.lib/values/keys.dart /build/ # Symbolication related From a6346c34eda646194f654641b5d357a47f81af97 Mon Sep 17 00:00:00 2001 From: Lucas Delanier Date: Sun, 30 Jul 2023 20:01:02 +0200 Subject: [PATCH 15/16] choice between camera and gallery --- .../components/editable_post_component.dart | 46 +++++++++++++++++-- .../lib/screens/search_location_screen.dart | 4 +- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/Sources/justMUSIC/lib/components/editable_post_component.dart b/Sources/justMUSIC/lib/components/editable_post_component.dart index f66759f..960344e 100644 --- a/Sources/justMUSIC/lib/components/editable_post_component.dart +++ b/Sources/justMUSIC/lib/components/editable_post_component.dart @@ -4,6 +4,7 @@ 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/cupertino.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -52,9 +53,9 @@ class _EditablePostComponentState extends State super.initState(); } - Future pickImage() async { + Future pickImage(ImageSource source) async { try { - final image = await ImagePicker().pickImage(source: ImageSource.gallery); + final image = await ImagePicker().pickImage(source: source); if (image == null) return; final imageTemp = File(image.path); setState(() { @@ -321,7 +322,7 @@ class _EditablePostComponentState extends State image = null; }); } else { - pickImage(); + _showActionSheet(context); } } @@ -334,4 +335,43 @@ class _EditablePostComponentState extends State searchLocation(); } } + + void _showActionSheet(BuildContext context) { + showCupertinoModalPopup( + context: context, + barrierColor: Colors.black.withOpacity(0.5), + builder: (BuildContext context) => Container( + color: Colors.black, + child: CupertinoActionSheet( + title: Text( + 'Ajouter une photo', + style: GoogleFonts.plusJakartaSans(fontWeight: FontWeight.bold), + ), + actions: [ + CupertinoActionSheetAction( + onPressed: () { + pickImage(ImageSource.gallery); + Navigator.pop(context); + }, + child: const Text('Gallerie'), + ), + CupertinoActionSheetAction( + onPressed: () { + pickImage(ImageSource.camera); + Navigator.pop(context); + }, + child: const Text('Prendre un selfie'), + ), + ], + cancelButton: CupertinoActionSheetAction( + isDestructiveAction: true, + onPressed: () { + Navigator.pop(context); + }, + child: const Text('Annuler'), + ), + ), + ), + ); + } } diff --git a/Sources/justMUSIC/lib/screens/search_location_screen.dart b/Sources/justMUSIC/lib/screens/search_location_screen.dart index 73f6d1a..82d8261 100644 --- a/Sources/justMUSIC/lib/screens/search_location_screen.dart +++ b/Sources/justMUSIC/lib/screens/search_location_screen.dart @@ -1,6 +1,7 @@ import 'dart:ui'; import 'package:flutter/Material.dart'; +import 'package:flutter/cupertino.dart'; import '../components/city_list_component.dart'; import '../services/GeoApi.dart'; @@ -71,7 +72,8 @@ class _SearchCityScreenState extends State { }); } else { return Center( - child: CircularProgressIndicator( + child: CupertinoActivityIndicator( + radius: 15, color: grayColor, ), ); From abe4913d39817b1bd31b6c98be3cb9311ac050b1 Mon Sep 17 00:00:00 2001 From: Lucas Delanier Date: Sun, 30 Jul 2023 21:06:08 +0200 Subject: [PATCH 16/16] choice between camera and gallery --- Sources/justMUSIC/lib/components/editable_post_component.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/justMUSIC/lib/components/editable_post_component.dart b/Sources/justMUSIC/lib/components/editable_post_component.dart index 960344e..7bc2714 100644 --- a/Sources/justMUSIC/lib/components/editable_post_component.dart +++ b/Sources/justMUSIC/lib/components/editable_post_component.dart @@ -353,7 +353,7 @@ class _EditablePostComponentState extends State pickImage(ImageSource.gallery); Navigator.pop(context); }, - child: const Text('Gallerie'), + child: const Text('Galerie'), ), CupertinoActionSheetAction( onPressed: () {