diff --git a/.idea/libraries/Dart_SDK.xml b/.idea/libraries/Dart_SDK.xml index 8173c5d..df2867e 100644 --- a/.idea/libraries/Dart_SDK.xml +++ b/.idea/libraries/Dart_SDK.xml @@ -1,25 +1,26 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0e259d4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/README.md b/README.md index 4babb63..9546276 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ --- -[Présentation](#présentation) | [Répartion](#répartition-du-gitlab) | [Fonctionnement](#fonctionnement) | [Deploiement](#deploiement) | [Remerciements](#remerciements) | [Wiki](https://codefirst.iut.uca.fr/git/justDEV/justMusic/wiki) +[Présentation](#présentation) | [Répartion](#répartition-du-gitlab) | [Fonctionnement](#fonctionnement) | [Deploiement](#deploiement) | [Remerciements](#remerciements) | [Wiki](https://codefirst.iut.uca.fr/git/justDEV/justMusic/wiki) | [Site officiel](https://justmusicapp.com) diff --git a/Sources/justMUSIC/assets/images/loadingPlaceholder.gif b/Sources/justMUSIC/assets/images/loadingPlaceholder.gif new file mode 100644 index 0000000..490bf64 Binary files /dev/null and b/Sources/justMUSIC/assets/images/loadingPlaceholder.gif differ diff --git a/Sources/justMUSIC/lib/components/music_list_component.dart b/Sources/justMUSIC/lib/components/music_list_component.dart index 2173ce4..c92bba1 100644 --- a/Sources/justMUSIC/lib/components/music_list_component.dart +++ b/Sources/justMUSIC/lib/components/music_list_component.dart @@ -1,10 +1,15 @@ import 'package:flutter/Material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:justmusic/components/play_button_component.dart'; -import 'package:justmusic/values/constants.dart'; +import 'package:text_scroll/text_scroll.dart'; +import '../model/Music.dart'; class MusicListComponent extends StatelessWidget { - const MusicListComponent({Key? key}) : super(key: key); + final Music music; + const MusicListComponent({ + Key? key, + required this.music, + }) : super(key: key); @override Widget build(BuildContext context) { @@ -12,58 +17,82 @@ class MusicListComponent extends StatelessWidget { padding: const EdgeInsets.only(bottom: 14), child: Row( children: [ - const ClipRRect( - borderRadius: BorderRadius.all(Radius.circular(5)), - child: Image( - image: AssetImage("assets/images/exemple_cover.png"), - width: 60, - height: 60, - ), - ), + LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + if (music.cover != null) { + return ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(5)), + child: music.cover != null + ? FadeInImage.assetNetwork( + height: 60, + width: 60, + fit: BoxFit.cover, + placeholder: "assets/images/loadingPlaceholder.gif", + image: music.cover!) + : Container( + height: 60, + width: 60, + color: Colors.grey, + ), + ); + } else { + return Image( + image: AssetImage("assets/images/exemple_cover.png"), + height: 60, + width: 60, + ); + } + }), const SizedBox( width: 10, ), Expanded( flex: 10, - child: Wrap( - alignment: WrapAlignment.center, - direction: Axis.vertical, - runSpacing: 3, - spacing: 3, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, children: [ - Wrap( - verticalDirection: VerticalDirection.up, - spacing: 5, - runSpacing: 8, - runAlignment: WrapAlignment.end, - alignment: WrapAlignment.end, + Row( children: [ - Text( - "A.C. Milan", - overflow: TextOverflow.ellipsis, - style: GoogleFonts.plusJakartaSans( - fontSize: 16, - color: Colors.white, - fontWeight: FontWeight.w700), - ), + Flexible( + flex: 8, + child: ScrollConfiguration( + behavior: + ScrollBehavior().copyWith(scrollbars: false), + child: TextScroll( + music.title ?? "Unknown", + style: GoogleFonts.plusJakartaSans( + fontSize: 16, + color: Colors.white, + fontWeight: FontWeight.w700), + mode: TextScrollMode.endless, + pauseBetween: Duration(milliseconds: 2500), + velocity: Velocity(pixelsPerSecond: Offset(30, 0)), + intervalSpaces: 10, + ), + )), Icon( Icons.explicit, color: Colors.grey.withOpacity(0.7), size: 17, - ) + ), ], ), - Text( - "Booba", - overflow: TextOverflow.ellipsis, - style: GoogleFonts.plusJakartaSans( - color: Colors.grey, fontWeight: FontWeight.w400), - ) + ScrollConfiguration( + behavior: ScrollBehavior().copyWith(scrollbars: false), + child: Text( + music.artists.first.name ?? "Unknown", + overflow: TextOverflow.ellipsis, + style: GoogleFonts.plusJakartaSans( + color: Colors.grey, fontWeight: FontWeight.w400), + )) ], ), ), Spacer(), - PlayButtonComponent() + PlayButtonComponent( + urlPreview: music.previewUrl, + ) ], ), ); diff --git a/Sources/justMUSIC/lib/components/play_button_component.dart b/Sources/justMUSIC/lib/components/play_button_component.dart index 3c20faa..5c3c2e2 100644 --- a/Sources/justMUSIC/lib/components/play_button_component.dart +++ b/Sources/justMUSIC/lib/components/play_button_component.dart @@ -2,10 +2,11 @@ import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/Material.dart'; import 'package:flutter_animated_play_button/flutter_animated_play_button.dart'; import 'package:ionicons/ionicons.dart'; -import 'package:justmusic/values/constants.dart'; class PlayButtonComponent extends StatefulWidget { - const PlayButtonComponent({Key? key}) : super(key: key); + final String? urlPreview; + const PlayButtonComponent({Key? key, required this.urlPreview}) + : super(key: key); @override State createState() => _PlayButtonComponentState(); @@ -37,11 +38,14 @@ class _PlayButtonComponentState extends State { return isPlaying ? GestureDetector( onTap: switchStatePlaying, - child: Icon( - Ionicons.play_circle_outline, - color: Colors.grey.withOpacity(0.3), - size: 30, - ), + child: Container( + width: 30, + height: 30, + child: Icon( + Ionicons.play_circle_outline, + color: Colors.grey.withOpacity(0.3), + size: 30, + )), ) : GestureDetector( onTap: switchStatePlaying, @@ -57,8 +61,9 @@ class _PlayButtonComponentState extends State { } Future playSong() async { - await player.play(UrlSource( - 'https://p.scdn.co/mp3-preview/d38052978a79adced2187cd8b6497bb10bedc452?cid=eb2aab666a43490f82eef0bb064d363f')); + if (widget.urlPreview != null) { + await player.play(UrlSource(widget.urlPreview ?? "")); + } } Future stopSong() async { diff --git a/Sources/justMUSIC/lib/main.dart b/Sources/justMUSIC/lib/main.dart index 52ff98e..1203f32 100644 --- a/Sources/justMUSIC/lib/main.dart +++ b/Sources/justMUSIC/lib/main.dart @@ -8,6 +8,7 @@ import 'package:justmusic/screens/post_screen.dart'; import 'package:justmusic/screens/profile_screen.dart'; import 'package:justmusic/screens/registration_screen.dart'; import 'package:justmusic/screens/welcome_screen.dart'; +import 'package:justmusic/view_model/MusicViewModel.dart'; import 'package:justmusic/view_model/UserViewModel.dart'; void main() { @@ -16,6 +17,8 @@ void main() { class MyApp extends StatelessWidget { static UserViewModel userViewModel = UserViewModel(); + static MusicViewModel musicViewModel = MusicViewModel(); + const MyApp({super.key}); // This widget is the root of your application. diff --git a/Sources/justMUSIC/lib/model/Music.dart b/Sources/justMUSIC/lib/model/Music.dart index ff3c685..367d6a6 100644 --- a/Sources/justMUSIC/lib/model/Music.dart +++ b/Sources/justMUSIC/lib/model/Music.dart @@ -6,11 +6,13 @@ class Music { String? _cover; String? _previewUrl; DateTime? _date; + double? _duration; + bool _explicit = false; List _artists; // Constructor Music(this._id, this._title, this._cover, this._previewUrl, this._date, - this._artists); + this._duration, this._explicit, this._artists); //Getters and setters String? get id => _id; @@ -39,6 +41,18 @@ class Music { _date = value; } + double? get duration => _duration; + + set duration(double? value) { + _duration = value; + } + + bool get explicit => _explicit; + + set explicit(bool value) { + _explicit = value; + } + List get artists => _artists; set artists(List value) { diff --git a/Sources/justMUSIC/lib/screens/search_song_screen.dart b/Sources/justMUSIC/lib/screens/search_song_screen.dart index 031e919..30b1757 100644 --- a/Sources/justMUSIC/lib/screens/search_song_screen.dart +++ b/Sources/justMUSIC/lib/screens/search_song_screen.dart @@ -1,11 +1,14 @@ +import 'dart:async'; import 'dart:ui'; import 'package:flutter/Material.dart'; import 'package:flutter/services.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'package:justmusic/model/Music.dart'; import '../components/music_list_component.dart'; import '../values/constants.dart'; +import '../main.dart'; class SearchSongScreen extends StatefulWidget { const SearchSongScreen({Key? key}) : super(key: key); @@ -15,12 +18,50 @@ class SearchSongScreen extends StatefulWidget { } class _SearchSongScreenState extends State { + final ScrollController _scrollController = ScrollController(); + final TextEditingController _textEditingController = TextEditingController(); + Future resetFullScreen() async { await SystemChannels.platform.invokeMethod( 'SystemChrome.restoreSystemUIOverlays', ); } + @override + void initState() { + super.initState(); + _scrollController.addListener(_scrollListener); + } + + Future _scrollListener() async { + if (_scrollController.position.pixels == + _scrollController.position.maxScrollExtent) { + filteredData.addAll(await MyApp.musicViewModel.getMusicsWithName( + _textEditingController.text, + limit: 10, + offset: filteredData.length)); + setState(() { + filteredData = filteredData; + }); + } + if (_scrollController.offset >= + _scrollController.position.maxScrollExtent && + !_scrollController.position.outOfRange) { + setState(() { + //you can do anything here + }); + } + if (_scrollController.offset <= + _scrollController.position.minScrollExtent && + !_scrollController.position.outOfRange) { + setState(() { + Timer(Duration(milliseconds: 1), () => _scrollController.jumpTo(0)); + }); + } + } + + List filteredData = []; + @override Widget build(BuildContext context) { double screenHeight = MediaQuery.of(context).size.height; @@ -40,8 +81,7 @@ class _SearchSongScreenState extends State { child: Container( color: bgAppBar.withOpacity(0.5), height: screenHeight - 50, - padding: const EdgeInsets.only( - top: 10, left: defaultPadding, right: defaultPadding), + padding: const EdgeInsets.only(top: 10), child: Column( children: [ Align( @@ -56,17 +96,25 @@ class _SearchSongScreenState extends State { height: 10, ), Padding( - padding: const EdgeInsets.only(bottom: 10), + padding: + const EdgeInsets.only(bottom: 10, left: 20, right: 20), child: SizedBox( height: 40, - child: TextFormField( + child: TextField( + controller: _textEditingController, keyboardAppearance: Brightness.dark, onEditingComplete: resetFullScreen, - validator: (value) { - if (value == null || value.isEmpty) { - return 'TODO'; + onChanged: (value) async { + if (_textEditingController.text.isEmpty) { + } else if (value == " ") { + print("popular"); + } else { + filteredData = await MyApp.musicViewModel + .getMusicsWithName(value); + setState(() { + filteredData = filteredData; + }); } - return null; }, cursorColor: Colors.white, keyboardType: TextInputType.text, @@ -100,31 +148,18 @@ class _SearchSongScreenState extends State { ), ), ), - Expanded( + Flexible( child: ScrollConfiguration( - behavior: ScrollBehavior().copyWith(scrollbars: false), - child: SingleChildScrollView( - child: Column( - children: const [ - MusicListComponent(), - MusicListComponent(), - MusicListComponent(), - MusicListComponent(), - MusicListComponent(), - MusicListComponent(), - MusicListComponent(), - MusicListComponent(), - MusicListComponent(), - MusicListComponent(), - MusicListComponent(), - MusicListComponent(), - MusicListComponent(), - MusicListComponent(), - MusicListComponent(), - MusicListComponent(), - ], - ), - ), + behavior: ScrollBehavior().copyWith(scrollbars: true), + child: ListView.builder( + controller: _scrollController, + itemCount: filteredData.length, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: MusicListComponent(music: filteredData[index]), + ); + }), )) ], ), diff --git a/Sources/justMUSIC/lib/view_model/MusicViewModel.dart b/Sources/justMUSIC/lib/view_model/MusicViewModel.dart index 514155b..668526a 100644 --- a/Sources/justMUSIC/lib/view_model/MusicViewModel.dart +++ b/Sources/justMUSIC/lib/view_model/MusicViewModel.dart @@ -24,7 +24,7 @@ class MusicViewModel { final responseData = jsonDecode(response.body); List artists = List.from(responseData['artists'].map((artist) { - return Artist(artist['id'], artist['name'],''); + return Artist(artist['id'], artist['name'], ''); })); return Music( @@ -33,6 +33,8 @@ class MusicViewModel { responseData['album']['images'][0]['url'], responseData['preview_url'], DateTime.parse(responseData['album']['release_date']), + responseData['duration_ms'] / 1000, + responseData['explicit'], artists); } else { throw Exception( @@ -46,7 +48,7 @@ class MusicViewModel { List tracks = responseData['tracks']['items']; for (var track in tracks) { List artists = List.from(track['artists'].map((artist) { - return Artist(artist['id'], artist['name'],''); + return Artist(artist['id'], artist['name'], ''); })); musics.add(Music( @@ -55,18 +57,23 @@ class MusicViewModel { track['album']['images'][0]['url'], track['preview_url'], DateTime.now(), + track['duration_ms'] / 1000, + track['explicit'], artists)); } return musics; } - Future> getMusicsWithName(String name, {int limit = 20, int offset = 0, String market = "FR"}) async { + Future> getMusicsWithName(String name, + {int limit = 20, int offset = 0, String market = "FR"}) async { var accessToken = await _token.getAccessToken(); - var response = await http - .get(Uri.parse('$API_URL/search?q=track%3A$name&type=track&market=fr&limit=$limit&offset=$offset'), headers: { - 'Authorization': 'Bearer $accessToken', - }); + var response = await http.get( + Uri.parse( + '$API_URL/search?q=track%3A$name&type=track&market=fr&limit=$limit&offset=$offset'), + headers: { + 'Authorization': 'Bearer $accessToken', + }); if (response.statusCode == 200) { Map responseData = jsonDecode(response.body); @@ -77,10 +84,12 @@ class MusicViewModel { } } - Future> getMusicsWithArtistName(String name, {int limit = 20, int offset = 0, String market = "FR"}) async { + Future> getMusicsWithArtistName(String name, + {int limit = 20, int offset = 0, String market = "FR"}) async { var accessToken = await _token.getAccessToken(); var response = await http.get( - Uri.parse('$API_URL/search?q=artist%3A$name&type=track&market=fr&limit=$limit&offset=$offset'), + Uri.parse( + '$API_URL/search?q=artist%3A$name&type=track&market=fr&limit=$limit&offset=$offset'), headers: { 'Authorization': 'Bearer $accessToken', }); @@ -93,4 +102,102 @@ class MusicViewModel { 'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}'); } } + + Future getArtistWithName(String name, {String market = "FR"}) async { + var accessToken = await _token.getAccessToken(); + var response = await http.get( + Uri.parse( + '$API_URL/search?q=artist%3A$name&type=artist&market=$market'), + headers: { + 'Authorization': 'Bearer $accessToken', + }); + + if (response.statusCode == 200) { + final responseData = jsonDecode(response.body); + List artists = + List.from(responseData['artists']['items'].map((artist) { + String image = ''; + if (!artist['images'].isEmpty) { + image = artist['images'][0]['url']; + } + return Artist(artist['id'], artist['name'], image); + })); + + for (Artist a in artists) { + if (a.name?.toLowerCase() == name.toLowerCase()) { + return a; + } + } + + throw Exception('Artist not found : ${name}'); + } else { + throw Exception( + 'Error retrieving artist information : ${response.statusCode} ${response.reasonPhrase}'); + } + } + + Future> getArtistsWithName(String name, + {int limit = 20, int offset = 0, String market = "FR"}) async { + var accessToken = await _token.getAccessToken(); + var response = await http.get( + Uri.parse( + '$API_URL/search?q=artist%3A$name&type=artist&market=$market&limit=$limit&offset=$offset'), + headers: { + 'Authorization': 'Bearer $accessToken', + }); + + if (response.statusCode == 200) { + final responseData = jsonDecode(response.body); + List artists = + List.from(responseData['artists']['items'].map((artist) { + String image = ''; + if (!artist['images'].isEmpty) { + image = artist['images'][0]['url']; + } + return Artist(artist['id'], artist['name'], image); + })); + + return artists; + } else { + throw Exception( + 'Error while retrieving artist : ${response.statusCode} ${response.reasonPhrase}'); + } + } + + Future> getTopMusicsWithArtistId(String id, + {String market = "FR"}) async { + var accessToken = await _token.getAccessToken(); + var response = await http.get( + Uri.parse('$API_URL/artists/$id/top-tracks?market=$market'), + headers: { + 'Authorization': 'Bearer $accessToken', + }); + + if (response.statusCode == 200) { + Map responseData = jsonDecode(response.body); + List musics = []; + + List tracks = responseData['tracks']; + 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'], + DateTime.now(), + track['duration_ms'] / 1000, + track['explicit'], + artists)); + } + + return musics; + } else { + throw Exception( + 'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}'); + } + } } diff --git a/Sources/justMUSIC/pubspec.lock b/Sources/justMUSIC/pubspec.lock index 843edcb..685a4a9 100644 --- a/Sources/justMUSIC/pubspec.lock +++ b/Sources/justMUSIC/pubspec.lock @@ -5,140 +5,160 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.10.0" audioplayers: dependency: "direct main" description: name: audioplayers - url: "https://pub.dartlang.org" + sha256: "61583554386721772f9309f509e17712865b38565a903c761f96b1115a979282" + url: "https://pub.dev" source: hosted version: "4.1.0" audioplayers_android: dependency: transitive description: name: audioplayers_android - url: "https://pub.dartlang.org" + sha256: dbdc9b7f2aa2440314c638aa55aadd45c7705e8340d5eddf2e3fb8da32d4ae2c + url: "https://pub.dev" source: hosted version: "3.0.2" audioplayers_darwin: dependency: transitive description: name: audioplayers_darwin - url: "https://pub.dartlang.org" + sha256: "6aea96df1d12f7ad5a71d88c6d1b22a216211a9564219920124c16768e456e9d" + url: "https://pub.dev" source: hosted version: "4.1.0" audioplayers_linux: dependency: transitive description: name: audioplayers_linux - url: "https://pub.dartlang.org" + sha256: "396b62ac62c92dd26c3bc5106583747f57a8b325ebd2b41e5576f840cfc61338" + url: "https://pub.dev" source: hosted version: "2.1.0" audioplayers_platform_interface: dependency: transitive description: name: audioplayers_platform_interface - url: "https://pub.dartlang.org" + sha256: f7daaed4659143094151ecf6bacd927d29ab8acffba98c110c59f0b81ae51143 + url: "https://pub.dev" source: hosted version: "5.0.1" audioplayers_web: dependency: transitive description: name: audioplayers_web - url: "https://pub.dartlang.org" + sha256: ec84fd46eed1577148ed4113f5998a36a18da4fce7170c37ce3e21b631393339 + url: "https://pub.dev" source: hosted version: "3.1.0" audioplayers_windows: dependency: transitive description: name: audioplayers_windows - url: "https://pub.dartlang.org" + sha256: "1d3aaac98a192b8488167711ba1e67d8b96333e8d0572ede4e2912e5bbce69a3" + url: "https://pub.dev" source: hosted version: "2.0.2" auto_size_text: dependency: "direct main" description: name: auto_size_text - url: "https://pub.dartlang.org" + sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599" + url: "https://pub.dev" source: hosted version: "3.0.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" source: hosted version: "1.2.1" circular_reveal_animation: dependency: "direct main" description: name: circular_reveal_animation - url: "https://pub.dartlang.org" + sha256: "198f5a1fa27384dcf950807e0ae07a0da857c04df6233f7468755ee9db102b0c" + url: "https://pub.dev" source: hosted version: "2.0.1" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + url: "https://pub.dev" source: hosted version: "3.0.2" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" source: hosted version: "1.0.5" custom_draggable_widget: dependency: "direct main" description: name: custom_draggable_widget - url: "https://pub.dartlang.org" + sha256: "15718003ebcebb84acdf0c625831a880d139a284d8de9d943ef0d0a669f10159" + url: "https://pub.dev" source: hosted version: "0.0.2" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted version: "1.3.1" ffi: dependency: transitive description: name: ffi - url: "https://pub.dartlang.org" + sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 + url: "https://pub.dev" source: hosted version: "2.0.2" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" source: hosted version: "6.1.4" flutter: @@ -150,28 +170,32 @@ packages: dependency: "direct main" description: name: flutter_animated_play_button - url: "https://pub.dartlang.org" + sha256: dd955a450a4514e935e2f410afbd03b3bcf5f31b933a8f1334199caa3c6a81e2 + url: "https://pub.dev" source: hosted version: "0.3.0" flutter_lints: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4" + url: "https://pub.dev" source: hosted version: "2.0.2" flutter_screenutil: dependency: "direct main" description: name: flutter_screenutil - url: "https://pub.dartlang.org" + sha256: "0a122936b450324cbdfd51be0819cc6fcebb093eb65585e9cd92263f7a1a8a39" + url: "https://pub.dev" source: hosted version: "5.7.0" flutter_signin_button: dependency: "direct main" description: name: flutter_signin_button - url: "https://pub.dartlang.org" + sha256: a063ecc5d5308377e103c9c3a89084abf15fca4440636233af6a13abacd5dcae + url: "https://pub.dev" source: hosted version: "2.0.0" flutter_test: @@ -188,154 +212,176 @@ packages: dependency: transitive description: name: font_awesome_flutter - url: "https://pub.dartlang.org" + sha256: "1f93e5799f0e6c882819e8393a05c6ca5226010f289190f2242ec19f3f0fdba5" + url: "https://pub.dev" source: hosted version: "9.2.0" google_fonts: dependency: "direct main" description: name: google_fonts - url: "https://pub.dartlang.org" + sha256: "6b6f10f0ce3c42f6552d1c70d2c28d764cf22bb487f50f66cca31dcd5194f4d6" + url: "https://pub.dev" source: hosted version: "4.0.4" gradiantbutton: dependency: "direct main" description: name: gradiantbutton - url: "https://pub.dartlang.org" + sha256: c88ac8567242630cd14231e2a6a861da4e40a02a9a0310af360e05634890d172 + url: "https://pub.dev" source: hosted version: "0.0.1" gradient_borders: dependency: "direct main" description: name: gradient_borders - url: "https://pub.dartlang.org" + sha256: "69eeaff519d145a4c6c213ada1abae386bcc8981a4970d923e478ce7ba19e309" + url: "https://pub.dev" source: hosted version: "1.0.0" http: dependency: "direct main" description: name: http - url: "https://pub.dartlang.org" + sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + url: "https://pub.dev" source: hosted version: "0.13.5" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" source: hosted version: "4.0.2" ionicons: dependency: "direct main" description: name: ionicons - url: "https://pub.dartlang.org" + sha256: "5496bc65a16115ecf05b15b78f494ee4a8869504357668f0a11d689e970523cf" + url: "https://pub.dev" source: hosted version: "0.2.2" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.6.5" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + url: "https://pub.dev" source: hosted version: "2.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.13" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.2.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" source: hosted version: "1.8.0" modal_bottom_sheet: dependency: "direct main" description: name: modal_bottom_sheet - url: "https://pub.dartlang.org" + sha256: ef533916a2c3089571c32bd34e410faca77a6849a3f28f748e0794525c5658a0 + url: "https://pub.dev" source: hosted version: "2.1.2" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" source: hosted version: "1.8.2" path_provider: dependency: transitive description: name: path_provider - url: "https://pub.dartlang.org" + sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" + url: "https://pub.dev" source: hosted version: "2.0.15" path_provider_android: dependency: transitive description: name: path_provider_android - url: "https://pub.dartlang.org" + sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" + url: "https://pub.dev" source: hosted version: "2.0.27" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - url: "https://pub.dartlang.org" + sha256: "916731ccbdce44d545414dd9961f26ba5fbaa74bcbb55237d8e65a623a8c7297" + url: "https://pub.dev" source: hosted version: "2.2.4" path_provider_linux: dependency: transitive description: name: path_provider_linux - url: "https://pub.dartlang.org" + sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 + url: "https://pub.dev" source: hosted version: "2.1.11" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - url: "https://pub.dartlang.org" + sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" + url: "https://pub.dev" source: hosted version: "2.0.6" path_provider_windows: dependency: transitive description: name: path_provider_windows - url: "https://pub.dartlang.org" + sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" + url: "https://pub.dev" source: hosted version: "2.1.7" platform: dependency: transitive description: name: platform - url: "https://pub.dartlang.org" + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" source: hosted version: "3.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd" + url: "https://pub.dev" source: hosted version: "2.1.5" sky_engine: @@ -347,112 +393,128 @@ packages: dependency: "direct main" description: name: smooth_corner - url: "https://pub.dartlang.org" + sha256: "1e920cffd9644d6f51f9a99674652f8c00f2e9074b275f3edde0de1441ba78e9" + url: "https://pub.dev" source: hosted version: "1.1.0" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" synchronized: dependency: transitive description: name: synchronized - url: "https://pub.dartlang.org" + sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60" + url: "https://pub.dev" source: hosted version: "3.1.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.4.16" text_scroll: dependency: "direct main" description: name: text_scroll - url: "https://pub.dartlang.org" + sha256: "7869d86a6fdd725dee56bdd150216a99f0372b82fbfcac319214dbd5f36e1908" + url: "https://pub.dev" source: hosted version: "0.2.0" top_snackbar_flutter: dependency: "direct main" description: name: top_snackbar_flutter - url: "https://pub.dartlang.org" + sha256: "22d14664a13db6ac714934c3382bd8d4daa57fb888a672f922df71981c5a5cb2" + url: "https://pub.dev" source: hosted version: "3.1.0" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" source: hosted version: "1.3.2" uuid: dependency: transitive description: name: uuid - url: "https://pub.dartlang.org" + sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + url: "https://pub.dev" source: hosted version: "3.0.7" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" win32: dependency: transitive description: name: win32 - url: "https://pub.dartlang.org" + sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c" + url: "https://pub.dev" source: hosted version: "4.1.4" xdg_directories: dependency: transitive description: name: xdg_directories - url: "https://pub.dartlang.org" + sha256: e0b1147eec179d3911f1f19b59206448f78195ca1d20514134e10641b7d7fbff + url: "https://pub.dev" source: hosted version: "1.0.1" zoom_tap_animation: dependency: "direct main" description: name: zoom_tap_animation - url: "https://pub.dartlang.org" + sha256: d9f7a73cab65aa1546ba6886b5e21d3c8ccccb34e4e5f770301c306d4868bee0 + url: "https://pub.dev" source: hosted version: "1.1.0" sdks: diff --git a/Sources/justMUSIC/pubspec.yaml b/Sources/justMUSIC/pubspec.yaml index 339aa4f..1a52f91 100644 --- a/Sources/justMUSIC/pubspec.yaml +++ b/Sources/justMUSIC/pubspec.yaml @@ -79,6 +79,7 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - assets/images/ + - assets/ # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware diff --git a/Sources/justMUSIC/test/Music_test.dart b/Sources/justMUSIC/test/Music_test.dart index eab5022..baf3aaa 100644 --- a/Sources/justMUSIC/test/Music_test.dart +++ b/Sources/justMUSIC/test/Music_test.dart @@ -7,7 +7,7 @@ Future main() async { Music m = await musicVM.getMusic('295SxdR1DqunCNwd0U767w'); print("id : ${m.id.toString()}, cover : ${m.cover}, title : ${m.title}"); - print("date : ${m.date.toString()}, preview : ${m.previewUrl}"); + 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}"); } @@ -17,7 +17,7 @@ Future main() async { List musics = await musicVM.getMusicsWithName('Shavkat'); for (Music m in musics) { print("id : ${m.id.toString()}, cover : ${m.cover}, title : ${m.title}"); - print("date : ${m.date.toString()}, preview : ${m.previewUrl}"); + 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}"); } @@ -28,9 +28,33 @@ Future main() async { List musics2 = await musicVM.getMusicsWithArtistName('jul'); for (Music m in musics2) { print("id : ${m.id.toString()}, cover : ${m.cover}, title : ${m.title}"); - print("date : ${m.date.toString()}, preview : ${m.previewUrl}"); + 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('\nArtist with Name:'); + + Artist a = await musicVM.getArtistWithName('jul'); + print("id : ${a.id}, name : ${a.name}, image : ${a.image}"); + + print('\nArtists with Name:'); + + List artists = await musicVM.getArtistsWithName('jul'); + for (Artist a in artists) { + print("id : ${a.id}, name : ${a.name}, image : ${a.image}"); + } + + print('\nTop Musics :'); + + List topMusics = await musicVM.getTopMusicsWithArtistId('3NH8t45zOTqzlZgBvZRjvB'); + for (Music m in topMusics) { + 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}"); + } + } + } diff --git a/Sources/justMUSIC/test/widget_test.dart b/Sources/justMUSIC/test/widget_test.dart index 7612045..0dd0921 100644 --- a/Sources/justMUSIC/test/widget_test.dart +++ b/Sources/justMUSIC/test/widget_test.dart @@ -11,7 +11,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:justmusic/main.dart'; void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { + /*testWidgets('Counter increments smoke test', (WidgetTester tester) async { // Build our app and trigger a frame. await tester.pumpWidget(const MyApp()); @@ -26,5 +26,5 @@ void main() { // Verify that our counter has incremented. expect(find.text('0'), findsNothing); expect(find.text('1'), findsOneWidget); - }); + });*/ }