summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHritik Chouhan <hritikc3961@gmail.com>2022-09-01 23:40:02 +0200
committerHritik Chouhan <hritikc3961@gmail.com>2022-09-10 19:40:25 +0200
commit1698dd7db75dadb4915e1b48f0f974b804a019f8 (patch)
tree22d1376bb92b753936b43f04aba9a65e773c3c64
parent85b78ad4577b65d0bfd398cf3723f83a5ee03dd9 (diff)
Upload Flutter-MediaPlayer app for IVIlamprey_12.1.6lamprey/12.1.612.1.6
Flutter MediaPlayer app which play song directly from MPD server connected via TCP socket.Functions included in mediaplayer play/pause/next/previous/loop , progress bar for current song,playlist from database , volume. Removed Unused code. Bug-AGL: SPEC-4549 Signed-off-by: Hritik Chouhan <hritikc3961@gmail.com> Change-Id: Ie7cdf109bca266e48fd10cd9b3cc0178edf42a52
-rw-r--r--.gitreview5
-rw-r--r--License.md201
-rw-r--r--assets/music.pngbin0 -> 17810 bytes
-rw-r--r--lib/class.dart30
-rw-r--r--lib/loadingPage.dart108
-rw-r--r--lib/main.dart33
-rw-r--r--lib/musicPage.dart462
-rw-r--r--lib/music_methods/controller.dart178
-rw-r--r--lib/music_methods/modeClass.dart15
-rw-r--r--lib/music_methods/mpd.dart20
-rw-r--r--lib/music_methods/musicProvider.dart64
-rw-r--r--lib/nomusic.dart27
-rw-r--r--lib/playlistLoading.dart109
-rw-r--r--lib/size.dart43
-rw-r--r--lib/socketProblem.dart29
-rw-r--r--pubspec.yaml90
16 files changed, 1414 insertions, 0 deletions
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 0000000..d5d3bcb
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,5 @@
+[gerrit]
+host=gerrit.automotivelinux.org
+port=29418
+project=apps/flutter-mediaplayer
+defaultbranch=master
diff --git a/License.md b/License.md
new file mode 100644
index 0000000..a0b7d15
--- /dev/null
+++ b/License.md
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [2022] [Hritik Chouhan]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/assets/music.png b/assets/music.png
new file mode 100644
index 0000000..766de9d
--- /dev/null
+++ b/assets/music.png
Binary files differ
diff --git a/lib/class.dart b/lib/class.dart
new file mode 100644
index 0000000..5aa74cf
--- /dev/null
+++ b/lib/class.dart
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:core';
+
+class CurrentSong{
+ CurrentSong({required this.title, required this.artist, required this.duration, required this.isPlaying, required this.time});
+
+ final String title;
+ final String artist;
+ final String duration;
+ final bool isPlaying;
+ final String time;
+
+ CurrentSong copyWith({
+ String ? title,
+ String ? artist,
+ String ? duration,
+ bool ? isPlaying,
+ String? time,
+ }){
+ return CurrentSong(artist: artist ?? this.artist,
+ title: title ?? this.title,
+ duration: duration ?? this.duration,
+ isPlaying: isPlaying ?? this.isPlaying,
+ time: time ?? this.time,
+ );
+ }
+
+}
+
diff --git a/lib/loadingPage.dart b/lib/loadingPage.dart
new file mode 100644
index 0000000..7d5c1af
--- /dev/null
+++ b/lib/loadingPage.dart
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'package:flutter/material.dart';
+
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+
+import 'package:musicplayer/music_methods/controller.dart';
+import 'package:musicplayer/nomusic.dart';
+import 'package:musicplayer/playlistLoading.dart';
+import 'package:musicplayer/socketProblem.dart';
+
+
+class loadingPage extends ConsumerStatefulWidget {
+ const loadingPage({Key? key}) : super(key: key);
+
+ @override
+ _loadingPageState createState() => _loadingPageState();
+}
+
+class _loadingPageState extends ConsumerState<loadingPage> {
+
+ @override
+ void initState() {
+ // TODO: implement initState
+ super.initState();
+ }
+
+ MPDTalker mpdTalker = MPDTalker();
+ List<Map<String, String>> list = [];
+
+ String convertToMin(String str){
+ String strforint = '';
+ for(int i = 0; i<str.length;i++){
+ if(str[i] == '.'){
+ break;
+ }
+ strforint += str[i];
+ }
+ int num = int.parse(strforint);
+ double min = num/60;
+ double sec = num%60;
+ String ans = min.toInt().toString()+'min ' + sec.toInt().toString()+'sec';
+ return ans;
+
+ }
+
+
+ Future mymethod() async{
+ list = await mpdTalker.cmdListMap('listall');
+ return list;
+
+ }
+
+ @override
+ Widget build(BuildContext context) {
+
+ return Scaffold(
+ body: FutureBuilder(
+ future: mymethod(),
+ builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
+
+ if (snapshot.connectionState == ConnectionState.done) {
+ // If we got an error
+ if (snapshot.hasError) {
+ return const SocketProblem();
+
+ // if we got our data
+ } else if (snapshot.hasData) {
+ // Extracting data from snapshot object
+ List list = snapshot.data as dynamic;
+
+ if(list.isNotEmpty){
+ mpdTalker.cmdStr('clear');
+ for(int i =0; i<list.length;i++){
+
+ String addsong = list[i]['file'];
+
+ mpdTalker.cmdStr('add "$addsong"');
+
+ }
+ return PlaylistLoading();
+
+ }
+ else{
+ return NoMusicFound();
+ }
+
+ } else if(snapshot.data == null){
+ return NoMusicFound();
+
+ }
+
+ }
+ return const Center(
+ child: CircularProgressIndicator(
+ color: Colors.black,
+ ),
+ );
+
+ },
+ ),
+ );
+
+
+
+ }
+} \ No newline at end of file
diff --git a/lib/main.dart b/lib/main.dart
new file mode 100644
index 0000000..58a65e3
--- /dev/null
+++ b/lib/main.dart
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: Apache-2.0
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:musicplayer/loadingPage.dart';
+import 'dart:io';
+import 'dart:convert';
+import 'dart:async';
+
+import 'package:musicplayer/music_methods/controller.dart';
+import 'package:musicplayer/music_methods/musicProvider.dart';
+
+
+void main() {
+ runApp(ProviderScope(child: const MyApp()));
+}
+
+class MyApp extends StatelessWidget {
+ const MyApp({Key? key}) : super(key: key);
+
+ // This widget is the root of your application.
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ title: 'MediaPlayer',
+ theme: ThemeData(
+
+ primarySwatch: Colors.blue,
+ ),
+ home: loadingPage(),
+ );
+ }
+}
+
diff --git a/lib/musicPage.dart b/lib/musicPage.dart
new file mode 100644
index 0000000..ea01a4e
--- /dev/null
+++ b/lib/musicPage.dart
@@ -0,0 +1,462 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:async';
+
+import 'package:badges/badges.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter/material.dart';
+
+import 'package:musicplayer/size.dart';
+
+import 'music_methods/controller.dart';
+import 'music_methods/modeClass.dart';
+import 'music_methods/musicProvider.dart';
+
+class MusicPageTest extends ConsumerStatefulWidget {
+ List<Map<String, String>> list;
+
+ MusicPageTest({Key? key, required this.list}) : super(key: key);
+
+ @override
+ _MusicPageTestState createState() => _MusicPageTestState();
+}
+
+
+
+class _MusicPageTestState extends ConsumerState<MusicPageTest> {
+
+
+ MPDTalker mpdTalker = MPDTalker();
+ bool isPlaying = false;
+ late int currindex;
+ String currSongTime = '0';
+ late Timer timer;
+
+ late Mode mode;
+
+
+
+ @override
+ void initState() {
+ // TODO: implement initState
+ super.initState();
+ WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
+
+ ref.read(CurrentSongProvider.notifier).update(artist:widget.list[0]['Artist'].toString(), title:widget.list[0]['file'].toString(),
+ duration: convertToMin(widget.list[0]['Time'].toString()), time: '0');
+
+ //timer for progress bar
+
+ timer = Timer.periodic(Duration(seconds: 1), (timer) async{
+
+ Map info = await mpdTalker.cmdMap('status');
+ ref.read(CurrentSongProvider.notifier).update(time: info['time']);
+
+
+
+
+ if(int.parse(currSongTime) == int.parse(convertTosimpleStr(widget.list[currindex]['Time'].toString()))-1 && mode.isSingle == false){
+
+
+
+
+ ref.read(CurrentSongProvider.notifier).update(isPlaying: true);
+
+ if(currindex == widget.list.length-1){
+ currindex = 0;
+ ref.read(currIndexProvider.notifier).update(currindex);
+ ref.read(CurrentSongProvider.notifier).update(artist:widget.list[currindex]['Artist'].toString(), title: widget.list[currindex]['file'].toString(),
+ duration: convertToMin(widget.list[currindex]['Time'].toString(),));
+ }
+ else{
+ currindex++;
+ ref.read(currIndexProvider.notifier).update(currindex);
+
+
+ ref.read(CurrentSongProvider.notifier).update(artist:widget.list[currindex]['Artist'].toString(), title: widget.list[currindex]['file'].toString(),
+ duration: convertToMin(widget.list[currindex]['Time'].toString(),));
+ }
+
+
+
+ }
+
+
+
+
+
+
+
+
+ });
+
+
+ });
+
+
+
+
+ }
+
+ @override
+ void dispose() {
+ timer.cancel();
+ super.dispose();
+ }
+
+
+
+
+ String convertToMin(String str){
+ String strforint = '';
+ for(int i = 0; i<str.length;i++){
+ if(str[i] == '.'){
+ break;
+ }
+ strforint += str[i];
+ }
+ int num = int.parse(strforint);
+ double min = num/60;
+ double sec = num%60;
+ String ans = min.toInt().toString()+':' + sec.toInt().toString();
+ return ans;
+
+ }
+ String convertTosimpleStr(String str){
+ String strforint = '';
+ for(int i = 0; i<str.length;i++){
+ if(str[i] == '.'){
+ break;
+ }
+ strforint += str[i];
+ }
+ return strforint;
+
+ }
+
+
+
+
+
+
+
+ @override
+ Widget build(BuildContext context) {
+ isPlaying = ref.watch(CurrentSongProvider).isPlaying;
+ currSongTime = ref.watch(CurrentSongProvider).time;
+ SizeConfig().init(context);
+
+ mode = ref.watch(Modeprovider);
+ currindex = ref.watch(currIndexProvider);
+
+
+
+
+
+
+
+
+
+ return Scaffold(
+
+ body: Flex(
+ direction: Axis.vertical,
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ crossAxisAlignment: CrossAxisAlignment.center,
+
+ children: [
+ Flexible(
+ flex: 4,
+ child: Flex(direction: Axis.horizontal,
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ Flexible(
+ flex: 1,
+ child: Container(
+
+ height: SizeConfig.screenHeight*0.5,
+ width: SizeConfig.screenWidth*0.4,
+ // color: Colors.blueGrey,
+ decoration: BoxDecoration(
+ color: Colors.blueGrey,
+ borderRadius: BorderRadius.circular(10)),
+ child: Padding(
+ padding: const EdgeInsets.all(15.0),
+ child: Flex(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ direction: Axis.vertical,
+ children: [
+ Flexible(
+ flex: 3,
+ child: Image.asset('assets/music.png')),
+ Flexible(
+ flex: 1,
+ child: Flex(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ direction: Axis.horizontal,
+ children: [Flexible(
+ flex: 3,
+ child: SingleChildScrollView(
+ scrollDirection: Axis.vertical,
+ child: Text(ref.watch(CurrentSongProvider).title,
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: SizeConfig.fontsize/2,
+
+
+ ),),
+ ),
+ ),
+ Flexible(
+ flex: 1,
+ child: Text(ref.watch(CurrentSongProvider).duration,
+ style: TextStyle(color: Colors.white,fontSize: SizeConfig.fontsize*0.4),)),
+ ],)),
+
+ Flexible(
+ flex: 1,
+ child:ref.watch(CurrentSongProvider).artist == 'null' ? const Text("Artist: unknown") : Text('Artist: ${ref.watch(CurrentSongProvider).artist}',
+ style: TextStyle(color: Colors.white,fontSize: SizeConfig.fontsize*0.4),),
+ )
+ ],
+ ),
+ ),
+
+ ),),
+ Flexible(flex : 1,
+ child: Container(
+ height: SizeConfig.screenHeight*0.5,
+ width: SizeConfig.screenWidth*0.4,
+ child: ListView.builder(
+ controller: ScrollController(),
+ scrollDirection: Axis.vertical,
+ itemCount: widget.list.length,
+ itemBuilder: ((context, index) => Card(
+ color: Colors.blueGrey,
+ shadowColor: Colors.blueAccent,
+ elevation: 5,
+
+ child: ListTile(
+ minLeadingWidth: 4,
+ textColor: Color.fromARGB(199, 255, 255, 255),
+
+ title: Text(widget.list[index]['file'].toString()),
+ subtitle: Text(widget.list[index]['Artist'] == null ? '' : widget.list[index]['Artist'].toString(),
+ style: TextStyle(color: Colors.black),),
+ trailing: Text(
+ convertToMin(widget.list[index]['Time'].toString(),),
+ style: TextStyle(color: Colors.black),
+ ),
+ onTap: (){
+
+
+ ref.read(CurrentSongProvider.notifier).update(artist:widget.list[index]['Artist'] == null ? "Unknown": widget.list[index]['Artist'].toString(),
+ title: widget.list[index]['file'].toString(),
+ duration: convertToMin(widget.list[index]['Time'].toString(),) ,isPlaying: true,);
+
+ mpdTalker.cmdStr('playid ' +widget.list[index]['Id'].toString());
+
+ currindex = index;
+ ref.read(currIndexProvider.notifier).update(currindex);
+
+
+ },
+ ),
+ ))),
+ ),),
+
+
+ ],
+ )),
+ Flexible(
+ flex: 2,
+ child: Flex(
+ direction: Axis.vertical,
+ children: [
+ Flexible(
+ flex: 1,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Flexible(
+ flex: 1,
+
+ child: Text(convertToMin(currSongTime))),
+ Flexible(
+ flex: 6,
+ child: RotatedBox(
+ quarterTurns: 4,
+ child: Slider(
+ activeColor: Colors.blueGrey,
+
+ thumbColor: Colors.transparent,
+ value: int.parse(currSongTime).toDouble()/((int.parse(convertTosimpleStr(widget.list[currindex]['Time'].toString())).toDouble())),
+ onChanged:(value){
+ double seekTime = value*int.parse(convertTosimpleStr(widget.list[currindex]['Time'].toString())).toDouble();
+ int seektime = seekTime.toInt();
+ mpdTalker.cmd('seekcur $seektime');
+ },
+ max: 1,
+ min: 0,
+ ),
+ ),
+ ),
+ Flexible(
+ flex: 1,
+ child: Text(convertToMin(widget.list[currindex]['Time'].toString()))),
+
+
+ ],
+ ),),
+ Flex(
+ direction: Axis.horizontal,
+
+ children: [
+ Flexible(
+ flex: 1,
+ child: SizedBox(
+ width: SizeConfig.screenWidth/3,
+ )),
+ Flexible(
+ flex : 1,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+
+ Badge(
+ badgeContent: mode.isSingle ? const Text('1') : null,
+ elevation: 0,
+ badgeColor: Colors.greenAccent,
+ child: IconButton(
+ icon: const Icon(Icons.loop),
+ color: Colors.greenAccent,
+ onPressed: (() {
+ if(mode.isSingle){
+ ref.read(Modeprovider.notifier).update(isSingle: false);
+ mpdTalker.cmd('single 0');
+ }
+ if(mode.isSingle == false ){
+ ref.read(Modeprovider.notifier).update(isSingle: true);
+ mpdTalker.cmd('single 1');
+
+
+
+
+ }
+
+
+
+ }),),
+ ),
+
+
+ IconButton(onPressed: (){
+
+ mpdTalker.cmdStr('previous');
+ ref.read(CurrentSongProvider.notifier).update(isPlaying: true);
+
+ if(currindex == 0){
+
+ ref.read(currIndexProvider.notifier).update(widget.list.length-1);
+ currindex = widget.list.length-1;
+
+ ref.read(CurrentSongProvider.notifier).update(artist:widget.list[currindex]['Artist'].toString(), title: widget.list[currindex]['file'].toString(),
+ duration: convertToMin(widget.list[currindex]['Time'].toString(),));
+ }
+ else{
+ currindex--;
+ ref.read(currIndexProvider.notifier).update(currindex);
+ ref.read(CurrentSongProvider.notifier).update(artist:widget.list[currindex]['Artist'].toString(), title: widget.list[currindex]['file'].toString(),
+ duration: convertToMin(widget.list[currindex]['Time'].toString(),));
+ }
+
+
+
+ }, icon: Icon(Icons.skip_previous)),
+ IconButton(
+ onPressed: (){
+
+ if(isPlaying){
+ mpdTalker.cmdStr('pause 1');
+ }
+ else{
+ mpdTalker.cmdStr('pause 0');
+ }
+ ref.read(CurrentSongProvider.notifier).update( isPlaying: !isPlaying);
+
+
+
+
+
+ },
+ icon: isPlaying ? Icon(Icons.pause): Icon(Icons.play_arrow)
+ ),
+ IconButton(onPressed: (){
+
+ mpdTalker.cmdStr('next');
+ ref.read(CurrentSongProvider.notifier).update(isPlaying: true);
+
+ if(currindex == widget.list.length-1){
+ ref.read(currIndexProvider.notifier).update(0);
+
+
+ ref.read(CurrentSongProvider.notifier).update(artist:widget.list[0]['Artist'].toString(), title: widget.list[0]['file'].toString(),
+ duration: convertToMin(widget.list[0]['Time'].toString(),));
+ }
+ else{
+ currindex++;
+ ref.read(currIndexProvider.notifier).update(currindex);
+
+ ref.read(CurrentSongProvider.notifier).update(artist:widget.list[currindex]['Artist'].toString(), title: widget.list[currindex]['file'].toString(),
+ duration: convertToMin(widget.list[currindex]['Time'].toString(),));
+ }
+
+
+
+
+ }, icon: Icon(Icons.skip_next)),
+
+
+ ],
+ ),),
+ Flexible(
+ flex: 1,
+ child: Row(
+ children: [
+ Icon(Icons.volume_up),
+ SizedBox(
+ width: SizeConfig.screenWidth/4,
+ child: RotatedBox(
+ quarterTurns: 4,
+ child: Slider(value: ref.watch(VolumeProvider).toDouble()/100, onChanged: (Value){
+ double vol = Value*100;
+ int songVol = vol.toInt();
+ mpdTalker.cmd('setvol $songVol');
+ ref.read(VolumeProvider.notifier).update(songVol);
+
+ }),
+ ),
+ ),
+ ],
+ ),
+
+ )
+ ],
+ ),
+ ],
+ ),
+ ),
+
+ ],
+
+
+
+ ),
+ );
+
+
+
+ }
+} \ No newline at end of file
diff --git a/lib/music_methods/controller.dart b/lib/music_methods/controller.dart
new file mode 100644
index 0000000..0ccd32b
--- /dev/null
+++ b/lib/music_methods/controller.dart
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: Apache-2.0
+import 'dart:async';
+import 'dart:io';
+
+import 'package:musicplayer/music_methods/mpd.dart';
+
+class MPDTalker {
+ String host;
+ int port;
+ // Socket socket;
+
+ MPDTalker({
+ this.host: "localhost",
+ this.port: 6600,
+
+ });
+
+ /**
+ * Send a request to MPD and get the output as a String.
+ */
+ Future<String> cmdStr(String cmd) {
+ Completer<String> com = new Completer<String>();
+ String data = "";
+
+ // Connect to MPD.
+ Socket.connect(host, port)
+ .then((Socket socket) {
+ // Write the command to MPD.
+ socket.write("$cmd\n");
+
+ // Listen for MPD.
+ socket.listen((List<int> chars) {
+ // Get the response.
+ String line = new String.fromCharCodes(chars);
+ data += line;
+
+ // Check if MPD is done sending data.
+ try {
+ if(_atEnd(line)) {
+ socket.close();
+ }
+ } catch(error, stacktrace) {
+ com.completeError(error, stacktrace);
+ }
+ },
+ onDone: () {
+ // Finish the future if there hasn't been an error.
+ if(!com.isCompleted) {
+ com.complete(data);
+ }
+ });
+ });
+
+ return com.future;
+ }
+
+ /**
+ * Check if MPD is done sending data.
+ */
+ bool _atEnd(String str) {
+
+ //str.contains(new RegExp("ACK \[[0-9]?([0-9])@[0-9]?([0-9])\]"));
+ if(str.contains("ACK [")) {
+ for(String line in str.split("\n")) {
+ if(line.startsWith("ACK [")) {
+ throw new MPDError(line);
+ break;
+ }
+ }
+ }
+
+ return str.endsWith("OK\n");
+ }
+
+ Future cmd(String str) {
+ Completer com = new Completer();
+ cmdStr(str).then((String data) {
+ com.complete();
+ });
+
+ return com.future;
+ }
+
+ /**
+ * Send a request to MPD and get the output as a List of Strings.
+ */
+ Future cmdList(String cmd) {
+ Completer com = new Completer();
+
+ // Get the data as a String, then turn it into a List.
+ cmdStr(cmd).then((String dataStr) {
+ List<String> data = [];
+
+ // For each line in the string:
+ for(String line in dataStr.split("\n")) {
+ // It will be separated into key/value pairs.
+ List<String> kv = line.split(":");
+
+ // We care about the value in this case, so add it to our list.
+ if(kv.length > 1)
+ data.add(kv[1].trim());
+ }
+
+ // Finished.
+ com.complete(data);
+ });
+
+ return com.future;
+ }
+
+ /**
+ * Send a request to MPD and get the output as a Map of Strings keyed to Strings.
+ */
+ Future<Map<String, String>> cmdMap(String cmd) async{
+ Map<String, String> data = new Map<String, String>();
+
+
+ // Get the data as a String, then turn it into a Map.
+ String dataStr = await cmdStr(cmd);
+
+ // For every line in the String:
+ for(String line in dataStr.split("\n")) {
+ // Split it into key value pairs like a map.
+ List<String> kv = line.split(":");
+ if(kv.length > 1) {
+ // Add our keys/values to the map.
+ data[kv[0].trim()] = kv[1].trim();
+ }
+ }
+
+
+
+ return data;
+ }
+
+ /**
+ * Send a request to MPD and get the output as a List of Maps of Strings keyed to Strings.
+ *
+ * String newKey: The key that defines a new item in the list.
+ */
+ Future<List<Map<String, String>>> cmdListMap(String cmd, {List<String>? newKeys}) async{
+ Completer com = new Completer();
+
+ // Set newKey's default to ["file"].
+ if(newKeys == null)
+ newKeys = ["file"];
+ List<Map<String, String>> data = [];
+
+
+ // Get the data as a String, then turn it into a List of Maps.
+
+
+ String dataStr = await cmdStr(cmd);
+
+
+ // For every line:
+ for(String line in dataStr.split("\n")) {
+ // Split it into keys/values.
+ List<String> kv = line.split(":");
+ if(kv.length > 1) {
+ // If the key is a new key, create a new Map in our list.
+ for(String key in newKeys) {
+ if(kv[0].trim() == key) {
+ data.add(Map<String, String>());
+ break;
+ }
+ }
+ // If we have Maps in our list, add the new item to the last Map.
+ if(data.isNotEmpty) {
+ data.last[kv[0].trim()] = kv[1].trim();
+ }
+ }
+ }
+
+ return data;
+
+ }
+} \ No newline at end of file
diff --git a/lib/music_methods/modeClass.dart b/lib/music_methods/modeClass.dart
new file mode 100644
index 0000000..1cb6122
--- /dev/null
+++ b/lib/music_methods/modeClass.dart
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: Apache-2.0
+class Mode{
+ Mode({required this.isRepeat, required this.isSingle, required this.prev});
+
+ final bool isSingle;
+ final bool isRepeat;
+ final bool prev;
+
+
+ Mode copyWith({bool? isSingle , bool? isRepeat, bool? prev}){
+ return Mode(isRepeat: isRepeat ?? this.isRepeat, isSingle: isSingle ?? this.isSingle, prev: prev ?? this.prev);
+ }
+
+
+} \ No newline at end of file
diff --git a/lib/music_methods/mpd.dart b/lib/music_methods/mpd.dart
new file mode 100644
index 0000000..124a5d4
--- /dev/null
+++ b/lib/music_methods/mpd.dart
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: Apache-2.0
+library MPD;
+
+import "dart:async";
+import "dart:io";
+
+
+
+
+/**
+ * An error for MPD.
+ */
+class MPDError extends Error {
+ String msg;
+ MPDError(this.msg) : super();
+
+ String toString() {
+ return "MPD Error: $msg";
+ }
+} \ No newline at end of file
diff --git a/lib/music_methods/musicProvider.dart b/lib/music_methods/musicProvider.dart
new file mode 100644
index 0000000..0e4d450
--- /dev/null
+++ b/lib/music_methods/musicProvider.dart
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: Apache-2.0
+import 'package:flutter/widgets.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:musicplayer/class.dart';
+import 'package:musicplayer/music_methods/modeClass.dart';
+
+final PositionProvider = StateNotifierProvider<Position,Duration>(((ref) => Position()));
+
+class Position extends StateNotifier<Duration>{
+ Position() : super(Duration(seconds: 0));
+ void update(value) async{
+ state = value;
+ }
+
+
+}
+
+final CurrentSongProvider = StateNotifierProvider<Current, CurrentSong>(((ref) => Current()));
+
+class Current extends StateNotifier<CurrentSong>{
+ Current() : super(currentval);
+ static final CurrentSong currentval = CurrentSong(title: 'title', artist: 'unknown', duration: '0min 0sec',isPlaying: false, time: '0');
+
+ void update({ String? title, String? artist, String? duration, bool? isPlaying, String? time}){
+ state = state.copyWith(title: title, artist: artist, duration: duration, isPlaying: isPlaying,time: time);
+ }
+
+}
+
+final VolumeProvider = StateNotifierProvider<Volume,int>(((ref) => Volume()));
+
+class Volume extends StateNotifier<int>{
+ Volume() : super(70);
+
+ void update(int val){
+ state = val;
+ }
+
+}
+
+final Modeprovider = StateNotifierProvider<mode,Mode>(((ref) => mode()));
+
+class mode extends StateNotifier<Mode>{
+ mode() : super(intial_value);
+ static final Mode intial_value = Mode(isRepeat: true, isSingle : false, prev: true);
+
+ void update({bool? isSingle, bool? isRepeat, bool? prev}){
+ state = state.copyWith(isRepeat : isRepeat, isSingle : isSingle,prev: prev);
+ }
+
+}
+
+final currIndexProvider = StateNotifierProvider<Index,int>(((ref) => Index()));
+
+class Index extends StateNotifier<int>{
+ Index() : super(0);
+
+ void update(int val){
+ state = val;
+ }
+
+}
+
+
diff --git a/lib/nomusic.dart b/lib/nomusic.dart
new file mode 100644
index 0000000..8fd8b67
--- /dev/null
+++ b/lib/nomusic.dart
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: Apache-2.0
+import 'package:flutter/material.dart';
+import 'package:flutter/src/foundation/key.dart';
+import 'package:flutter/src/widgets/framework.dart';
+
+class NoMusicFound extends StatelessWidget {
+ const NoMusicFound({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: SafeArea(child: Center(child: Container(
+ height: MediaQuery.of(context).size.height*0.5,
+ width: MediaQuery.of(context).size.width*0.5,
+ color: Colors.white,
+ child: const Center(
+ child: Text("NO MUSIC FILE FOUND IN THE MUSIC DIRECTORY!!!!", style: TextStyle(
+ fontSize: 30,
+ color: Colors.black,
+
+
+ ),),
+ ),
+ ),)),
+ );
+ }
+} \ No newline at end of file
diff --git a/lib/playlistLoading.dart b/lib/playlistLoading.dart
new file mode 100644
index 0000000..e643323
--- /dev/null
+++ b/lib/playlistLoading.dart
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'package:flutter/material.dart';
+import 'package:flutter/src/foundation/key.dart';
+import 'package:flutter/src/widgets/framework.dart';
+import 'package:musicplayer/musicPage.dart';
+import 'package:musicplayer/nomusic.dart';
+
+import 'music_methods/controller.dart';
+
+class PlaylistLoading extends StatelessWidget {
+ PlaylistLoading({Key? key}) : super(key: key);
+
+
+
+
+ @override
+
+ MPDTalker mpdTalker = MPDTalker();
+ List<Map<String, String>> playlist = [];
+
+
+
+ String convertToMin(String str){
+ String strforint = '';
+ for(int i = 0; i<str.length;i++){
+ if(str[i] == '.'){
+ break;
+ }
+ strforint += str[i];
+ }
+ int num = int.parse(strforint);
+ double min = num/60;
+ double sec = num%60;
+ String ans = min.toInt().toString()+'min ' + sec.toInt().toString()+'sec';
+ return ans;
+
+ }
+
+
+ Future mymethod() async{
+ playlist = await mpdTalker.cmdListMap('playlistinfo');
+ return playlist;
+
+ }
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: FutureBuilder(
+ future: mymethod(),
+ builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
+
+ if (snapshot.connectionState == ConnectionState.done) {
+ // If we got an error
+ if (snapshot.hasError) {
+ return Center(
+ child: Text(
+ '${snapshot.error} occurred',
+ style: TextStyle(fontSize: 18, color: Colors.black),
+ ),
+ );
+
+ // if we got our data
+ } else if (snapshot.hasData) {
+ // Extracting data from snapshot object
+ List<Map<String, String>> list = snapshot.data as dynamic;
+
+ if(list.isNotEmpty){
+
+ mpdTalker.cmd('repeat 1');
+ mpdTalker.cmd('single 0');
+ mpdTalker.cmd('consume 0');
+ mpdTalker.cmd('play');
+ mpdTalker.cmd('pause 1');
+
+
+
+
+ return MusicPageTest(list : list,);
+
+ }
+ else{
+ return const NoMusicFound();
+
+ }
+
+
+
+
+
+
+
+ } else if(snapshot.data == null){
+ return const NoMusicFound();
+
+ }
+
+ }
+ return Center(
+ child: CircularProgressIndicator(
+ color: Colors.black,
+ ),
+ );
+
+ },
+ ),
+ );
+
+ }
+} \ No newline at end of file
diff --git a/lib/size.dart b/lib/size.dart
new file mode 100644
index 0000000..7018a81
--- /dev/null
+++ b/lib/size.dart
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: Apache-2.0
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+
+class SizeConfig {
+ static late MediaQueryData _mediaQueryData;
+ static late double screenWidth;
+ static late double screenHeight;
+ static late double blockSizeHorizontal;
+ static late double blockSizeVertical;
+ static late double _safeAreaHorizontal;
+ static late double _safeAreaVertical;
+ static late double safeBlockHorizontal;
+ static late double safeBlockVertical;
+ static late double fontsize;
+ static late TextStyle normalfont;
+ static late TextStyle smallnormalfont;
+
+ void init(BuildContext context) {
+ _mediaQueryData = MediaQuery.of(context);
+ screenWidth = _mediaQueryData.size.width;
+ screenHeight = _mediaQueryData.size.height;
+ blockSizeHorizontal = screenWidth / 100;
+ blockSizeVertical = screenHeight / 100;
+ _safeAreaHorizontal =
+ _mediaQueryData.padding.left + _mediaQueryData.padding.right;
+ _safeAreaVertical =
+ _mediaQueryData.padding.top + _mediaQueryData.padding.bottom;
+ safeBlockHorizontal = (screenWidth - _safeAreaHorizontal) / 100;
+ safeBlockVertical = (screenHeight - _safeAreaVertical) / 100;
+ fontsize = screenHeight * screenWidth * 0.01 * 0.01 * 0.4;
+ normalfont = TextStyle(
+ fontSize: fontsize * 0.8,
+ fontWeight: FontWeight.w700,
+ color: Colors.white,
+ );
+ smallnormalfont = TextStyle(
+ fontSize: fontsize / 2,
+ fontWeight: FontWeight.w700,
+ color: Colors.white,
+ );
+ }
+} \ No newline at end of file
diff --git a/lib/socketProblem.dart b/lib/socketProblem.dart
new file mode 100644
index 0000000..af4b2b5
--- /dev/null
+++ b/lib/socketProblem.dart
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: Apache-2.0
+import 'package:flutter/material.dart';
+import 'package:flutter/src/foundation/key.dart';
+import 'package:flutter/src/widgets/framework.dart';
+
+class SocketProblem extends StatelessWidget {
+ const SocketProblem({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+
+ return Scaffold(
+ body: SafeArea(child: Center(child: Container(
+ height: MediaQuery.of(context).size.height*0.5,
+ width: MediaQuery.of(context).size.width*0.5,
+ color: Colors.white,
+ child: const Center(
+ child: Text("Unable to Connect with MPD server", style: TextStyle(
+ fontSize: 30,
+ color: Colors.black,
+
+
+ ),),
+ ),
+ ),)),
+ );
+
+ }
+} \ No newline at end of file
diff --git a/pubspec.yaml b/pubspec.yaml
new file mode 100644
index 0000000..a7b2c3c
--- /dev/null
+++ b/pubspec.yaml
@@ -0,0 +1,90 @@
+name: musicplayer
+description: A new Flutter project.
+
+# The following line prevents the package from being accidentally published to
+# pub.dev using `flutter pub publish`. This is preferred for private packages.
+publish_to: 'none' # Remove this line if you wish to publish to pub.dev
+
+# The following defines the version and build number for your application.
+# A version number is three numbers separated by dots, like 1.2.43
+# followed by an optional build number separated by a +.
+# Both the version and the builder number may be overridden in flutter
+# build by specifying --build-name and --build-number, respectively.
+# In Android, build-name is used as versionName while build-number used as versionCode.
+# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
+# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
+# Read more about iOS versioning at
+# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
+version: 1.0.0+1
+
+environment:
+ sdk: ">=2.17.6 <3.0.0"
+
+# Dependencies specify other packages that your package needs in order to work.
+# To automatically upgrade your package dependencies to the latest versions
+# consider running `flutter pub upgrade --major-versions`. Alternatively,
+# dependencies can be manually updated by changing the version numbers below to
+# the latest version available on pub.dev. To see which dependencies have newer
+# versions available, run `flutter pub outdated`.
+dependencies:
+ flutter:
+ sdk: flutter
+
+
+ # The following adds the Cupertino Icons font to your application.
+ # Use with the CupertinoIcons class for iOS style icons.
+ cupertino_icons: ^1.0.2
+ flutter_riverpod: ^1.0.4
+ badges: ^2.0.3
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+
+ # The "flutter_lints" package below contains a set of recommended lints to
+ # encourage good coding practices. The lint set provided by the package is
+ # activated in the `analysis_options.yaml` file located at the root of your
+ # package. See that file for information about deactivating specific lint
+ # rules and activating additional ones.
+ flutter_lints: ^2.0.0
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+# The following section is specific to Flutter packages.
+flutter:
+
+ # The following line ensures that the Material Icons font is
+ # included with your application, so that you can use the icons in
+ # the material Icons class.
+ uses-material-design: true
+
+ # To add assets to your application, add an assets section, like this:
+ assets:
+ - assets/
+
+ # An image asset can refer to one or more resolution-specific "variants", see
+ # https://flutter.dev/assets-and-images/#resolution-aware
+
+ # For details regarding adding assets from package dependencies, see
+ # https://flutter.dev/assets-and-images/#from-packages
+
+ # To add custom fonts to your application, add a fonts section here,
+ # in this "flutter" section. Each entry in this list should have a
+ # "family" key with the font family name, and a "fonts" key with a
+ # list giving the asset and other descriptors for the font. For
+ # example:
+ # fonts:
+ # - family: Schyler
+ # fonts:
+ # - asset: fonts/Schyler-Regular.ttf
+ # - asset: fonts/Schyler-Italic.ttf
+ # style: italic
+ # - family: Trajan Pro
+ # fonts:
+ # - asset: fonts/TrajanPro.ttf
+ # - asset: fonts/TrajanPro_Bold.ttf
+ # weight: 700
+ #
+ # For details regarding fonts from package dependencies,
+ # see https://flutter.dev/custom-fonts/#from-packages