├── .gitignore
├── .metadata
├── README.md
├── android
├── app
│ ├── build.gradle
│ ├── google-services.json
│ ├── proguard-rules.pro
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── janhrastnik
│ │ │ └── musicplayer2
│ │ │ └── MainActivity.java
│ │ └── res
│ │ ├── drawable
│ │ └── launch_background.xml
│ │ ├── mipmap-hdpi
│ │ └── icon.png
│ │ ├── mipmap-mdpi
│ │ └── icon.png
│ │ ├── mipmap-xhdpi
│ │ └── icon.png
│ │ ├── mipmap-xxhdpi
│ │ └── icon.png
│ │ ├── mipmap-xxxhdpi
│ │ └── icon.png
│ │ └── values
│ │ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── images
├── flower.jpg
├── icon3-192.png
└── noimage.png
├── ios
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ └── contents.xcworkspacedata
└── Runner
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-1024x1024@1x.png
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ └── Icon-App-83.5x83.5@2x.png
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ └── main.m
├── lib
├── artistpage.dart
├── config.dart
├── favourites.dart
├── home.dart
├── library.dart
├── main.dart
├── musicplayer.dart
├── permissions.dart
├── playingpage.dart
├── playlistpage.dart
├── splashpage.dart
└── wave.dart
├── pubspec.yaml
├── screenshots
├── 1.png
├── 2.png
└── 3.png
└── test
└── widget_test.dart
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.lock
4 | *.log
5 | *.pyc
6 | *.swp
7 | .DS_Store
8 | .atom/
9 | .buildlog/
10 | .history
11 | .svn/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # Visual Studio Code related
20 | .vscode/
21 |
22 | # Flutter/Dart/Pub related
23 | **/doc/api/
24 | .dart_tool/
25 | .flutter-plugins
26 | .packages
27 | .pub-cache/
28 | .pub/
29 | build/
30 |
31 | # Android related
32 | **/android/**/gradle-wrapper.jar
33 | **/android/.gradle
34 | **/android/captures/
35 | **/android/gradlew
36 | **/android/gradlew.bat
37 | **/android/local.properties
38 | **/android/**/GeneratedPluginRegistrant.java
39 | key.properties
40 |
41 | # iOS/XCode related
42 | **/ios/**/*.mode1v3
43 | **/ios/**/*.mode2v3
44 | **/ios/**/*.moved-aside
45 | **/ios/**/*.pbxuser
46 | **/ios/**/*.perspectivev3
47 | **/ios/**/*sync/
48 | **/ios/**/.sconsign.dblite
49 | **/ios/**/.tags*
50 | **/ios/**/.vagrant/
51 | **/ios/**/DerivedData/
52 | **/ios/**/Icon?
53 | **/ios/**/Pods/
54 | **/ios/**/.symlinks/
55 | **/ios/**/profile
56 | **/ios/**/xcuserdata
57 | **/ios/.generated/
58 | **/ios/Flutter/App.framework
59 | **/ios/Flutter/Flutter.framework
60 | **/ios/Flutter/Generated.xcconfig
61 | **/ios/Flutter/app.flx
62 | **/ios/Flutter/app.zip
63 | **/ios/Flutter/flutter_assets/
64 | **/ios/ServiceDefinitions.json
65 | **/ios/Runner/GeneratedPluginRegistrant.*
66 |
67 | # Exceptions to above rules.
68 | !**/ios/**/default.mode1v3
69 | !**/ios/**/default.mode2v3
70 | !**/ios/**/default.pbxuser
71 | !**/ios/**/default.perspectivev3
72 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
73 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: f37c235c32fc15babe6dc7b7bc2ee4387e5ecf92
8 | channel: beta
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Nano Music Player 
2 |
3 | Simple local music player built with flutter. It uses the [audioplayer](https://pub.dartlang.org/packages/audioplayer#-readme-tab-) plugin to play files, and [path_provider](https://pub.dartlang.org/packages/path_provider#-readme-tab-) to locate the external directory and search it for playable files. Metadata is gathered through native java code. I also used this [Waves widget](https://github.com/i-protoss/wave). You can download the app from [Google Play](https://play.google.com/store/apps/details?id=janhrastnik.musicplayer2).
4 |
5 | # Screenshots
6 | 

7 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
26 |
27 | android {
28 | compileSdkVersion 27
29 |
30 | compileOptions {
31 | sourceCompatibility JavaVersion.VERSION_1_8
32 | targetCompatibility JavaVersion.VERSION_1_8
33 | }
34 |
35 | lintOptions {
36 | disable 'InvalidPackage'
37 | }
38 |
39 | defaultConfig {
40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
41 | applicationId "janhrastnik.musicplayer2"
42 | minSdkVersion 19
43 | targetSdkVersion 27
44 | versionCode flutterVersionCode.toInteger()
45 | versionName flutterVersionName
46 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
47 | }
48 |
49 | signingConfigs {
50 |
51 | }
52 | buildTypes {
53 | release {
54 | signingConfig signingConfigs.debug
55 |
56 | useProguard true
57 |
58 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
59 | }
60 | }
61 | }
62 |
63 | flutter {
64 | source '../..'
65 | }
66 |
67 | dependencies {
68 | testImplementation 'junit:junit:4.12'
69 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
70 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
71 | implementation 'com.mpatric:mp3agic:0.9.1'
72 | }
--------------------------------------------------------------------------------
/android/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "500480221380",
4 | "firebase_url": "https://musicplayer-5b840.firebaseio.com",
5 | "project_id": "musicplayer-5b840",
6 | "storage_bucket": "musicplayer-5b840.appspot.com"
7 | },
8 | "client": [
9 | {
10 | "client_info": {
11 | "mobilesdk_app_id": "1:500480221380:android:8e5e93b5302c1f0f",
12 | "android_client_info": {
13 | "package_name": "janhrastnik.musicplayer2"
14 | }
15 | },
16 | "oauth_client": [
17 | {
18 | "client_id": "500480221380-m4ntu6g4e88o288iv2hmutp3v1u8ti4b.apps.googleusercontent.com",
19 | "client_type": 3
20 | }
21 | ],
22 | "api_key": [
23 | {
24 | "current_key": "AIzaSyBzdEMjZiuAR-Dt1IrhyFmF0rGUwwntzSs"
25 | }
26 | ],
27 | "services": {
28 | "analytics_service": {
29 | "status": 1
30 | },
31 | "appinvite_service": {
32 | "status": 1,
33 | "other_platform_oauth_client": []
34 | },
35 | "ads_service": {
36 | "status": 2
37 | }
38 | }
39 | }
40 | ],
41 | "configuration_version": "1"
42 | }
--------------------------------------------------------------------------------
/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | #Flutter Wrapper
2 | -keep class io.flutter.app.** { *; }
3 | -keep class io.flutter.plugin.** { *; }
4 | -keep class io.flutter.util.** { *; }
5 | -keep class io.flutter.view.** { *; }
6 | -keep class io.flutter.** { *; }
7 | -keep class io.flutter.plugins.** { *; }
8 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
9 |
10 |
11 |
12 |
17 |
22 |
29 |
33 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/android/app/src/main/java/janhrastnik/musicplayer2/MainActivity.java:
--------------------------------------------------------------------------------
1 | package janhrastnik.musicplayer2;
2 |
3 | import android.graphics.Bitmap;
4 | import android.media.MediaMetadataRetriever;
5 | import android.os.Bundle;
6 | import android.renderscript.Sampler;
7 |
8 | import io.flutter.app.FlutterActivity;
9 | import io.flutter.plugin.common.MethodCall;
10 | import io.flutter.plugin.common.MethodChannel;
11 | import io.flutter.plugins.GeneratedPluginRegistrant;
12 | import com.mpatric.mp3agic.*;
13 |
14 | import java.io.IOException;
15 | import java.util.ArrayList;
16 | import java.util.List;
17 | import java.util.Map;
18 |
19 | public class MainActivity extends FlutterActivity {
20 | private static final String CHANNEL = "demo.janhrastnik.com/info";
21 | private static final MediaMetadataRetriever mmr = new MediaMetadataRetriever();
22 |
23 | @Override
24 | protected void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | GeneratedPluginRegistrant.registerWith(this);
27 |
28 | new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(new MethodChannel.MethodCallHandler() {
29 | @Override
30 | public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
31 | Map arguments = methodCall.arguments();
32 | if (methodCall.method.equals("getMetaData")) {
33 | String filepath = (String) arguments.get("filepath");
34 | System.out.println(filepath);
35 | List l = new ArrayList();
36 | mmr.setDataSource(filepath);
37 | l.add(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE));
38 | l.add(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST));
39 | try {
40 | l.add(mmr.getEmbeddedPicture());
41 | } catch (Exception e) {
42 | l.add(null);
43 | }
44 | l.add(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM));
45 | l.add(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER));
46 | result.success(l);
47 | } else if (methodCall.method.equals("getSdCardPath")) {
48 | String removableStoragePath = null;
49 | try {
50 | removableStoragePath = getExternalCacheDirs()[1].toString();
51 | } catch (Exception e) {
52 | }
53 | result.success(removableStoragePath);
54 | }
55 |
56 | }
57 | });
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/android/app/src/main/res/mipmap-hdpi/icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/android/app/src/main/res/mipmap-mdpi/icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/android/app/src/main/res/mipmap-xhdpi/icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/android/app/src/main/res/mipmap-xxhdpi/icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/android/app/src/main/res/mipmap-xxxhdpi/icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | jcenter()
5 | }
6 |
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:3.2.1'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | google()
15 | jcenter()
16 | }
17 | }
18 |
19 | rootProject.buildDir = '../build'
20 | subprojects {
21 | project.buildDir = "${rootProject.buildDir}/${project.name}"
22 | }
23 | subprojects {
24 | project.evaluationDependsOn(':app')
25 | project.configurations.all {
26 |
27 | resolutionStrategy.eachDependency { details ->
28 |
29 | if (details.requested.group == 'com.android.support'
30 | && !details.requested.name.contains('multidex') ) {
31 | details.useVersion "27.1.0"
32 | }
33 | }
34 | }
35 | }
36 |
37 | task clean(type: Delete) {
38 | delete rootProject.buildDir
39 | }
40 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Jan 12 12:56:32 CET 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
7 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/images/flower.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/images/flower.jpg
--------------------------------------------------------------------------------
/images/icon3-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/images/icon3-192.png
--------------------------------------------------------------------------------
/images/noimage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/images/noimage.png
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; };
12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
13 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
14 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
15 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
16 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
17 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
18 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
19 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
20 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
21 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
22 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
23 | /* End PBXBuildFile section */
24 |
25 | /* Begin PBXCopyFilesBuildPhase section */
26 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
27 | isa = PBXCopyFilesBuildPhase;
28 | buildActionMask = 2147483647;
29 | dstPath = "";
30 | dstSubfolderSpec = 10;
31 | files = (
32 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
33 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
34 | );
35 | name = "Embed Frameworks";
36 | runOnlyForDeploymentPostprocessing = 0;
37 | };
38 | /* End PBXCopyFilesBuildPhase section */
39 |
40 | /* Begin PBXFileReference section */
41 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
42 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
43 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
44 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
45 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; };
46 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
47 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
48 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
49 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
50 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
51 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; };
52 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
53 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
54 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
55 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
56 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
57 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
58 | /* End PBXFileReference section */
59 |
60 | /* Begin PBXFrameworksBuildPhase section */
61 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
62 | isa = PBXFrameworksBuildPhase;
63 | buildActionMask = 2147483647;
64 | files = (
65 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
66 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
67 | );
68 | runOnlyForDeploymentPostprocessing = 0;
69 | };
70 | /* End PBXFrameworksBuildPhase section */
71 |
72 | /* Begin PBXGroup section */
73 | 9740EEB11CF90186004384FC /* Flutter */ = {
74 | isa = PBXGroup;
75 | children = (
76 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */,
77 | 3B80C3931E831B6300D905FE /* App.framework */,
78 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
79 | 9740EEBA1CF902C7004384FC /* Flutter.framework */,
80 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
81 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
82 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
83 | );
84 | name = Flutter;
85 | sourceTree = "";
86 | };
87 | 97C146E51CF9000F007C117D = {
88 | isa = PBXGroup;
89 | children = (
90 | 9740EEB11CF90186004384FC /* Flutter */,
91 | 97C146F01CF9000F007C117D /* Runner */,
92 | 97C146EF1CF9000F007C117D /* Products */,
93 | CF3B75C9A7D2FA2A4C99F110 /* Frameworks */,
94 | );
95 | sourceTree = "";
96 | };
97 | 97C146EF1CF9000F007C117D /* Products */ = {
98 | isa = PBXGroup;
99 | children = (
100 | 97C146EE1CF9000F007C117D /* Runner.app */,
101 | );
102 | name = Products;
103 | sourceTree = "";
104 | };
105 | 97C146F01CF9000F007C117D /* Runner */ = {
106 | isa = PBXGroup;
107 | children = (
108 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
109 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
110 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
111 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
112 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
113 | 97C147021CF9000F007C117D /* Info.plist */,
114 | 97C146F11CF9000F007C117D /* Supporting Files */,
115 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
116 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
117 | );
118 | path = Runner;
119 | sourceTree = "";
120 | };
121 | 97C146F11CF9000F007C117D /* Supporting Files */ = {
122 | isa = PBXGroup;
123 | children = (
124 | 97C146F21CF9000F007C117D /* main.m */,
125 | );
126 | name = "Supporting Files";
127 | sourceTree = "";
128 | };
129 | /* End PBXGroup section */
130 |
131 | /* Begin PBXNativeTarget section */
132 | 97C146ED1CF9000F007C117D /* Runner */ = {
133 | isa = PBXNativeTarget;
134 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
135 | buildPhases = (
136 | 9740EEB61CF901F6004384FC /* Run Script */,
137 | 97C146EA1CF9000F007C117D /* Sources */,
138 | 97C146EB1CF9000F007C117D /* Frameworks */,
139 | 97C146EC1CF9000F007C117D /* Resources */,
140 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
141 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
142 | );
143 | buildRules = (
144 | );
145 | dependencies = (
146 | );
147 | name = Runner;
148 | productName = Runner;
149 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
150 | productType = "com.apple.product-type.application";
151 | };
152 | /* End PBXNativeTarget section */
153 |
154 | /* Begin PBXProject section */
155 | 97C146E61CF9000F007C117D /* Project object */ = {
156 | isa = PBXProject;
157 | attributes = {
158 | LastUpgradeCheck = 0910;
159 | ORGANIZATIONNAME = "The Chromium Authors";
160 | TargetAttributes = {
161 | 97C146ED1CF9000F007C117D = {
162 | CreatedOnToolsVersion = 7.3.1;
163 | };
164 | };
165 | };
166 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
167 | compatibilityVersion = "Xcode 3.2";
168 | developmentRegion = English;
169 | hasScannedForEncodings = 0;
170 | knownRegions = (
171 | en,
172 | Base,
173 | );
174 | mainGroup = 97C146E51CF9000F007C117D;
175 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
176 | projectDirPath = "";
177 | projectRoot = "";
178 | targets = (
179 | 97C146ED1CF9000F007C117D /* Runner */,
180 | );
181 | };
182 | /* End PBXProject section */
183 |
184 | /* Begin PBXResourcesBuildPhase section */
185 | 97C146EC1CF9000F007C117D /* Resources */ = {
186 | isa = PBXResourcesBuildPhase;
187 | buildActionMask = 2147483647;
188 | files = (
189 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
190 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
191 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
192 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
193 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */,
194 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
195 | );
196 | runOnlyForDeploymentPostprocessing = 0;
197 | };
198 | /* End PBXResourcesBuildPhase section */
199 |
200 | /* Begin PBXShellScriptBuildPhase section */
201 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
202 | isa = PBXShellScriptBuildPhase;
203 | buildActionMask = 2147483647;
204 | files = (
205 | );
206 | inputPaths = (
207 | );
208 | name = "Thin Binary";
209 | outputPaths = (
210 | );
211 | runOnlyForDeploymentPostprocessing = 0;
212 | shellPath = /bin/sh;
213 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
214 | };
215 | 9740EEB61CF901F6004384FC /* Run Script */ = {
216 | isa = PBXShellScriptBuildPhase;
217 | buildActionMask = 2147483647;
218 | files = (
219 | );
220 | inputPaths = (
221 | );
222 | name = "Run Script";
223 | outputPaths = (
224 | );
225 | runOnlyForDeploymentPostprocessing = 0;
226 | shellPath = /bin/sh;
227 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
228 | };
229 | /* End PBXShellScriptBuildPhase section */
230 |
231 | /* Begin PBXSourcesBuildPhase section */
232 | 97C146EA1CF9000F007C117D /* Sources */ = {
233 | isa = PBXSourcesBuildPhase;
234 | buildActionMask = 2147483647;
235 | files = (
236 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
237 | 97C146F31CF9000F007C117D /* main.m in Sources */,
238 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
239 | );
240 | runOnlyForDeploymentPostprocessing = 0;
241 | };
242 | /* End PBXSourcesBuildPhase section */
243 |
244 | /* Begin PBXVariantGroup section */
245 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
246 | isa = PBXVariantGroup;
247 | children = (
248 | 97C146FB1CF9000F007C117D /* Base */,
249 | );
250 | name = Main.storyboard;
251 | sourceTree = "";
252 | };
253 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
254 | isa = PBXVariantGroup;
255 | children = (
256 | 97C147001CF9000F007C117D /* Base */,
257 | );
258 | name = LaunchScreen.storyboard;
259 | sourceTree = "";
260 | };
261 | /* End PBXVariantGroup section */
262 |
263 | /* Begin XCBuildConfiguration section */
264 | 97C147031CF9000F007C117D /* Debug */ = {
265 | isa = XCBuildConfiguration;
266 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
267 | buildSettings = {
268 | ALWAYS_SEARCH_USER_PATHS = NO;
269 | CLANG_ANALYZER_NONNULL = YES;
270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
271 | CLANG_CXX_LIBRARY = "libc++";
272 | CLANG_ENABLE_MODULES = YES;
273 | CLANG_ENABLE_OBJC_ARC = YES;
274 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
275 | CLANG_WARN_BOOL_CONVERSION = YES;
276 | CLANG_WARN_COMMA = YES;
277 | CLANG_WARN_CONSTANT_CONVERSION = YES;
278 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
279 | CLANG_WARN_EMPTY_BODY = YES;
280 | CLANG_WARN_ENUM_CONVERSION = YES;
281 | CLANG_WARN_INFINITE_RECURSION = YES;
282 | CLANG_WARN_INT_CONVERSION = YES;
283 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
284 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
285 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
286 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
287 | CLANG_WARN_STRICT_PROTOTYPES = YES;
288 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
289 | CLANG_WARN_UNREACHABLE_CODE = YES;
290 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
291 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
292 | COPY_PHASE_STRIP = NO;
293 | DEBUG_INFORMATION_FORMAT = dwarf;
294 | ENABLE_STRICT_OBJC_MSGSEND = YES;
295 | ENABLE_TESTABILITY = YES;
296 | GCC_C_LANGUAGE_STANDARD = gnu99;
297 | GCC_DYNAMIC_NO_PIC = NO;
298 | GCC_NO_COMMON_BLOCKS = YES;
299 | GCC_OPTIMIZATION_LEVEL = 0;
300 | GCC_PREPROCESSOR_DEFINITIONS = (
301 | "DEBUG=1",
302 | "$(inherited)",
303 | );
304 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
305 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
306 | GCC_WARN_UNDECLARED_SELECTOR = YES;
307 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
308 | GCC_WARN_UNUSED_FUNCTION = YES;
309 | GCC_WARN_UNUSED_VARIABLE = YES;
310 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
311 | MTL_ENABLE_DEBUG_INFO = YES;
312 | ONLY_ACTIVE_ARCH = YES;
313 | SDKROOT = iphoneos;
314 | TARGETED_DEVICE_FAMILY = "1,2";
315 | };
316 | name = Debug;
317 | };
318 | 97C147041CF9000F007C117D /* Release */ = {
319 | isa = XCBuildConfiguration;
320 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
321 | buildSettings = {
322 | ALWAYS_SEARCH_USER_PATHS = NO;
323 | CLANG_ANALYZER_NONNULL = YES;
324 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
325 | CLANG_CXX_LIBRARY = "libc++";
326 | CLANG_ENABLE_MODULES = YES;
327 | CLANG_ENABLE_OBJC_ARC = YES;
328 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
329 | CLANG_WARN_BOOL_CONVERSION = YES;
330 | CLANG_WARN_COMMA = YES;
331 | CLANG_WARN_CONSTANT_CONVERSION = YES;
332 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
333 | CLANG_WARN_EMPTY_BODY = YES;
334 | CLANG_WARN_ENUM_CONVERSION = YES;
335 | CLANG_WARN_INFINITE_RECURSION = YES;
336 | CLANG_WARN_INT_CONVERSION = YES;
337 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
338 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
339 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
340 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
341 | CLANG_WARN_STRICT_PROTOTYPES = YES;
342 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
343 | CLANG_WARN_UNREACHABLE_CODE = YES;
344 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
345 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
346 | COPY_PHASE_STRIP = NO;
347 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
348 | ENABLE_NS_ASSERTIONS = NO;
349 | ENABLE_STRICT_OBJC_MSGSEND = YES;
350 | GCC_C_LANGUAGE_STANDARD = gnu99;
351 | GCC_NO_COMMON_BLOCKS = YES;
352 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
353 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
354 | GCC_WARN_UNDECLARED_SELECTOR = YES;
355 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
356 | GCC_WARN_UNUSED_FUNCTION = YES;
357 | GCC_WARN_UNUSED_VARIABLE = YES;
358 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
359 | MTL_ENABLE_DEBUG_INFO = NO;
360 | SDKROOT = iphoneos;
361 | TARGETED_DEVICE_FAMILY = "1,2";
362 | VALIDATE_PRODUCT = YES;
363 | };
364 | name = Release;
365 | };
366 | 97C147061CF9000F007C117D /* Debug */ = {
367 | isa = XCBuildConfiguration;
368 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
369 | buildSettings = {
370 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
371 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
372 | ENABLE_BITCODE = NO;
373 | FRAMEWORK_SEARCH_PATHS = (
374 | "$(inherited)",
375 | "$(PROJECT_DIR)/Flutter",
376 | );
377 | INFOPLIST_FILE = Runner/Info.plist;
378 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
379 | LIBRARY_SEARCH_PATHS = (
380 | "$(inherited)",
381 | "$(PROJECT_DIR)/Flutter",
382 | );
383 | PRODUCT_BUNDLE_IDENTIFIER = janhrastnik.musicplayer2;
384 | PRODUCT_NAME = "$(TARGET_NAME)";
385 | VERSIONING_SYSTEM = "apple-generic";
386 | };
387 | name = Debug;
388 | };
389 | 97C147071CF9000F007C117D /* Release */ = {
390 | isa = XCBuildConfiguration;
391 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
392 | buildSettings = {
393 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
394 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
395 | ENABLE_BITCODE = NO;
396 | FRAMEWORK_SEARCH_PATHS = (
397 | "$(inherited)",
398 | "$(PROJECT_DIR)/Flutter",
399 | );
400 | INFOPLIST_FILE = Runner/Info.plist;
401 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
402 | LIBRARY_SEARCH_PATHS = (
403 | "$(inherited)",
404 | "$(PROJECT_DIR)/Flutter",
405 | );
406 | PRODUCT_BUNDLE_IDENTIFIER = janhrastnik.musicplayer2;
407 | PRODUCT_NAME = "$(TARGET_NAME)";
408 | VERSIONING_SYSTEM = "apple-generic";
409 | };
410 | name = Release;
411 | };
412 | /* End XCBuildConfiguration section */
413 |
414 | /* Begin XCConfigurationList section */
415 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
416 | isa = XCConfigurationList;
417 | buildConfigurations = (
418 | 97C147031CF9000F007C117D /* Debug */,
419 | 97C147041CF9000F007C117D /* Release */,
420 | );
421 | defaultConfigurationIsVisible = 0;
422 | defaultConfigurationName = Release;
423 | };
424 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
425 | isa = XCConfigurationList;
426 | buildConfigurations = (
427 | 97C147061CF9000F007C117D /* Debug */,
428 | 97C147071CF9000F007C117D /* Release */,
429 | );
430 | defaultConfigurationIsVisible = 0;
431 | defaultConfigurationName = Release;
432 | };
433 | /* End XCConfigurationList section */
434 | };
435 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
436 | }
437 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
40 |
41 |
42 |
43 |
44 |
45 |
56 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
75 |
77 |
83 |
84 |
85 |
86 |
88 |
89 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface AppDelegate : FlutterAppDelegate
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.m:
--------------------------------------------------------------------------------
1 | #include "AppDelegate.h"
2 | #include "GeneratedPluginRegistrant.h"
3 |
4 | @implementation AppDelegate
5 |
6 | - (BOOL)application:(UIApplication *)application
7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
8 | [GeneratedPluginRegistrant registerWithRegistry:self];
9 | // Override point for customization after application launch.
10 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
11 | }
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | musicplayer2
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/ios/Runner/main.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char* argv[]) {
6 | @autoreleasepool {
7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/lib/artistpage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'musicplayer.dart' as musicplayer;
3 | import 'playingpage.dart';
4 |
5 | class ArtistPage extends StatefulWidget {
6 | ArtistPageState createState() => ArtistPageState();
7 | }
8 |
9 | class ArtistPageState extends State {
10 | Map artists = Map();
11 |
12 | List artistsNames;
13 |
14 | @override
15 | void initState() {
16 | for (var track in musicplayer.allMetaData) {
17 | if (artists.containsKey(track[1]) == false) {
18 | artists[track[1]] = [track[0]];
19 | } else {
20 | var l = artists[track[1]];
21 | l.add(track[0]);
22 | artists.update(track[1], (value) => l);
23 | }
24 | }
25 | artistsNames = artists.keys.toList();
26 | super.initState();
27 | }
28 |
29 | @override
30 | Widget build(BuildContext context) {
31 | return Scaffold(
32 | appBar: AppBar(
33 | title: Text("Artists"),
34 | ),
35 | drawer: musicplayer.AppDrawer(),
36 | body: ListView.builder(
37 | itemCount: artists.length,
38 | itemBuilder: (BuildContext context, int index) => ListTile(
39 | title: Text(artistsNames[index]),
40 | onTap: () {
41 | Navigator.of(context).push(MaterialPageRoute(
42 | builder: (BuildContext context) => ShowArtistAlbums(
43 | artistName: artistsNames[index],
44 | )));
45 | },
46 | )),
47 | );
48 | }
49 | }
50 |
51 | class ShowArtistAlbums extends StatefulWidget {
52 | String artistName;
53 |
54 | ShowArtistAlbums({Key key, @required this.artistName}) : super(key: key);
55 |
56 | ShowArtistAlbumsState createState() => ShowArtistAlbumsState();
57 | }
58 |
59 | class ShowArtistAlbumsState extends State {
60 | Map albums = Map();
61 |
62 | List albumsNames;
63 |
64 | @override
65 | void initState() {
66 | super.initState();
67 | for (var track in musicplayer.allMetaData) {
68 | if (track[1] == widget.artistName) {
69 | if (albums.containsKey(track[3]) == false) {
70 | albums[track[3]] = [[track[0], track[4]]];
71 | } else {
72 | var l = albums[track[3]];
73 | l.add([track[0], track[4]]);
74 | albums.update(track[3], (value) => l);
75 | }
76 | }
77 | }
78 | albumsNames = albums.keys.toList();
79 | print("ALBUMS ARE " + albumsNames.toString());
80 | }
81 |
82 | @override
83 | Widget build(BuildContext context) {
84 | return Scaffold(
85 | appBar: AppBar(
86 | title: Text(widget.artistName),
87 | ),
88 | body: ListView.builder(
89 | itemCount: albumsNames.length,
90 | itemBuilder: (BuildContext context, int index) => ListTile(
91 | title: albumsNames[index] != null ? Text(albumsNames[index]) : Text("Unknown Album"),
92 | onTap: () {
93 | Navigator.of(context).push(MaterialPageRoute(
94 | builder: (BuildContext context) => ShowAlbum(
95 | tracks: albums[albumsNames[index]],
96 | albumName: albumsNames[index]
97 | )));
98 | },
99 | )
100 | ),
101 | );
102 | }
103 | }
104 |
105 | class ShowAlbum extends StatefulWidget {
106 | List tracks;
107 | String albumName;
108 | ShowAlbum({Key key, @required this.tracks, @required this.albumName}) : super(key: key);
109 |
110 | ShowAlbumState createState() => ShowAlbumState();
111 | }
112 |
113 | class ShowAlbumState extends State {
114 | List albumMetaData = [];
115 | List albumFilePaths = [];
116 | Map trackNumbers = Map();
117 |
118 | List sortedAlbumMetaData = [];
119 | List sortedAlbumFilePaths = [];
120 |
121 | @override
122 | void initState() {
123 | super.initState();
124 | for (var track in widget.tracks) {
125 | int i;
126 | String path;
127 | for (var x in musicplayer.allMetaData) {
128 | if (x[0] == track[0]) {
129 | i = musicplayer.allMetaData.indexOf(x);
130 | path = musicplayer.allFilePaths[i];
131 | albumFilePaths.add(path);
132 | albumMetaData.add([
133 | musicplayer.allMetaData[i][0],
134 | musicplayer.allMetaData[i][1],
135 | musicplayer.allMetaData[i][2]
136 | ]);
137 | }
138 | }
139 | }
140 |
141 | print(widget.tracks);
142 |
143 | int count = 0;
144 | for (var track in widget.tracks) {
145 | print("track is " + track.toString());
146 | if (trackNumbers[int.parse(track[1])] == null) {
147 | trackNumbers[int.parse(track[1])] = count;
148 | } else {
149 | trackNumbers[count+1] = count;
150 | }
151 | count += 1;
152 | }
153 |
154 | print(trackNumbers);
155 |
156 | var l = trackNumbers.keys.toList();
157 | l.sort();
158 | for (var num in l) {
159 | sortedAlbumMetaData.add(albumMetaData[trackNumbers[num]]);
160 | sortedAlbumFilePaths.add(albumFilePaths[trackNumbers[num]]);
161 | }
162 | }
163 |
164 | @override
165 | Widget build(BuildContext context) {
166 | return Scaffold(
167 | appBar: AppBar(
168 | title: widget.albumName != null ? Text(widget.albumName) : Text("Unknown Album"),
169 | ),
170 | body: ListView.builder(
171 | itemCount: widget.tracks.length,
172 | itemBuilder: (BuildContext context, int index) => ListTile(
173 | leading: musicplayer.getImage(sortedAlbumMetaData[index][2], context),
174 | title: Text(sortedAlbumMetaData[index][0].toString()),
175 | subtitle: Text(sortedAlbumMetaData[index][1].toString()),
176 | onTap: () {
177 | musicplayer.queueFileList = sortedAlbumFilePaths;
178 | musicplayer.queueMetaData = sortedAlbumMetaData;
179 | musicplayer.currTrack = index;
180 | Navigator.of(context).push(MaterialPageRoute(
181 | builder: (BuildContext context) => PlayingPage(
182 | filePath: sortedAlbumFilePaths[index],
183 | fileMetaData: sortedAlbumMetaData[index],
184 | backPage: "artistPage")));
185 | },
186 | )
187 | ),
188 | );
189 | }
190 | }
--------------------------------------------------------------------------------
/lib/config.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 |
3 | import 'package:flutter/widgets.dart';
4 |
5 | enum ColorMode {
6 | /// Waves with *single* **color** but different **alpha** and **amplitude**.
7 | single,
8 |
9 | /// Waves using *random* **color**, **alpha** and **amplitude**.
10 | random,
11 |
12 | /// Waves' colors must be set, and [colors]'s length must equal with [layers]
13 | custom,
14 | }
15 |
16 | abstract class Config {
17 | final ColorMode colorMode;
18 |
19 | Config({this.colorMode});
20 |
21 | void throwNullError(String colorModeStr, String configStr) {
22 | throw FlutterError(
23 | 'When using `ColorMode.$colorModeStr`, `$configStr` must be set.');
24 | }
25 | }
26 |
27 | class CustomConfig extends Config {
28 | final List colors;
29 | final List> gradients;
30 | final Alignment gradientBegin;
31 | final Alignment gradientEnd;
32 | final List durations;
33 | final List heightPercentages;
34 | final MaskFilter blur;
35 |
36 | CustomConfig({
37 | this.colors,
38 | this.gradients,
39 | this.gradientBegin,
40 | this.gradientEnd,
41 | @required this.durations,
42 | @required this.heightPercentages,
43 | this.blur,
44 | }) : assert(() {
45 | if (colors == null && gradients == null) {
46 | throwNullError('custom', 'colors` or `gradients');
47 | }
48 | return true;
49 | }()),
50 | assert(() {
51 | if (gradients == null &&
52 | (gradientBegin != null || gradientEnd != null)) {
53 | throw FlutterError(
54 | 'You set a gradient direction but forgot setting `gradients`.');
55 | }
56 | return true;
57 | }()),
58 | assert(() {
59 | if (durations == null) {
60 | throwNullError('custom', 'durations');
61 | }
62 | return true;
63 | }()),
64 | assert(() {
65 | if (heightPercentages == null) {
66 | throwNullError('custom', 'heightPercentages');
67 | }
68 | return true;
69 | }()),
70 | assert(() {
71 | if (colors != null) {
72 | if (colors.length != durations.length ||
73 | colors.length != heightPercentages.length) {
74 | throw FlutterError(
75 | 'Length of `colors`, `durations` and `heightPercentages` must be equal.');
76 | }
77 | }
78 | return true;
79 | }()),
80 | assert(colors == null || gradients == null,
81 | 'Cannot provide both colors and gradients.'),
82 | super(colorMode: ColorMode.custom);
83 | }
84 |
85 | /// todo
86 | class RandomConfig extends Config {
87 | RandomConfig() : super(colorMode: ColorMode.random);
88 | }
89 |
90 | /// todo
91 | class SingleConfig extends Config {
92 | SingleConfig() : super(colorMode: ColorMode.single);
93 | }
--------------------------------------------------------------------------------
/lib/favourites.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'musicplayer.dart' as musicplayer;
3 | import 'playingpage.dart';
4 |
5 | String img = "images/noimage.png";
6 |
7 | class FavouritesPage extends StatefulWidget {
8 | @override
9 | FavouritesPageState createState() => FavouritesPageState();
10 | }
11 |
12 | class FavouritesPageState extends State{
13 | List favListMetaData = [];
14 | @override
15 | void initState() {
16 | super.initState();
17 | if (musicplayer.favList != null) {
18 | print("favlist is " + musicplayer.favList.toString());
19 | for (var track in musicplayer.favList) {
20 | favListMetaData.add(musicplayer.allMetaData[musicplayer.allFilePaths.indexOf(track)]);
21 | }
22 | } else {
23 |
24 | }
25 | }
26 |
27 | @override
28 | Widget build(BuildContext context) {
29 | return Scaffold(
30 | drawer: musicplayer.AppDrawer(),
31 | appBar: AppBar(
32 | title: Text("Favourites"),
33 | ),
34 | body: musicplayer.favList != null ?
35 | ListView.builder(
36 | itemCount: musicplayer.favList.length,
37 | itemBuilder: (BuildContext context, int index) {
38 | var track_metadata = favListMetaData[index];
39 | return ListTile(
40 | leading: musicplayer.getImage(track_metadata[2], context),
41 | title: Text(track_metadata[0]),
42 | subtitle: Text(track_metadata[1]),
43 | onTap: () {
44 | musicplayer.queueFileList = musicplayer.favList;
45 | musicplayer.queueMetaData = favListMetaData;
46 | musicplayer.currTrack = index;
47 | Navigator.of(context).push(
48 | MaterialPageRoute(
49 | builder: (BuildContext context) => new PlayingPage(
50 | filePath: musicplayer.favList[index],
51 | fileMetaData: track_metadata[0] != null ?
52 | track_metadata :
53 | [musicplayer.favList[index], "unknown"] ,
54 | backPage: "favouritesPage",
55 | )
56 | )
57 | );
58 | },
59 | );
60 | },
61 | ) : Center(child: Text("You haven't favourited any tracks yet."),)
62 | );
63 | }
64 | }
--------------------------------------------------------------------------------
/lib/home.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'dart:async';
3 | import 'library.dart';
4 | import 'musicplayer.dart' as musicplayer;
5 | import 'package:audioplayer/audioplayer.dart';
6 | import 'favourites.dart';
7 | import 'playingpage.dart';
8 | import 'playlistpage.dart';
9 | import 'artistpage.dart';
10 |
11 | class HomePage extends StatefulWidget {
12 | HomePageState createState() => HomePageState();
13 | }
14 |
15 | class HomePageState extends State {
16 | StreamSubscription _positionSubscription;
17 | StreamSubscription _audioPlayerStateSubscription;
18 | ScrollController _scrollController;
19 |
20 | void initAudioPlayer() {
21 | musicplayer.audioPlayer = new AudioPlayer();
22 | _positionSubscription = musicplayer.audioPlayer.onAudioPositionChanged
23 | .listen((p) => setState(() => musicplayer.position = p));
24 | _audioPlayerStateSubscription =
25 | musicplayer.audioPlayer.onPlayerStateChanged.listen((s) {
26 | if (s == AudioPlayerState.PLAYING) {
27 | setState(() =>
28 | musicplayer.duration = musicplayer.audioPlayer.duration);
29 | } else if (s == AudioPlayerState.STOPPED) {
30 | setState(() {
31 | musicplayer.position = musicplayer.duration;
32 | });
33 | }
34 | }, onError: (msg) {
35 | setState(() {
36 | // musicplayer.playerState = PlayerState.stopped;
37 | musicplayer.duration = new Duration(seconds: 0);
38 | musicplayer.position = new Duration(seconds: 0);
39 | });
40 | });
41 | }
42 |
43 | @override
44 | void dispose() {
45 | _positionSubscription.cancel();
46 | _audioPlayerStateSubscription.cancel();
47 | musicplayer.audioPlayer.stop();
48 | super.dispose();
49 | }
50 |
51 | scrollQueue() { // scrolls to current track
52 | // TODO: test if this really works
53 | try {
54 | _scrollController.jumpTo(musicplayer.currTrack * (MediaQuery.of(context).size.width/4 + 24.0));
55 | } catch(e) {
56 |
57 | }
58 | }
59 |
60 | @override
61 | void initState() {
62 | super.initState();
63 | _scrollController = ScrollController();
64 | initAudioPlayer();
65 | musicplayer.getFavTrackList().then((l) {
66 | musicplayer.favList = l;
67 | });
68 | musicplayer.getPlayListNames().then((l) {
69 | musicplayer.playlistNames = l;
70 | });
71 | WidgetsBinding.instance.addPostFrameCallback((_) => scrollQueue());
72 | musicplayer.hideAppBarAgain();
73 | }
74 |
75 | @override
76 | Widget build(BuildContext context) {
77 | return Scaffold(
78 | drawer: musicplayer.AppDrawer(),
79 | body: SafeArea(
80 | child: Column(
81 | mainAxisAlignment: MainAxisAlignment.spaceEvenly,
82 | mainAxisSize: MainAxisSize.max,
83 | children: [
84 | Padding(
85 | padding: EdgeInsets.only(top: 30.0),
86 | child: Column(
87 | children: [
88 | Text("Your queue", style: TextStyle(fontSize: 22.0),),
89 | Container(
90 | padding: EdgeInsets.only(left: 70.0, right: 70.0),
91 | child: Divider(color: Colors.black54,),
92 | )
93 | ],
94 | )
95 | ),
96 | Expanded(
97 | child: musicplayer.queueMetaData != null ? ListView.builder(// play queue
98 | itemCount: musicplayer.queueMetaData.length,
99 | controller: _scrollController,
100 | scrollDirection: Axis.horizontal,
101 | itemBuilder: (BuildContext context, int index) {
102 | return Padding(
103 | padding: EdgeInsets.only(bottom: 40.0, top: 10.0),
104 | child: Card(
105 | child: Material(
106 | color: index == musicplayer.currTrack ? Colors.limeAccent : Colors.lightBlueAccent,
107 | child: InkWell(
108 | child: Column(
109 | children: [
110 | musicplayer.queueMetaData[index][2] != "" ? Padding(
111 | padding: EdgeInsets.all(8.0),
112 | child: Container(width: MediaQuery.of(context).size.width/4,
113 | height: MediaQuery.of(context).size.width/4,
114 | child: musicplayer.getImage(
115 | musicplayer.queueMetaData[index][2],
116 | context
117 | ),)
118 | )
119 | : Container(),
120 | Container(
121 | padding: EdgeInsets.only(left: 5.0, right: 5.0),
122 | width: 100.0,
123 | child: Center(child: Text(
124 | musicplayer.queueMetaData[index][0],
125 | maxLines: 2,
126 | overflow: TextOverflow.ellipsis,
127 | )),
128 | ),
129 | ],
130 | ),
131 | onTap: () {
132 | musicplayer.currTrack = index;
133 | Navigator.of(context).push(
134 | MaterialPageRoute(
135 | builder: (BuildContext context) => new PlayingPage(
136 | filePath: musicplayer.queueFileList[index],
137 | fileMetaData: musicplayer.queueMetaData[index][0] != null ?
138 | musicplayer.queueMetaData[index] :
139 | [musicplayer.queueMetaData[index], "unknown"],
140 | backPage: "homePage",
141 | )
142 | )
143 | );
144 | },
145 | )
146 | ),
147 | )
148 | );
149 | },
150 | ) : Padding(padding: EdgeInsets.all(70.0), child: Text("Your queue is empty", style: TextStyle(
151 | fontStyle: FontStyle.italic, color: Colors.grey),),
152 | )
153 | ),
154 | Container(
155 | decoration: BoxDecoration(
156 | boxShadow: [BoxShadow(
157 | offset: Offset(5.0, 5.0),
158 | spreadRadius: 5.0,
159 | blurRadius: 15.0,
160 | color: Colors.grey
161 | )]
162 | ),
163 | child: GridView.count(
164 | shrinkWrap: true,
165 | crossAxisCount: 2,
166 | children: [
167 | Padding(
168 | padding: EdgeInsets.only(right: 1.0, bottom: 1.0),
169 | child: Material(
170 | child: InkWell(
171 | child: Center(child: Column(
172 | children: [
173 | Icon(Icons.library_music),
174 | Text("Library")
175 | ],
176 | mainAxisSize: MainAxisSize.min,
177 | ),),
178 | onTap: () {
179 | Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => Library(
180 | musicFiles: musicplayer.allFilePaths,
181 | metadata: musicplayer.allMetaData,
182 | ),));
183 | },
184 | ),
185 | ),
186 | ),
187 | Padding(
188 | padding: EdgeInsets.only(left: 1.0, bottom: 1.0),
189 | child: Material(
190 | child: InkWell(
191 | child: Center(child: Column(
192 | children: [
193 | Icon(Icons.favorite_border),
194 | Text("Favourites")
195 | ],
196 | mainAxisSize: MainAxisSize.min,
197 | ),),
198 | onTap: () {
199 | Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => FavouritesPage(),));
200 | },
201 | ),
202 | ),
203 | ),
204 | Padding(
205 | padding: EdgeInsets.only(top: 1.0, right: 1.0),
206 | child: Material(
207 | child: InkWell(
208 | child: Center(child: Column(
209 | children: [
210 | Icon(Icons.list),
211 | Text("Playlists")
212 | ],
213 | mainAxisSize: MainAxisSize.min,
214 | ),),
215 | onTap: () {
216 | Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => PlaylistPage(
217 | ),));
218 | },
219 | ),
220 | ),
221 | ),
222 | Padding(
223 | padding: EdgeInsets.only(left: 1.0, top: 1.0),
224 | child: Material(
225 | child: InkWell(
226 | child: Center(child: Column(
227 | children: [
228 | Icon(Icons.account_circle),
229 | Text("Artists")
230 | ],
231 | mainAxisSize: MainAxisSize.min,
232 | ),),
233 | onTap: () {
234 | Navigator.of(context).push(MaterialPageRoute(
235 | builder: (BuildContext context) => ArtistPage()
236 | ));
237 | },
238 | ),
239 | ),
240 | )
241 | ],
242 | ),
243 | ),
244 | ],
245 | ),
246 | )
247 | );
248 | }
249 | }
250 |
251 | class GridBlock extends StatelessWidget {
252 | String route;
253 | String blockTitle;
254 |
255 | GridBlock({Key key, @required this.route, @required this.blockTitle}) : super(key: key);
256 |
257 | @override
258 | Widget build(BuildContext context) {
259 | return Padding(
260 | padding: EdgeInsets.all(10.0),
261 | child: Container(
262 | decoration: BoxDecoration(
263 | color: Colors.white,
264 | borderRadius: BorderRadius.circular(10.0),
265 | boxShadow: [
266 | BoxShadow(
267 | color: Colors.grey,
268 | // offset, the X,Y coordinates to offset the shadow
269 | offset: Offset(0.0, 0.0),
270 | // blurRadius, the higher the number the more smeared look
271 | blurRadius: 10.0,
272 | spreadRadius: 1.0)],
273 | ),
274 | child: Material(
275 | child: InkWell(
276 | borderRadius: BorderRadius.circular(10.0),
277 | onTap: () {
278 | Navigator.of(context).pushNamed(route);
279 | },
280 | child: Container(
281 | child: Center(child:Text(blockTitle)),
282 | ),
283 | ),
284 | color: Colors.transparent,
285 | ),
286 | ),
287 | );
288 | }
289 | }
--------------------------------------------------------------------------------
/lib/library.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 | import 'dart:async';
4 | import 'musicplayer.dart' as musicplayer;
5 | import 'playingpage.dart';
6 | import 'package:audioplayer/audioplayer.dart';
7 | import 'dart:math';
8 |
9 | String img = "images/noimage.png";
10 |
11 | class Library extends StatefulWidget {
12 | List metadata;
13 | List musicFiles;
14 |
15 | Library({Key key, @required this.musicFiles, this.metadata}) : super(key: key);
16 |
17 | @override
18 | _LibraryState createState() => new _LibraryState();
19 | }
20 |
21 | class _LibraryState extends State{
22 | StreamSubscription _positionSubscription;
23 | StreamSubscription _audioPlayerStateSubscription;
24 | static const platform = const MethodChannel('demo.janhrastnik.com/info');
25 | var r = Random();
26 | int randnum;
27 |
28 | void onComplete() {
29 | // setState(() => musicplayer.playerState = PlayerState.stopped);
30 | }
31 |
32 | @override
33 | void dispose() {
34 | _positionSubscription.cancel();
35 | _audioPlayerStateSubscription.cancel();
36 | musicplayer.audioPlayer.stop();
37 | super.dispose();
38 | }
39 |
40 | @override
41 | void initState() {
42 | super.initState();
43 | initAudioPlayer();
44 | randnum = r.nextInt(1000);
45 | }
46 |
47 | void initAudioPlayer() {
48 | musicplayer.audioPlayer = new AudioPlayer();
49 | _positionSubscription = musicplayer.audioPlayer.onAudioPositionChanged
50 | .listen((p) => setState(() => musicplayer.position = p));
51 | _audioPlayerStateSubscription =
52 | musicplayer.audioPlayer.onPlayerStateChanged.listen((s) {
53 | if (s == AudioPlayerState.PLAYING) {
54 | setState(() =>
55 | musicplayer.duration = musicplayer.audioPlayer.duration);
56 | } else if (s == AudioPlayerState.STOPPED) {
57 | setState(() {
58 | musicplayer.position = musicplayer.duration;
59 | });
60 | }
61 | }, onError: (msg) {
62 | setState(() {
63 | // musicplayer.playerState = PlayerState.stopped;
64 | musicplayer.duration = new Duration(seconds: 0);
65 | musicplayer.position = new Duration(seconds: 0);
66 | });
67 | });
68 | }
69 |
70 | playerInfo() {
71 | return Container(
72 | decoration: BoxDecoration(
73 | color: Colors.white,
74 | boxShadow: [BoxShadow(
75 | offset: Offset(5.0, 5.0),
76 | spreadRadius: 5.0,
77 | blurRadius: 15.0,
78 | color: Colors.grey
79 | )]
80 | ),
81 | child: Material(
82 | color: Colors.transparent,
83 | child: InkWell(
84 | onTap: () {
85 | Navigator.of(context).push(MaterialPageRoute(
86 | builder: (BuildContext context) => PlayingPage(
87 | filePath: musicplayer.queueFileList[musicplayer.currTrack],
88 | fileMetaData: musicplayer.queueMetaData[musicplayer.currTrack],
89 | backPage: "libraryPage",
90 | )
91 | ));
92 | },
93 | child: Padding(
94 | padding: EdgeInsets.all(20.0),
95 | child: Column(
96 | children: [
97 | Row(children: [
98 | Text("Now playing: ",
99 | style: TextStyle(
100 | color: Colors.blueGrey
101 | ),
102 | ),
103 | Expanded(
104 | child: Text("${
105 | musicplayer.queueMetaData[musicplayer.currTrack][0] != null
106 | ? musicplayer.queueMetaData[musicplayer.currTrack][0]
107 | : musicplayer.queueFileList[musicplayer.currTrack]
108 | } by ${
109 | musicplayer.queueMetaData[musicplayer.currTrack][1] != null
110 | ? musicplayer.queueMetaData[musicplayer.currTrack][1]
111 | : "unknown"
112 | }",
113 | style: TextStyle(
114 | fontSize: 12.0
115 | ),
116 | ),
117 | ),
118 | getIcon()
119 | ],
120 | ),
121 |
122 | ],
123 | ),
124 | ),
125 | ),
126 | ),
127 | );
128 | }
129 |
130 | getIcon() {
131 | if (musicplayer.playerState == musicplayer.PlayerState.playing) {
132 | return InkWell(
133 | child: Icon(Icons.pause, size: 30.0,),
134 | onTap: () {
135 | musicplayer.pause();
136 | setState(() {
137 | musicplayer.playerState = musicplayer.PlayerState.paused;
138 | });
139 |
140 | }
141 | );
142 | } else if (musicplayer.playerState == musicplayer.PlayerState.paused) {
143 | return InkWell(
144 | child: Icon(Icons.play_arrow, size: 30.0,),
145 | onTap: () {
146 | musicplayer.play(musicplayer.queueFileList[musicplayer.currTrack]);
147 | setState(() {
148 | musicplayer.playerState = musicplayer.PlayerState.playing;
149 | });
150 |
151 | }
152 | );
153 | }
154 | }
155 |
156 | @override
157 | Widget build(BuildContext context) {
158 | return MaterialApp(
159 | debugShowCheckedModeBanner: false,
160 | home: Scaffold(
161 | drawer: musicplayer.AppDrawer(),
162 | appBar: AppBar(
163 | title: Text("Library"),
164 | actions: [
165 | IconButton(
166 | icon: Icon(Icons.search),
167 | onPressed: () {
168 | showSearch(
169 | context: context,
170 | delegate: TrackSearch(musicplayer.allMetaData)
171 | );
172 | }
173 | )
174 | ],
175 | ),
176 | body: Column(
177 | children: [
178 | Expanded(
179 | child: ListView.builder(
180 | itemCount: widget.musicFiles.length,
181 | itemBuilder: (BuildContext context, int index) {
182 | return index == 0 ? Column(
183 | children: [
184 | ListTile(
185 | leading: Icon(Icons.shuffle, size: MediaQuery.of(context).size.width/7),
186 | title: Text("Shuffle All Songs"),
187 | onTap: () {
188 | List a = musicplayer.allFilePaths.map((e) => e).toList();
189 | List b = [];
190 | for (var data in musicplayer.allMetaData) {
191 | var temp = data.map((e) => e).toList();
192 | b.add(temp);
193 | }
194 | a.shuffle(Random(randnum));
195 | b.shuffle(Random(randnum));
196 | var shuffled = [a, b];
197 | musicplayer.queueFileList = shuffled[0];
198 | musicplayer.currTrack = 0;
199 | musicplayer.queueMetaData = shuffled[1];
200 | Navigator.of(context).push(
201 | MaterialPageRoute(
202 | builder: (BuildContext context) => new PlayingPage(
203 | filePath: shuffled[0][0],
204 | fileMetaData: shuffled[1][0][0] != null ?
205 | shuffled[1][0] :
206 | [shuffled[0][0], "unknown"],
207 | backPage: "libraryPage",
208 | )
209 | )
210 | );
211 | },
212 | ),
213 | ListTile(
214 | leading: musicplayer.getImage(widget.metadata[index][2], context),
215 | title: Text(widget.metadata[index][0]),
216 | subtitle: Text(widget.metadata[index][1]),
217 | onTap: () {
218 | musicplayer.queueFileList = widget.musicFiles;
219 | musicplayer.currTrack = index;
220 | musicplayer.queueMetaData = widget.metadata;
221 | Navigator.of(context).push(
222 | MaterialPageRoute(
223 | builder: (BuildContext context) => new PlayingPage(
224 | filePath: widget.musicFiles[index],
225 | fileMetaData: widget.metadata[index][0] != null ?
226 | widget.metadata[index] :
227 | [widget.musicFiles[index], "unknown"],
228 | backPage: "libraryPage",
229 | )
230 | )
231 | );
232 | },
233 | )
234 |
235 | ],
236 | ) : ListTile(
237 | leading: musicplayer.getImage(widget.metadata[index][2], context),
238 | title: Text(widget.metadata[index][0]),
239 | subtitle: Text(widget.metadata[index][1]),
240 | onTap: () {
241 | musicplayer.queueFileList = widget.musicFiles;
242 | musicplayer.currTrack = index;
243 | musicplayer.queueMetaData = widget.metadata;
244 | Navigator.of(context).push(
245 | MaterialPageRoute(
246 | builder: (BuildContext context) => new PlayingPage(
247 | filePath: widget.musicFiles[index],
248 | fileMetaData: widget.metadata[index][0] != null ?
249 | widget.metadata[index] :
250 | [widget.musicFiles[index], "unknown"],
251 | backPage: "libraryPage",
252 | )
253 | )
254 | );
255 | },
256 | );
257 | }
258 | )
259 | ),
260 | (musicplayer.playerState == musicplayer.PlayerState.playing || musicplayer.playerState == musicplayer.PlayerState.paused)
261 | ? playerInfo() : Container(child: null,)
262 | ]
263 | )
264 | )
265 | );
266 | }
267 | }
268 |
269 | class TrackSearch extends SearchDelegate {
270 | final List tracks;
271 |
272 | TrackSearch(this.tracks);
273 |
274 | @override
275 | List buildActions(BuildContext context) {
276 | // TODO: implement buildActions
277 | return [
278 | IconButton(
279 | icon: Icon(Icons.clear),
280 | onPressed: () {
281 | query = "";
282 | },
283 | )
284 | ];
285 | }
286 |
287 | @override
288 | Widget buildLeading(BuildContext context) {
289 | // TODO: implement buildLeading
290 | return IconButton(
291 | icon: Icon(Icons.arrow_back),
292 | onPressed: () {
293 | close(context, null);
294 | },
295 | );
296 | }
297 |
298 | @override
299 | Widget buildResults(BuildContext context) {
300 | final results = tracks.where((track) => track[0].toLowerCase().contains(query.toLowerCase()));
301 | // TODO: implement buildResults
302 | return ListView(
303 | children: results.map((track) => ListTile(
304 | leading: musicplayer.getImage(track[2], context),
305 | title: Text(track[0]),
306 | subtitle: Text(track[1]),
307 | onTap: () {
308 | musicplayer.queueFileList = [musicplayer.allFilePaths[tracks.indexOf(track)]];
309 | musicplayer.currTrack = 0;
310 | musicplayer.queueMetaData = [track];
311 | Navigator.of(context).push(
312 | MaterialPageRoute(
313 | builder: (BuildContext context) => new PlayingPage(
314 | filePath: musicplayer.allFilePaths[tracks.indexOf(track)],
315 | fileMetaData: track,
316 | backPage: "libraryPage",
317 | )
318 | )
319 | );
320 | },
321 | ),
322 | ).toList());
323 | }
324 |
325 | @override
326 | Widget buildSuggestions(BuildContext context) {
327 | // TODO: implement buildSuggestions
328 | final results = tracks.where((track) => track[0].toLowerCase().contains(query.toLowerCase()));
329 | return ListView(
330 | children: results.map((track) => ListTile(
331 | leading: musicplayer.getImage(track[2], context),
332 | title: Text(track[0]),
333 | subtitle: Text(track[1]),
334 | onTap: () {
335 | musicplayer.queueFileList = [musicplayer.allFilePaths[tracks.indexOf(track)]];
336 | musicplayer.currTrack = 0;
337 | musicplayer.queueMetaData = [track];
338 | Navigator.of(context).push(
339 | MaterialPageRoute(
340 | builder: (BuildContext context) => new PlayingPage(
341 | filePath: musicplayer.allFilePaths[tracks.indexOf(track)],
342 | fileMetaData: track,
343 | backPage: "libraryPage",
344 | )
345 | )
346 | );
347 | },
348 | ),
349 | ).toList());
350 | }
351 |
352 | }
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'musicplayer.dart' as musicplayer;
3 | import 'permissions.dart';
4 |
5 | void main() => runApp(new MyApp());
6 |
7 | class MyApp extends StatelessWidget {
8 |
9 | @override
10 | Widget build(BuildContext context) {
11 | musicplayer.hideAppBar();
12 | return MaterialApp(
13 | title: "Nano Music Player",
14 | debugShowCheckedModeBanner: false,
15 | home: GetPermissions(),
16 | );
17 | }
18 | }
--------------------------------------------------------------------------------
/lib/musicplayer.dart:
--------------------------------------------------------------------------------
1 | library musicplayer2.musicplayer;
2 | import 'package:audioplayer/audioplayer.dart';
3 | import 'package:shared_preferences/shared_preferences.dart';
4 | import 'package:flutter/material.dart';
5 | import 'home.dart';
6 | import 'playlistpage.dart';
7 | import 'favourites.dart';
8 | import 'library.dart';
9 | import 'package:random_color/random_color.dart';
10 | import 'artistpage.dart';
11 | import 'package:flutter/services.dart';
12 | import 'dart:io';
13 | String img = "images/noimage.png";
14 | // for playlists, play queue
15 | List queueFileList;
16 | int currTrack;
17 | String currTrackName;
18 | List queueMetaData;
19 | // data of all tracks on device
20 | List allMetaData;
21 | List allFilePaths;
22 | // for favourites
23 | List favList = [];
24 |
25 | // all playlist names
26 | List playlistNames;
27 |
28 | RandomColor randomColor = RandomColor();
29 | String appPath;
30 | bool onPlayingPage = false;
31 |
32 | enum PlayerState { stopped, playing, paused }
33 | AudioPlayer audioPlayer;
34 | PlayerState playerState;
35 | Duration duration;
36 | Duration position;
37 |
38 | void hideAppBar() {
39 | SystemChrome.setEnabledSystemUIOverlays([]);
40 | }
41 |
42 | void hideAppBarAgain() {
43 | SystemChrome.restoreSystemUIOverlays();
44 | }
45 |
46 | void setOrientation() {
47 | SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
48 | }
49 |
50 | Future clearPrefs() async {
51 | SharedPreferences prefs = await SharedPreferences.getInstance();
52 | prefs.clear();
53 | }
54 |
55 | Future getFavTrackList() async {
56 | SharedPreferences prefs = await SharedPreferences.getInstance();
57 | List trackList = prefs.getStringList("favTracks");
58 | return trackList;
59 | }
60 |
61 | Future getPlayListNames() async {
62 | SharedPreferences prefs = await SharedPreferences.getInstance();
63 | List playListNames = prefs.getStringList("playlistNames");
64 | return playListNames;
65 | }
66 |
67 | Future getPlayList(name) async {
68 | SharedPreferences prefs = await SharedPreferences.getInstance();
69 | List playList = prefs.getStringList(name);
70 | return playList;
71 | }
72 |
73 | Future loadPlaylistData() async {
74 | List playlistTracks = [];
75 | if (playlistNames != null) {
76 | for (String name in playlistNames) { // we get tracks from all playlists from shared preferences
77 | getPlayList(name).then((l) {
78 | playlistTracks.add(l);
79 | });
80 | }
81 | }
82 | return playlistTracks;
83 | }
84 |
85 | void savePlaylist(String name, List CurrTrackList, List trackList) async {
86 | SharedPreferences prefs = await SharedPreferences.getInstance();
87 | if (trackList != null) {
88 | for (var track in trackList) {
89 | CurrTrackList.add(track);
90 | }
91 | }
92 | prefs.setStringList(name, CurrTrackList);
93 | }
94 |
95 | Future play(url) async {
96 | await audioPlayer.play(url, isLocal: true);
97 | }
98 |
99 | Future pause() async {
100 | await audioPlayer.pause();
101 | }
102 |
103 | Future stop() async {
104 | await audioPlayer.stop();
105 | }
106 |
107 | getImage(imageHash, context) {
108 | if (imageHash == null) {
109 | imageHash = "";
110 | }
111 | String imageData = appPath + "/" + imageHash;
112 | File f = File(imageData);
113 | return f.existsSync() ? Image(image: FileImage(f)) : Image.asset(img, width: MediaQuery.of(context).size.width/7);
114 | }
115 |
116 | class AppDrawer extends StatelessWidget {
117 | @override
118 | Widget build(BuildContext context) {
119 | return Drawer(
120 | child: Column(
121 | children: [
122 | InkWell(
123 | child: ListTile(
124 | leading: Icon(Icons.home),
125 | title: Text("Home"),
126 | ),
127 | onTap: () {
128 | onPlayingPage = false;
129 | Navigator.of(context).push(MaterialPageRoute(
130 | builder: (BuildContext context) => HomePage()
131 | )
132 | );
133 | },
134 | ),
135 | InkWell(
136 | child: ListTile(
137 | leading: Icon(Icons.library_music),
138 | title: Text("Library"),
139 | ),
140 | onTap: () {
141 | onPlayingPage = false;
142 | Navigator.of(context).push(MaterialPageRoute(
143 | builder: (BuildContext context) => Library(
144 | musicFiles: allFilePaths,
145 | metadata: allMetaData,
146 | )
147 | )
148 | );
149 | },
150 | ),
151 | InkWell(
152 | child: ListTile(
153 | leading: Icon(Icons.favorite_border),
154 | title: Text("Favourites"),
155 | ),
156 | onTap: () {
157 | onPlayingPage = false;
158 | Navigator.of(context).push(MaterialPageRoute(
159 | builder: (BuildContext context) => FavouritesPage()
160 | )
161 | );
162 | },
163 | ),
164 | InkWell(
165 | child: ListTile(
166 | leading: Icon(Icons.list),
167 | title: Text("Playlists"),
168 | ),
169 | onTap: () {
170 | onPlayingPage = false;
171 | Navigator.of(context).push(MaterialPageRoute(
172 | builder: (BuildContext context) => PlaylistPage(
173 | )
174 | )
175 | );
176 | },
177 | ),
178 | InkWell(
179 | child: ListTile(
180 | leading: Icon(Icons.account_circle),
181 | title: Text("Artists"),
182 | ),
183 | onTap: () {
184 | onPlayingPage = false;
185 | Navigator.of(context).push(MaterialPageRoute(
186 | builder: (BuildContext context) => ArtistPage(
187 | )
188 | )
189 | );
190 | },
191 | )
192 | ],
193 | ),
194 | );
195 | }
196 | }
--------------------------------------------------------------------------------
/lib/permissions.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'splashpage.dart';
3 | import 'package:simple_permissions/simple_permissions.dart';
4 |
5 | class GetPermissions extends StatefulWidget {
6 | @override
7 | GetPermissionsState createState() => GetPermissionsState();
8 | }
9 |
10 | class GetPermissionsState extends State {
11 | Permission permission = Permission.ReadExternalStorage;
12 |
13 | _requestExtStorage(p) async {
14 | final r = await SimplePermissions.requestPermission(p);
15 | print("permission is " + r.toString());
16 | onDoneLoading();
17 | }
18 |
19 | onDoneLoading() async {
20 | Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (context) => SplashScreen()));
21 | }
22 |
23 | @override
24 | void initState() {
25 | _requestExtStorage(permission);
26 | super.initState();
27 | }
28 |
29 | @override
30 | Widget build(BuildContext context) {
31 | return Scaffold(
32 | body: Center(child: Image.asset("images/icon3-192.png"),),
33 | );
34 | }
35 | }
--------------------------------------------------------------------------------
/lib/playingpage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'dart:async';
3 | import 'musicplayer.dart' as musicplayer;
4 | import 'package:shared_preferences/shared_preferences.dart';
5 | import 'library.dart';
6 | import 'favourites.dart';
7 | import 'home.dart';
8 | import 'package:audioplayer/audioplayer.dart';
9 | import 'playlistpage.dart';
10 | import 'package:random_color/random_color.dart';
11 | import 'artistpage.dart';
12 | import 'wave.dart';
13 | import 'config.dart';
14 | import 'dart:io';
15 |
16 | class PlayingPage extends StatefulWidget {
17 | var filePath;
18 | var fileMetaData;
19 | var backPage;
20 |
21 | PlayingPage({Key key, @required this.filePath, this.fileMetaData, @required this.backPage}) : super(key: key);
22 |
23 | PlayingPageState createState() => PlayingPageState();
24 | }
25 |
26 | class PlayingPageState extends State {
27 | Color pageColor = musicplayer.randomColor.randomColor(colorBrightness: ColorBrightness.custom(Range(80, 83)));
28 | bool isFavorited;
29 | StreamSubscription _positionSubscription;
30 | StreamSubscription _audioPlayerStateSubscription;
31 | var missingImg = AssetImage("images/noimage.png");
32 | final key = GlobalKey();
33 | var img;
34 |
35 | @override
36 | void initState() {
37 | initAudioPlayer();
38 | super.initState();
39 | if (musicplayer.currTrackName != widget.filePath) {
40 | musicplayer.duration = new Duration(seconds: 0);
41 | musicplayer.position = new Duration(seconds: 0);
42 | musicplayer.stop();
43 | musicplayer.play(widget.filePath);
44 | } else {
45 | musicplayer.play(widget.filePath);
46 | }
47 | musicplayer.playerState = musicplayer.PlayerState.playing;
48 | musicplayer.getFavTrackList().then((l) {
49 | if (musicplayer.favList != null) {
50 | if (musicplayer.favList.contains(widget.filePath) == true) {
51 | isFavorited = true;
52 | } else {
53 | isFavorited = false;
54 | }
55 | } else {
56 | isFavorited = false;
57 | }
58 | });
59 | musicplayer.getFavTrackList().then((l) {
60 | musicplayer.favList = l;
61 | });
62 | musicplayer.currTrackName = widget.filePath;
63 |
64 | musicplayer.onPlayingPage = true;
65 | }
66 |
67 | @override
68 | void dispose() {
69 | _positionSubscription.cancel();
70 | _audioPlayerStateSubscription.cancel();
71 | musicplayer.stop();
72 | super.dispose();
73 | }
74 |
75 | void initAudioPlayer() {
76 | musicplayer.audioPlayer = new AudioPlayer();
77 | _positionSubscription = musicplayer.audioPlayer.onAudioPositionChanged
78 | .listen((p) => setState(() => musicplayer.position = p));
79 | _audioPlayerStateSubscription =
80 | musicplayer.audioPlayer.onPlayerStateChanged.listen((s) {
81 | musicplayer.hideAppBarAgain();
82 | if (s == AudioPlayerState.PLAYING) {
83 | setState(() =>
84 | musicplayer.duration = musicplayer.audioPlayer.duration);
85 | } else if (s == AudioPlayerState.COMPLETED) {
86 | try {
87 | musicplayer.play(musicplayer.queueFileList[musicplayer.currTrack+1]);
88 | } catch(e) {
89 |
90 | }
91 | if (musicplayer.onPlayingPage == true) {
92 | if (musicplayer.currTrack != musicplayer.queueFileList.length - 1) {
93 | musicplayer.currTrack++;
94 | Navigator.of(context).push(MaterialPageRoute(
95 | builder: (BuildContext context) =>
96 | PlayingPage(
97 | filePath: musicplayer.queueFileList[musicplayer
98 | .currTrack],
99 | fileMetaData: musicplayer.queueMetaData[musicplayer
100 | .currTrack][0] != null
101 | ? musicplayer.queueMetaData[musicplayer.currTrack]
102 | : [
103 | musicplayer.queueFileList[musicplayer.currTrack],
104 | "unknown"
105 | ],
106 | backPage: widget.backPage,
107 | )
108 | )
109 | );
110 | }
111 | } else {
112 | if (musicplayer.currTrack != musicplayer.queueFileList.length - 1) {
113 | musicplayer.currTrack++;
114 | musicplayer.duration = new Duration(seconds: 0);
115 | musicplayer.position = new Duration(seconds: 0);
116 | musicplayer.play(musicplayer.queueFileList[musicplayer.currTrack]);
117 | }
118 | }
119 | }
120 | }, onError: (msg) {
121 | setState(() {
122 | // musicplayer.playerState = PlayerState.stopped;
123 | musicplayer.duration = new Duration(seconds: 0);
124 | musicplayer.position = new Duration(seconds: 0);
125 | });
126 | });
127 | }
128 |
129 | get isPlaying => musicplayer.playerState == musicplayer.PlayerState.playing;
130 | get isPaused => musicplayer.playerState == musicplayer.PlayerState.paused;
131 | get durationText {
132 | var minutes = musicplayer.duration.inMinutes.toString();
133 | var seconds = (musicplayer.duration.inSeconds % 60).toString();
134 | if (seconds.length == 1) {
135 | seconds = "0" + seconds;
136 | }
137 | return minutes + ":" + seconds;
138 | }
139 | get positionText {
140 | var minutes = musicplayer.position.inMinutes.toString();
141 | var seconds = (musicplayer.position.inSeconds % 60).toString();
142 | if (seconds.length == 1) {
143 | seconds = "0" + seconds;
144 | }
145 | return minutes + ":" + seconds;
146 | }
147 | void saveFavTrack(String track, List trackList) async {
148 | SharedPreferences prefs = await SharedPreferences.getInstance();
149 | if (track != "") {
150 | try {
151 | trackList.add(track);
152 | } catch(e) {
153 | prefs.setStringList("favTracks", [track]);
154 | return null;
155 | }
156 | }
157 | prefs.setStringList("favTracks", trackList);
158 | }
159 |
160 | getIcon() {
161 | if (isPlaying == true || musicplayer.playerState == musicplayer.PlayerState.stopped) {
162 | return IconButton(
163 | icon: Icon(Icons.pause),
164 | iconSize: 50.0,
165 | tooltip: "Pause Track",
166 | onPressed: () {
167 | musicplayer.pause();
168 | setState(() {
169 | musicplayer.playerState = musicplayer.PlayerState.paused;
170 | });
171 |
172 | }
173 | );
174 | } else if (isPlaying == false) {
175 | return IconButton(
176 | icon: Icon(Icons.play_arrow),
177 | iconSize: 50.0,
178 | tooltip: "Play Track",
179 | onPressed: () {
180 | musicplayer.play(widget.filePath);
181 | setState(() {
182 | musicplayer.playerState = musicplayer.PlayerState.playing;
183 | });
184 |
185 | }
186 | );
187 | }
188 | }
189 |
190 | void addToPlaylist() {
191 | List playlistTracks;
192 | musicplayer.loadPlaylistData().then((data) {
193 | playlistTracks = data;
194 | AlertDialog dialog = AlertDialog(
195 | title: Text("Add track to playlist"),
196 | content: Column(
197 | mainAxisSize: MainAxisSize.min,
198 | children: [
199 | musicplayer.playlistNames != null ?
200 | Expanded(
201 | child: ListView.builder(
202 | shrinkWrap: true,
203 | itemCount: musicplayer.playlistNames.length,
204 | itemBuilder: (BuildContext context, int index) {
205 | return Container(
206 | child: ListTile(
207 | title: Text(musicplayer.playlistNames[index]),
208 | trailing: Text("${playlistTracks[index].length} Tracks"),
209 | onTap: () {
210 | musicplayer.savePlaylist(musicplayer.playlistNames[index], playlistTracks[index], [widget.fileMetaData[0]]);
211 | Navigator.pop(context);
212 | key.currentState.showSnackBar(SnackBar(content: Text("Track has been added to playlist")));
213 | },
214 | ),
215 | decoration: BoxDecoration(
216 | border: Border(bottom: BorderSide(color: Colors.black54))
217 | )
218 | );
219 | }
220 | )
221 | ) : Text("You haven't created any playlists yet."),
222 | ],
223 | )
224 | );
225 | showDialog(context: context, builder: (BuildContext context) => dialog);
226 | });
227 | }
228 |
229 | @override
230 | Widget build(BuildContext context) {
231 | img = musicplayer.getImage(widget.fileMetaData[2], context);
232 | return Scaffold(
233 | key: key,
234 | drawer: musicplayer.AppDrawer(),
235 | appBar: AppBar(
236 | leading: IconButton(
237 | icon: Icon(Icons.arrow_back),
238 | onPressed: () {
239 | if (widget.backPage == "libraryPage") {
240 | Navigator.of(context).push(MaterialPageRoute(
241 | builder: (BuildContext context) =>
242 | Library(
243 | musicFiles: musicplayer.allFilePaths,
244 | metadata: musicplayer.allMetaData,
245 | )
246 | ));
247 | } else if (widget.backPage == "favouritesPage") {
248 | Navigator.of(context).push(MaterialPageRoute(
249 | builder: (BuildContext context) =>
250 | FavouritesPage()
251 | ));
252 | } else if (widget.backPage == "playlistPage") {
253 | Navigator.of(context).push(MaterialPageRoute(
254 | builder: (BuildContext context) =>
255 | PlaylistPage()
256 | ));
257 | } else if (widget.backPage == "artistPage") {
258 | Navigator.of(context).push(MaterialPageRoute(
259 | builder: (BuildContext context) =>
260 | ArtistPage()
261 | ));
262 | } else {
263 | Navigator.of(context).push(MaterialPageRoute(
264 | builder: (BuildContext context) =>
265 | HomePage()
266 | ));
267 | }
268 | },
269 | ),
270 | actions: [
271 | IconButton(
272 | icon: Icon(Icons.library_add),
273 | onPressed: () {
274 | addToPlaylist();
275 | },
276 | ),
277 | IconButton(
278 | icon: isFavorited == true ? Icon(Icons.favorite, size: 32.0)
279 | : Icon(Icons.favorite_border, size: 32.0,),
280 | onPressed: () {
281 | if (isFavorited == true) {
282 | setState(() {
283 | musicplayer.favList.remove(widget.filePath);
284 | saveFavTrack("", musicplayer.favList);
285 | isFavorited = false;
286 | });
287 | } else {
288 | setState(() {
289 | saveFavTrack(widget.filePath, musicplayer.favList);
290 | isFavorited = true;
291 | musicplayer.getFavTrackList().then((l) {
292 | musicplayer.favList = l;
293 | });
294 | });
295 | }
296 | }
297 | )
298 | ],
299 | toolbarOpacity: 1.0,
300 | backgroundColor: Colors.white,
301 | elevation: 0.0,
302 | iconTheme: IconThemeData(
303 | color: Colors.black54
304 | ),
305 | ),
306 | body: Material(
307 | color: pageColor,
308 | child: Column(
309 | mainAxisSize: MainAxisSize.max,
310 | mainAxisAlignment: MainAxisAlignment.start,
311 | children: [
312 | Column( // IMAGE PORTION OF PLAYINGPAGE
313 | children: [
314 | Container(
315 | color: Colors.white,
316 | child: Container(
317 | width: 300.0,
318 | height: 300.0,
319 | child: img,
320 | ),
321 | padding: EdgeInsets.only(
322 | left: MediaQuery.of(context).size.width/6,
323 | right: MediaQuery.of(context).size.width/6,
324 | )
325 | ),
326 | Container(
327 | padding: EdgeInsets.only(top: MediaQuery.of(context).size.width/12),
328 | color: Colors.white,
329 | child: musicplayer.playerState == musicplayer.PlayerState.playing ? WaveWidget(
330 | config: CustomConfig(
331 | gradients: [
332 | [pageColor, pageColor],
333 | [pageColor, pageColor],
334 | [pageColor, pageColor],
335 | [pageColor, pageColor]
336 | ],
337 | durations: [2400, 2400, 2400, 2400],
338 | heightPercentages: [0.23, 0.23, 0.23, 0.23],
339 | gradientBegin: Alignment.bottomLeft,
340 | gradientEnd: Alignment.topRight,
341 | ),
342 | waveAmplitude: 0,
343 | backgroundColor: Colors.white,
344 | size: Size(
345 | double.infinity,
346 | MediaQuery.of(context).size.width/12,
347 | ),
348 | ) : Container(color: Colors.white, height: MediaQuery.of(context).size.width/12, child: null,),
349 | ),
350 | ],
351 | ),
352 | Expanded(
353 | child: Column(
354 | mainAxisAlignment: MainAxisAlignment.spaceEvenly,
355 | children: [
356 | Tooltip(
357 | message: widget.fileMetaData[0],
358 | child: Padding(
359 | padding: EdgeInsets.only(
360 | left: MediaQuery.of(context).size.width/20,
361 | right: MediaQuery.of(context).size.width/20,
362 | ),
363 | child: Text(
364 | widget.fileMetaData[0],
365 | style: TextStyle(fontSize: 24.0),
366 | overflow: TextOverflow.fade,
367 | maxLines: 1,
368 | softWrap: false,
369 | ),
370 | ),
371 | ),
372 | Text(
373 | widget.fileMetaData[1],
374 | style: TextStyle(fontSize: 18.0, color: Colors.black54),
375 | overflow: TextOverflow.fade,
376 | maxLines: 1,
377 | softWrap: false,
378 | ),
379 | Row( // BUTTONS
380 | mainAxisAlignment: MainAxisAlignment.center,
381 | children: [
382 | IconButton(
383 | icon: Icon(Icons.skip_previous, color: Colors.blueGrey,),
384 | iconSize: 30.0,
385 | tooltip: "Previous Track",
386 | onPressed: () {
387 | if (musicplayer.currTrack != 0) {
388 | musicplayer.currTrack--;
389 | Navigator.of(context).push(MaterialPageRoute(
390 | builder: (BuildContext context) => PlayingPage(
391 | filePath: musicplayer.queueFileList[musicplayer.currTrack],
392 | fileMetaData: musicplayer.queueMetaData[musicplayer.currTrack][0] != null
393 | ? musicplayer.queueMetaData[musicplayer.currTrack] : [musicplayer.queueFileList[musicplayer.currTrack], "unknown"],
394 | backPage: widget.backPage,
395 | )
396 | )
397 | );
398 | }
399 | },
400 | ),
401 | IconButton(
402 | icon: Icon(Icons.history),
403 | iconSize: 50.0,
404 | tooltip: "Replay Track",
405 | onPressed: () {
406 | setState(() {
407 | musicplayer.audioPlayer.seek(0.0);
408 | musicplayer.play(widget.filePath);
409 | musicplayer.playerState = musicplayer.PlayerState.playing;
410 | });
411 | },
412 | ),
413 | getIcon(), // PLAY BUTTON / PAUSE BUTTON
414 | IconButton(
415 | icon: Icon(Icons.skip_next, color: Colors.blueGrey,),
416 | iconSize: 30.0,
417 | tooltip: "Next Track",
418 | onPressed: () {
419 | if (musicplayer.currTrack != musicplayer.queueFileList.length-1) {
420 | musicplayer.currTrack++;
421 | Navigator.of(context).push(MaterialPageRoute(
422 | builder: (BuildContext context) => PlayingPage(
423 | filePath: musicplayer.queueFileList[musicplayer.currTrack],
424 | fileMetaData: musicplayer.queueMetaData[musicplayer.currTrack][0] != null
425 | ? musicplayer.queueMetaData[musicplayer.currTrack] : [musicplayer.queueFileList[musicplayer.currTrack], "unknown"],
426 | backPage: widget.backPage,
427 | )
428 | )
429 | );
430 | }
431 | },
432 | ),
433 | ],
434 | ),
435 | Column(
436 | mainAxisAlignment: MainAxisAlignment.start,
437 | children: [
438 | musicplayer.duration == null
439 | ? Container()
440 | : Slider(
441 | value: musicplayer.position?.inMilliseconds?.toDouble() ?? 0.0,
442 | onChanged: (double value) {
443 | musicplayer.play(widget.filePath);
444 | musicplayer.playerState = musicplayer.PlayerState.playing;
445 | musicplayer.audioPlayer.seek((value / 1000).roundToDouble());
446 | },
447 | min: 0.0,
448 | max: musicplayer.duration.inMilliseconds.toDouble()),
449 | Wrap(
450 | direction: Axis.horizontal,
451 | children: [
452 | Row(
453 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
454 | children: [
455 | Padding(
456 | padding: EdgeInsets.only(left: 14.0),
457 | child: Text(positionText, style: TextStyle(fontSize: 24.0)),
458 | ),
459 | Padding(
460 | padding: EdgeInsets.only(right: 14.0),
461 | child: Text(durationText, style: TextStyle(fontSize: 24.0)),
462 | )
463 | ],
464 | ),
465 | ],
466 | )
467 | ],
468 | ),
469 | ],
470 | ),
471 | ),
472 | ],
473 | ),
474 | )
475 | );
476 | }
477 | }
--------------------------------------------------------------------------------
/lib/playlistpage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'musicplayer.dart' as musicplayer;
3 | import 'playingpage.dart';
4 | import 'package:shared_preferences/shared_preferences.dart';
5 |
6 | String img = "images/noimage.png";
7 |
8 | class PlaylistPage extends StatefulWidget {
9 | PlaylistPageState createState() => PlaylistPageState();
10 | }
11 |
12 | class PlaylistPageState extends State {
13 | String _name;
14 | final TextEditingController controller = TextEditingController();
15 | int counter = 0;
16 | int playlistLength = 0;
17 | final key = GlobalKey();
18 |
19 | void savePlaylistNames(String name, playlistNames) async {
20 | if (name != null) {
21 | playlistNames.add(name);
22 | }
23 | SharedPreferences prefs = await SharedPreferences.getInstance();
24 | prefs.setStringList("playlistNames", playlistNames);
25 | }
26 |
27 | void createPlaylist() {
28 | _name = null;
29 | AlertDialog dialog = AlertDialog(
30 | title: Text("test"),
31 | content: Column(
32 | mainAxisSize: MainAxisSize.min,
33 | children: [
34 | TextField(
35 | decoration: InputDecoration(labelText: 'Playlist name'),
36 | onChanged: (input) {
37 | setState(() {
38 | _name = input;
39 | });
40 | },
41 | controller: controller,
42 | ),
43 | FlatButton(
44 | child: Text("Create playlist"),
45 | onPressed: () {
46 | if (_name != null) {
47 | setState(() {
48 | controller.text = "";
49 | });
50 | musicplayer.savePlaylist(
51 | _name, [], null); // saves playlist to shared preferences
52 | if (musicplayer.playlistNames != null) {
53 | savePlaylistNames(_name, musicplayer.playlistNames);
54 | } else {
55 | List lst = [];
56 | savePlaylistNames(_name, lst);
57 | }
58 | musicplayer.getPlayListNames().then((l) {
59 | musicplayer.playlistNames = l;
60 | });
61 | Navigator.of(context, rootNavigator: true).pop('dialog');
62 | Navigator.of(context).push(MaterialPageRoute(
63 | builder: (BuildContext context) => ShowPlaylist(
64 | name: _name,
65 | tracklist: [],
66 | )));
67 | } else {
68 | Navigator.of(context, rootNavigator: true).pop('dialog');
69 | key.currentState.showSnackBar(SnackBar(content: Text("Playlist name can't be empty.")));
70 | }
71 | },
72 | )
73 | ],
74 | ));
75 | showDialog(context: context, builder: (BuildContext context) => dialog);
76 | }
77 |
78 | @override
79 | void initState() {
80 | super.initState();
81 | // print("playlist names are " + musicplayer.playlistNames.toString());
82 | musicplayer.loadPlaylistData();
83 | print(musicplayer.playlistNames);
84 | }
85 |
86 | @override
87 | Widget build(BuildContext context) {
88 | return Scaffold(
89 | key: key,
90 | floatingActionButton: FloatingActionButton(
91 | child: Center(
92 | child: Text(
93 | "+",
94 | style: TextStyle(fontSize: 40.0, fontWeight: FontWeight.w300),
95 | ),
96 | ),
97 | onPressed: () {
98 | createPlaylist();
99 | },
100 | ),
101 | appBar: AppBar(
102 | title: Text("Playlists"),
103 | ),
104 | drawer: musicplayer.AppDrawer(),
105 | body: musicplayer.playlistNames != null ? FutureBuilder(
106 | future: musicplayer.loadPlaylistData(),
107 | builder: (BuildContext context, AsyncSnapshot snapshot) {
108 | try {
109 | var data = Map();
110 | List tempData = snapshot.data;
111 | if (tempData == null) {
112 | return Container(
113 | child: Text("Loading..."),
114 | );
115 | } else {
116 | for (var i in List.generate(
117 | tempData.length, (n) => n + 1)) {
118 | data[musicplayer.playlistNames[i - 1]] =
119 | tempData[i - 1];
120 | }
121 | return Column(
122 | children: [
123 | Expanded(
124 | child: ListView.builder(
125 | shrinkWrap: true,
126 | itemCount: data.length,
127 | itemBuilder: (BuildContext context, int index) {
128 | final playlistName =
129 | musicplayer.playlistNames[index];
130 | return Dismissible(
131 | key: Key(musicplayer.playlistNames[index]),
132 | background: Container(
133 | padding: EdgeInsets.only(left: 10.0),
134 | color: Colors.red,
135 | alignment: Alignment.centerLeft,
136 | child: Icon(Icons.delete),
137 | ),
138 | secondaryBackground: Container(
139 | padding: EdgeInsets.only(right: 10.0),
140 | color: Colors.red,
141 | alignment: Alignment.centerRight,
142 | child: Icon(Icons.delete),
143 | ),
144 | onDismissed: (direction) {
145 | musicplayer.playlistNames.remove(playlistName);
146 | savePlaylistNames(null, musicplayer.playlistNames);
147 | data.remove(playlistName);
148 | print(musicplayer.playlistNames);
149 | },
150 | child: ListTile(
151 | title: Text(playlistName),
152 | trailing: Text(data[playlistName].length.toString() +" Tracks"),
153 | onTap: () {
154 | Navigator.of(context).push(
155 | MaterialPageRoute(builder: (BuildContext context) =>
156 | ShowPlaylist(
157 | name: playlistName,
158 | tracklist: data[playlistName],
159 | )));
160 | }));
161 | }),
162 | )
163 | ],
164 | );
165 | }
166 | } catch (e) {
167 | return Text("loading...");
168 | }
169 | })
170 | : Center(
171 | child: Text("You haven't added any playlists yet."),
172 | ));
173 | }
174 | }
175 |
176 | class ShowPlaylist extends StatefulWidget {
177 | String name;
178 | List tracklist;
179 |
180 | ShowPlaylist({Key key, this.name, this.tracklist}) : super(key: key);
181 |
182 | ShowPlaylistState createState() => ShowPlaylistState();
183 | }
184 |
185 | class ShowPlaylistState extends State {
186 | List playlistMetaData = [];
187 | List playlistFilePaths = [];
188 |
189 | @override
190 | void initState() {
191 | super.initState();
192 | for (var track in widget.tracklist) {
193 | int i;
194 | String path;
195 | for (var x in musicplayer.allMetaData) {
196 | if (x[0] == track) {
197 | i = musicplayer.allMetaData.indexOf(x);
198 | path = musicplayer.allFilePaths[i];
199 | playlistFilePaths.add(path);
200 | playlistMetaData.add([
201 | musicplayer.allMetaData[i][0],
202 | musicplayer.allMetaData[i][1],
203 | musicplayer.allMetaData[i][2]
204 | ]);
205 | }
206 | }
207 | }
208 | }
209 |
210 | @override
211 | Widget build(BuildContext context) {
212 | return Scaffold(
213 | appBar: AppBar(
214 | title: widget.name != null ? Text(widget.name) : Text("aaa"),
215 | ),
216 | body: widget.tracklist.length == 0
217 | ? Column(
218 | mainAxisAlignment: MainAxisAlignment.center,
219 | crossAxisAlignment: CrossAxisAlignment.center,
220 | children: [
221 | Padding(
222 | padding: EdgeInsets.all(12.0),
223 | child: Center(
224 | child: Text(
225 | "This playlist is empty. Start adding some tracks!"),
226 | ),
227 | ),
228 | RaisedButton(
229 | child: Text("Add Tracks"),
230 | onPressed: () {
231 | Navigator.of(context).push(MaterialPageRoute(
232 | builder: (BuildContext context) => TrackSelection(
233 | name: widget.name,
234 | )));
235 | })
236 | ],
237 | )
238 | : ListView.builder(
239 | itemCount: playlistMetaData.length,
240 | itemBuilder: (BuildContext context, int index) {
241 | return Dismissible(
242 | key: Key(playlistMetaData[index][0]),
243 | background: Container(
244 | padding: EdgeInsets.only(left: 10.0),
245 | color: Colors.red,
246 | alignment: Alignment.centerLeft,
247 | child: Icon(Icons.delete),
248 | ),
249 | secondaryBackground: Container(
250 | padding: EdgeInsets.only(right: 10.0),
251 | color: Colors.red,
252 | alignment: Alignment.centerRight,
253 | child: Icon(Icons.delete),
254 | ),
255 | onDismissed: (direction) {
256 | setState(() {
257 | playlistMetaData.removeAt(index);
258 | widget.tracklist.removeAt(index);
259 | musicplayer.savePlaylist(
260 | widget.name, widget.tracklist, null);
261 | Scaffold.of(context).showSnackBar(
262 | SnackBar(content: Text("Track removed.")));
263 | });
264 | },
265 | child: ListTile(
266 | leading: musicplayer.getImage(playlistMetaData[index][2], context),
267 | title: Text(playlistMetaData[index][0]),
268 | subtitle: Text(playlistMetaData[index][1]),
269 | trailing: Text((index + 1).toString()),
270 | onTap: () {
271 | // TRACK GETS PLAYED, PLAYLIST FILEPATHS AND METADATA GET ADDED TO PLAYQUEUE
272 | musicplayer.queueFileList = playlistFilePaths;
273 | musicplayer.queueMetaData = playlistMetaData;
274 | musicplayer.currTrack = index;
275 | Navigator.of(context).push(MaterialPageRoute(
276 | builder: (BuildContext context) => PlayingPage(
277 | filePath: playlistFilePaths[index],
278 | fileMetaData: playlistMetaData[index][0] !=
279 | null
280 | ? playlistMetaData[index]
281 | : [playlistMetaData[index][0], "unknown"],
282 | backPage: "playlistPage")));
283 | },
284 | ));
285 | }));
286 | }
287 | }
288 |
289 | class TrackSelection extends StatefulWidget {
290 | String name;
291 |
292 | TrackSelection({Key key, this.name}) : super(key: key);
293 |
294 | TrackSelectionState createState() => TrackSelectionState();
295 | }
296 |
297 | class TrackSelectionState extends State {
298 | List checkedTracks = [];
299 |
300 | @override
301 | Widget build(BuildContext context) {
302 | return Scaffold(
303 | appBar: AppBar(
304 | title: Text("Add tracks to playlist"),
305 | actions: [
306 | InkWell(
307 | customBorder: CircleBorder(),
308 | child: Container(
309 | width: 50.0,
310 | child: Icon(Icons.check),
311 | ),
312 | onTap: () {
313 | musicplayer.savePlaylist(widget.name, [], checkedTracks);
314 | Navigator.of(context).push(MaterialPageRoute(
315 | builder: (BuildContext) => PlaylistPage()));
316 | },
317 | )
318 | ],
319 | ),
320 | body: ListView.builder(
321 | shrinkWrap: true,
322 | itemCount: musicplayer.allFilePaths.length,
323 | itemBuilder: (BuildContext context, int index) => ListTile(
324 | leading: musicplayer.getImage(musicplayer.allMetaData[index][2], context),
325 | title: Text(musicplayer.allMetaData[index][0]),
326 | subtitle: Text(musicplayer.allMetaData[index][1]),
327 | trailing:
328 | checkedTracks.contains(musicplayer.allMetaData[index][0]) ==
329 | true
330 | ? Icon(Icons.check_box)
331 | : Icon(Icons.check_box_outline_blank),
332 | onTap: () {
333 | setState(() {
334 | if (checkedTracks
335 | .contains(musicplayer.allMetaData[index][0]) ==
336 | true) {
337 | checkedTracks.remove(musicplayer.allMetaData[index][0]);
338 | } else {
339 | checkedTracks.add(musicplayer.allMetaData[index][0]);
340 | }
341 | });
342 | },
343 | )),
344 | );
345 | }
346 | }
--------------------------------------------------------------------------------
/lib/splashpage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'dart:io';
3 | import 'dart:typed_data';
4 | import 'package:path_provider/path_provider.dart';
5 | import 'package:flutter/services.dart';
6 | import 'dart:async';
7 | import 'musicplayer.dart' as musicplayer;
8 | import 'home.dart';
9 | import 'dart:convert';
10 | import 'package:crypto/crypto.dart';
11 |
12 | class SplashScreen extends StatefulWidget {
13 |
14 | @override
15 | State createState() {
16 | return SplashScreenState();
17 | }
18 | }
19 |
20 | class SplashScreenState extends State {
21 | Future extDir;
22 | Directory extDir2;
23 | String kUrl;
24 | Uint8List image1;
25 | RegExp exp = RegExp(r"^([^\/]+)");
26 | static const platform = const MethodChannel('demo.janhrastnik.com/info');
27 | var path;
28 | String loadingTrack;
29 | double loadingTrackNumber = 0.0;
30 | String sdCard;
31 |
32 | // used for app
33 | List _metaData = [];
34 | List _musicFiles = [];
35 |
36 | // used for json file
37 | Map mapMetaData = Map();
38 |
39 | Future get _localPath async {
40 | final directory = await getApplicationDocumentsDirectory();
41 |
42 | return directory.path;
43 | }
44 |
45 | Future get _localFile async {
46 | path = await _localPath;
47 | return File('$path/filesmetadata.json');
48 | }
49 |
50 | void updateLoadingTrack(track, number, size) {
51 | setState(() {
52 | loadingTrack = track;
53 | loadingTrackNumber = number/size;
54 | });
55 | }
56 |
57 | Future writeStoredMetaData(Map fileMetaData) async {
58 | final file = await _localFile;
59 | var jsonData = jsonEncode(fileMetaData);
60 | // Write the file
61 | return file.writeAsString(jsonData);
62 | }
63 |
64 | Future writeImage(var hash, List image) async {
65 | File imagefile = File('$path/$hash');
66 | return imagefile.writeAsBytes(image);
67 | }
68 |
69 |
70 | Future readStoredMetaData() async {
71 | try {
72 | final file = await _localFile;
73 |
74 | // Read the file
75 | String contents = await file.readAsString();
76 | return jsonDecode(contents);
77 | } catch (e) {
78 | print(e);
79 | // If encountering an error, return 0
80 | return 0;
81 | }
82 | }
83 |
84 | void wrap() async {
85 | path = await _localPath;
86 | musicplayer.appPath = path;
87 | await getFiles();
88 | await _getAllMetaData();
89 | for (var i = 0; i < _musicFiles.length; i++) {
90 | if (_metaData[i][0] == null) {
91 | String s = _musicFiles[i];
92 | for (var n = s.length; n > 0; n--) {
93 | if (s.substring(n - 2, n - 1) == "/") {
94 | _metaData[i][0] = s.substring(n-1, s.length - 4);
95 | break;
96 | }
97 | }
98 | if (_metaData[i][1] == null) {
99 | _metaData[i][1] = "Unknown Artist";
100 | }
101 | if (_metaData[i][3] == null) {
102 | _metaData[i][3] = "Unknown Album";
103 | }
104 | }
105 | if (_metaData[i][4] != null) {
106 | Iterable matches = exp.allMatches(_metaData[i][4]);
107 | for (Match match in matches) {
108 | _metaData[i][4] = match.group(0);
109 | }
110 | } else {
111 | _metaData[i][4] = "0";
112 | }
113 | }
114 |
115 | for (var i = 0; i < _musicFiles.length; i++) {
116 | mapMetaData[_musicFiles[i]] = _metaData[i];
117 | }
118 | writeStoredMetaData(mapMetaData);
119 | musicplayer.allMetaData = _metaData;
120 | musicplayer.allFilePaths = _musicFiles;
121 | onDoneLoading();
122 | }
123 |
124 | void getFiles() async {
125 | await _getSdCard().then((data) {
126 | sdCard = data;
127 | });
128 | await getExternalStorageDirectory().then((data) {
129 | extDir2 = data;
130 | if (_musicFiles.isEmpty == true) {
131 | var mainDir = Directory(extDir2.path);
132 | List contents = mainDir.listSync(recursive: true);
133 | for (var fileOrDir in contents) {
134 | if (fileOrDir.path.toString().endsWith(".mp3")) {
135 | _musicFiles.add(fileOrDir.path);
136 | }
137 | } // tries to find external sd card
138 | } else {
139 | }
140 | });
141 | try {
142 | await runStream();
143 | } catch(e) {
144 | print(e);
145 | }
146 | }
147 |
148 | pass() {
149 | return null;
150 | }
151 |
152 | Future _getAllMetaData() async {
153 | for (var track in _musicFiles) {
154 | var data = await _getFileMetaData(track);
155 | updateLoadingTrack(track, _musicFiles.indexOf(track), _musicFiles.length);
156 | if (data[2] != null) {
157 | if (data[2] is List) {
158 | var digest = sha1.convert(data[2]).toString();
159 | writeImage(digest, data[2]);
160 | data[2] = digest;
161 | _metaData.add(data);
162 | } else {
163 | _metaData.add(data);
164 | }
165 | } else {
166 | _metaData.add(data);
167 | }
168 | }
169 | }
170 |
171 | Future _getFileMetaData(track) async {
172 | var value;
173 | try {
174 | if (mapMetaData[track] == null) {
175 | value = await platform.invokeMethod("getMetaData", {
176 | 'filepath': track
177 | });
178 | } else {
179 | value = mapMetaData[track];
180 | }
181 | } catch(e) {
182 | print(e);
183 | }
184 | return value;
185 | }
186 |
187 | Future _getSdCard() async {
188 | var value;
189 | try {
190 | value = await platform.invokeMethod("getSdCardPath");
191 | } catch(e) {
192 | print(e);
193 | }
194 | return value;
195 | }
196 |
197 | runStream() async {
198 | String sdCardDir = Directory(sdCard).parent.parent.parent.parent.path;
199 | var extSdDir = Directory(sdCardDir);
200 | Stream sdContents = extSdDir.list(recursive: true);
201 | sdContents = sdContents.handleError((data) {
202 | });
203 | await for (var data in sdContents) {
204 | if (data.path.endsWith(".mp3")) {
205 | _musicFiles.add(data.path);
206 | }
207 | }
208 | }
209 |
210 | onDoneLoading() async {
211 | Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (context) => HomePage()));
212 | }
213 |
214 | @override
215 | void initState() {
216 | super.initState();
217 | musicplayer.setOrientation();
218 | readStoredMetaData().then((data) {
219 | if (data != 0) {
220 | mapMetaData = data;
221 | }
222 | wrap();
223 | });
224 | }
225 |
226 |
227 | @override
228 | Widget build(BuildContext context) {
229 | return Scaffold(
230 | body: Container(
231 | child: Center(
232 | child: Padding(
233 | padding: EdgeInsets.all(12.0),
234 | child: Column(
235 | mainAxisAlignment: MainAxisAlignment.spaceEvenly,
236 | children: [
237 | Image.asset("images/icon3-192.png"),
238 | Padding(
239 | padding: EdgeInsets.all(10.0),
240 | child: CircularProgressIndicator(
241 | valueColor: AlwaysStoppedAnimation(Colors.blueAccent),
242 | ),
243 | ),
244 | Container(
245 | width: 800.0,
246 | height: 100.0,
247 | child: Center(child: Text("Loading track: $loadingTrack"),),
248 | ),
249 | LinearProgressIndicator(
250 | value: loadingTrackNumber,
251 | ),
252 | ],
253 | ),
254 | )
255 | ),
256 | ),
257 | );
258 | }
259 | }
--------------------------------------------------------------------------------
/lib/wave.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:flutter/widgets.dart';
4 | import 'config.dart';
5 |
6 | class WaveWidget extends StatefulWidget {
7 | final Config config;
8 | final Size size;
9 | final double waveAmplitude;
10 | final double wavePhase;
11 | final double waveFrequency;
12 | final double heightPercentange;
13 | final int duration;
14 | final Color backgroundColor;
15 |
16 | WaveWidget({
17 | @required this.config,
18 | this.duration = 6000,
19 | @required this.size,
20 | this.waveAmplitude = 20.0,
21 | this.waveFrequency = 1.6,
22 | this.wavePhase = 10.0,
23 | this.backgroundColor,
24 | this.heightPercentange = 0.2,
25 | });
26 |
27 | @override
28 | State createState() => _WaveWidgetState();
29 | }
30 |
31 | class _WaveWidgetState extends State with TickerProviderStateMixin {
32 | List _waveControllers;
33 | List> _wavePhaseValues;
34 |
35 | List _waveAmplitudes = [];
36 | Map, AnimationController> valueList;
37 |
38 | _initAnimations() {
39 | if (widget.config.colorMode == ColorMode.custom) {
40 | _waveControllers =
41 | (widget.config as CustomConfig).durations.map((duration) {
42 | _waveAmplitudes.add(widget.waveAmplitude + 10);
43 | return AnimationController(
44 | vsync: this, duration: Duration(milliseconds: duration));
45 | }).toList();
46 |
47 | _wavePhaseValues = _waveControllers.map((controller) {
48 | CurvedAnimation _curve =
49 | CurvedAnimation(parent: controller, curve: Curves.easeInOut);
50 | Animation value = Tween(
51 | begin: widget.wavePhase,
52 | end: 360 + widget.wavePhase,
53 | ).animate(
54 | _curve,
55 | );
56 | value.addStatusListener((status) {
57 | switch (status) {
58 | case AnimationStatus.completed:
59 | controller.reverse();
60 | break;
61 | case AnimationStatus.dismissed:
62 | controller.forward();
63 | break;
64 | default:
65 | break;
66 | }
67 | });
68 | controller.forward();
69 | return value;
70 | }).toList();
71 | }
72 | }
73 |
74 | _buildPaints() {
75 | List paints = [];
76 | if (widget.config.colorMode == ColorMode.custom) {
77 | List _colors = (widget.config as CustomConfig).colors;
78 | List> _gradients = (widget.config as CustomConfig).gradients;
79 | Alignment begin = (widget.config as CustomConfig).gradientBegin;
80 | Alignment end = (widget.config as CustomConfig).gradientEnd;
81 | for (int i = 0; i < _wavePhaseValues.length; i++) {
82 | paints.add(
83 | Container(
84 | child: CustomPaint(
85 | painter: _CustomWavePainter(
86 | color: _colors == null ? null : _colors[i],
87 | gradient: _gradients == null ? null : _gradients[i],
88 | gradientBegin: begin,
89 | gradientEnd: end,
90 | heightPercentange:
91 | (widget.config as CustomConfig).heightPercentages[i],
92 | repaint: _waveControllers[i],
93 | waveFrequency: widget.waveFrequency,
94 | wavePhaseValue: _wavePhaseValues[i],
95 | waveAmplitude: _waveAmplitudes[i],
96 | blur: (widget.config as CustomConfig).blur,
97 | ),
98 | size: widget.size,
99 | ),
100 | ),
101 | );
102 | }
103 | }
104 | return paints;
105 | }
106 |
107 | _disposeAnimations() {
108 | _waveControllers.forEach((controller) {
109 | controller.dispose();
110 | });
111 | }
112 |
113 | @override
114 | void initState() {
115 | super.initState();
116 | _initAnimations();
117 | }
118 |
119 | @override
120 | void dispose() {
121 | _disposeAnimations();
122 | super.dispose();
123 | }
124 |
125 | @override
126 | Widget build(BuildContext context) {
127 | return Container(
128 | color: widget.backgroundColor,
129 | child: Stack(
130 | children: _buildPaints(),
131 | ),
132 | );
133 | }
134 | }
135 |
136 | /// Meta data of layer
137 | class Layer {
138 | final Color color;
139 | final List gradient;
140 | final MaskFilter blur;
141 | final Path path;
142 | final double amplitude;
143 | final double phase;
144 |
145 | Layer({
146 | this.color,
147 | this.gradient,
148 | this.blur,
149 | this.path,
150 | this.amplitude,
151 | this.phase,
152 | });
153 | }
154 |
155 |
156 | class _CustomWavePainter extends CustomPainter {
157 | final ColorMode colorMode;
158 | final Color color;
159 | final List gradient;
160 | final Alignment gradientBegin;
161 | final Alignment gradientEnd;
162 | final MaskFilter blur;
163 |
164 | double waveAmplitude;
165 |
166 | Animation wavePhaseValue;
167 |
168 | double waveFrequency;
169 |
170 | double heightPercentange;
171 |
172 | double _tempA = 0.0;
173 | double _tempB = 0.0;
174 | double viewWidth = 0.0;
175 | Paint _paint = Paint();
176 |
177 | _CustomWavePainter(
178 | {this.colorMode,
179 | this.color,
180 | this.gradient,
181 | this.gradientBegin,
182 | this.gradientEnd,
183 | this.blur,
184 | this.heightPercentange,
185 | this.waveFrequency,
186 | this.wavePhaseValue,
187 | this.waveAmplitude,
188 | Listenable repaint})
189 | : super(repaint: repaint);
190 |
191 | _setPaths(double viewCenterY, Size size, Canvas canvas) {
192 | Layer _layer = Layer(
193 | path: Path(),
194 | color: color,
195 | gradient: gradient,
196 | blur: blur,
197 | amplitude: (-1.6 + 0.8) * waveAmplitude,
198 | phase: wavePhaseValue.value * 2 + 30,
199 | );
200 |
201 | _layer.path.reset();
202 | _layer.path.moveTo(
203 | 0.0,
204 | viewCenterY +
205 | _layer.amplitude * _getSinY(_layer.phase, waveFrequency, -1));
206 | for (int i = 1; i < size.width + 1; i++) {
207 | _layer.path.lineTo(
208 | i.toDouble(),
209 | viewCenterY +
210 | _layer.amplitude * _getSinY(_layer.phase, waveFrequency, i));
211 | }
212 |
213 | _layer.path.lineTo(size.width, size.height);
214 | _layer.path.lineTo(0.0, size.height);
215 | _layer.path.close();
216 | if (_layer.color != null) {
217 | _paint.color = _layer.color;
218 | }
219 | if (_layer.gradient != null) {
220 | var rect = Offset.zero &
221 | Size(size.width, size.height - viewCenterY * heightPercentange);
222 | _paint.shader = LinearGradient(
223 | begin: gradientBegin == null ? Alignment.bottomCenter : gradientBegin,
224 | end: gradientEnd == null ? Alignment.topCenter : gradientEnd,
225 | colors: _layer.gradient)
226 | .createShader(rect);
227 | }
228 | if (_layer.blur != null) {
229 | _paint.maskFilter = _layer.blur;
230 | }
231 |
232 | _paint.style = PaintingStyle.fill;
233 | canvas.drawPath(_layer.path, _paint);
234 | }
235 |
236 | @override
237 | void paint(Canvas canvas, Size size) {
238 | double viewCenterY = size.height * (heightPercentange + 0.1);
239 | viewWidth = size.width;
240 | _setPaths(viewCenterY, size, canvas);
241 | }
242 |
243 | @override
244 | bool shouldRepaint(CustomPainter oldDelegate) {
245 | return false;
246 | }
247 |
248 | double _getSinY(
249 | double startradius, double waveFrequency, int currentposition) {
250 | if (_tempA == 0) {
251 | _tempA = pi / viewWidth;
252 | }
253 | if (_tempB == 0) {
254 | _tempB = 2 * pi / 360.0;
255 | }
256 |
257 | return (sin(
258 | _tempA * waveFrequency * (currentposition + 1) + startradius * _tempB));
259 | }
260 | }
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: musicplayer2
2 | description: A new Flutter application.
3 |
4 | # The following defines the version and build number for your application.
5 | # A version number is three numbers separated by dots, like 1.2.43
6 | # followed by an optional build number separated by a +.
7 | # Both the version and the builder number may be overridden in flutter
8 | # build by specifying --build-name and --build-number, respectively.
9 | # Read more about versioning at semver.org.
10 | version: 1.0.2+4
11 |
12 | environment:
13 | sdk: ">=2.0.0-dev.68.0 <3.0.0"
14 |
15 | dependencies:
16 | flutter:
17 | sdk: flutter
18 |
19 | # The following adds the Cupertino Icons font to your application.
20 | # Use with the CupertinoIcons class for iOS style icons.
21 | cupertino_icons: ^0.1.2
22 | simple_permissions: ^0.1.9
23 | path_provider: ^0.4.1
24 | audioplayer: ^0.5.2
25 | shared_preferences: ^0.4.3
26 | random_color: ^1.0.3
27 | crypto: ^2.0.6
28 |
29 | dev_dependencies:
30 | flutter_test:
31 | sdk: flutter
32 |
33 |
34 | # For information on the generic Dart part of this file, see the
35 | # following page: https://www.dartlang.org/tools/pub/pubspec
36 |
37 | # The following section is specific to Flutter.
38 | flutter:
39 |
40 | # The following line ensures that the Material Icons font is
41 | # included with your application, so that you can use the icons in
42 | # the material Icons class.
43 | uses-material-design: true
44 | assets:
45 | - images/
46 | # To add assets to your application, add an assets section, like this:
47 | # assets:
48 | # - images/a_dot_burr.jpeg
49 | # - images/a_dot_ham.jpeg
50 |
51 | # An image asset can refer to one or more resolution-specific "variants", see
52 | # https://flutter.io/assets-and-images/#resolution-aware.
53 |
54 | # For details regarding adding assets from package dependencies, see
55 | # https://flutter.io/assets-and-images/#from-packages
56 |
57 | # To add custom fonts to your application, add a fonts section here,
58 | # in this "flutter" section. Each entry in this list should have a
59 | # "family" key with the font family name, and a "fonts" key with a
60 | # list giving the asset and other descriptors for the font. For
61 | # example:
62 | # fonts:
63 | # - family: Schyler
64 | # fonts:
65 | # - asset: fonts/Schyler-Regular.ttf
66 | # - asset: fonts/Schyler-Italic.ttf
67 | # style: italic
68 | # - family: Trajan Pro
69 | # fonts:
70 | # - asset: fonts/TrajanPro.ttf
71 | # - asset: fonts/TrajanPro_Bold.ttf
72 | # weight: 700
73 | #
74 | # For details regarding fonts from package dependencies,
75 | # see https://flutter.io/custom-fonts/#from-packages
76 |
--------------------------------------------------------------------------------
/screenshots/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/screenshots/1.png
--------------------------------------------------------------------------------
/screenshots/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/screenshots/2.png
--------------------------------------------------------------------------------
/screenshots/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janhrastnik/flutter-music-player/504f6c58db5e06cc8ce677cde7d6244696df8acc/screenshots/3.png
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | // To perform an interaction with a widget in your test, use the WidgetTester utility that Flutter
3 | // provides. For example, you can send tap and scroll gestures. You can also use WidgetTester to
4 | // find child widgets in the widget tree, read text, and verify that the values of widget properties
5 | // are correct.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:flutter_test/flutter_test.dart';
9 |
10 | import 'package:musicplayer2/main.dart';
11 |
12 | void main() {
13 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
14 | // Build our app and trigger a frame.
15 | await tester.pumpWidget(new MyApp());
16 |
17 | // Verify that our counter starts at 0.
18 | expect(find.text('0'), findsOneWidget);
19 | expect(find.text('1'), findsNothing);
20 |
21 | // Tap the '+' icon and trigger a frame.
22 | await tester.tap(find.byIcon(Icons.add));
23 | await tester.pump();
24 |
25 | // Verify that our counter has incremented.
26 | expect(find.text('0'), findsNothing);
27 | expect(find.text('1'), findsOneWidget);
28 | });
29 | }
30 |
--------------------------------------------------------------------------------